Component
cp
Description
uutils cp can be vulnerable to a classic TOCTOU as it decides whether the source is a symlink using lstat-style metadata, but later opens the source by path without O_NOFOLLOW.
An attacker who can mutate the source tree concurrently can replace a regular file with a symlink between the check and the open, causing cp to copy the symlink target’s contents.
Test / Reproduction Steps
Evidence via strace to make it easier:
- In uutils, cp opens the source without
O_NOFOLLOW:
openat(AT_FDCWD, "/tmp/src/file", O_RDONLY|O_CLOEXEC) (no O_NOFOLLOW)
- In GNU cp on Linux, the equivalent open includes
O_NOFOLLOW:
openat(AT_FDCWD, "/tmp/src/file", O_RDONLY|O_NOFOLLOW)
Preconditions: attacker can modify/rename entries under the source path while cp runs; victim runs cp with more read privilege than attacker; destination is attacker-readable.
- Create a source directory attacker controls and a destination.
- Run cp on a file inside the source while a second process repeatedly swaps that pathname between a regular file and a symlink to a sensitive target.
- Observe occasional copies of the symlink target’s contents in the destination when the swap lands between the metadata check and the open.
Component
cpDescription
uutils cp can be vulnerable to a classic TOCTOU as it decides whether the source is a symlink using lstat-style metadata, but later opens the source by path without O_NOFOLLOW.
An attacker who can mutate the source tree concurrently can replace a regular file with a symlink between the check and the open, causing cp to copy the symlink target’s contents.
Test / Reproduction Steps
Evidence via strace to make it easier:
O_NOFOLLOW:openat(AT_FDCWD, "/tmp/src/file", O_RDONLY|O_CLOEXEC) (no O_NOFOLLOW)O_NOFOLLOW:openat(AT_FDCWD, "/tmp/src/file", O_RDONLY|O_NOFOLLOW)Preconditions: attacker can modify/rename entries under the source path while cp runs; victim runs cp with more read privilege than attacker; destination is attacker-readable.