diff options
author | Afanasyev Ivan <ivafanas@gmail.com> | 2024-06-12 08:41:15 +0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-11 21:41:15 -0400 |
commit | 7e5bc71514c7428ab791b187d5cbf8215afd5a87 (patch) | |
tree | e43ba9b38ceb24cd051ff39f725c687220c09a0e /libcxx/src/filesystem/operations.cpp | |
parent | 0c5319e546321d7a766999e49e0ccf801ff2b3dc (diff) | |
download | llvm-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.cpp | 6 |
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); } |