aboutsummaryrefslogtreecommitdiff
path: root/libcxx/src/filesystem/operations.cpp
diff options
context:
space:
mode:
authorAfanasyev Ivan <ivafanas@gmail.com>2024-06-12 08:41:15 +0700
committerGitHub <noreply@github.com>2024-06-11 21:41:15 -0400
commit7e5bc71514c7428ab791b187d5cbf8215afd5a87 (patch)
treee43ba9b38ceb24cd051ff39f725c687220c09a0e /libcxx/src/filesystem/operations.cpp
parent0c5319e546321d7a766999e49e0ccf801ff2b3dc (diff)
downloadllvm-7e5bc71514c7428ab791b187d5cbf8215afd5a87.zip
llvm-7e5bc71514c7428ab791b187d5cbf8215afd5a87.tar.gz
llvm-7e5bc71514c7428ab791b187d5cbf8215afd5a87.tar.bz2
[libc++] Fix UB in filesystem::__copy for non-existent destination. (#87615)
The lstat/stat/fstat functions have no guarantee whether the `struct stat` buffer is changed or not on failure. The filesystem::__copy function assumes that the `struct stat` buffer is not updated on failure, which is not necessarily correct. It appears that for a non-existing destination `detail::posix_lstat(to, t_st, &m_ec1)` returns a failure indicator and overwrites the `struct stat` buffer with a garbage value, which is accidentally equal to the `f_st` from stack internals from the previous `detail::posix_lstat(from, f_st, &m_ec1)` call. file_type::not_found is a known status, so checking against `if (not status_known(t))` passes spuriously and execution continues. Then the __copy function returns errc::function_not_supported because stats are accidentally equivalent, which is incorrect. Before checking for `detail::stat_equivalent`, we instead need to make sure that the call to lstat/stat/fstat was successful. As a result of `f_st` and `t_st` not being accessed anymore without checking for the lstat/stat/fstat success indicator, it is not needed to zero-initialize them.
Diffstat (limited to 'libcxx/src/filesystem/operations.cpp')
-rw-r--r--libcxx/src/filesystem/operations.cpp6
1 files changed, 3 insertions, 3 deletions
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
index 62bb248..87b38fb 100644
--- a/libcxx/src/filesystem/operations.cpp
+++ b/libcxx/src/filesystem/operations.cpp
@@ -109,20 +109,20 @@ void __copy(const path& from, const path& to, copy_options options, error_code*
const bool sym_status2 = bool(options & copy_options::copy_symlinks);
error_code m_ec1;
- StatT f_st = {};
+ StatT f_st;
const file_status f =
sym_status || sym_status2 ? detail::posix_lstat(from, f_st, &m_ec1) : detail::posix_stat(from, f_st, &m_ec1);
if (m_ec1)
return err.report(m_ec1);
- StatT t_st = {};
+ StatT t_st;
const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1) : detail::posix_stat(to, t_st, &m_ec1);
if (not status_known(t))
return err.report(m_ec1);
if (!exists(f) || is_other(f) || is_other(t) || (is_directory(f) && is_regular_file(t)) ||
- detail::stat_equivalent(f_st, t_st)) {
+ (exists(t) && detail::stat_equivalent(f_st, t_st))) {
return err.report(errc::function_not_supported);
}