[libcxx-commits] [libcxx] 7e5bc71 - [libc++] Fix UB in filesystem::__copy for non-existent destination. (#87615)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jun 11 18:41:19 PDT 2024
Author: Afanasyev Ivan
Date: 2024-06-11T21:41:15-04:00
New Revision: 7e5bc71514c7428ab791b187d5cbf8215afd5a87
URL: https://github.com/llvm/llvm-project/commit/7e5bc71514c7428ab791b187d5cbf8215afd5a87
DIFF: https://github.com/llvm/llvm-project/commit/7e5bc71514c7428ab791b187d5cbf8215afd5a87.diff
LOG: [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.
Added:
Modified:
libcxx/src/filesystem/operations.cpp
Removed:
################################################################################
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
index 62bb248d5eca9..87b38fbdecf4e 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);
}
More information about the libcxx-commits
mailing list