touch: drop O_TRUNC on create to close TOCTOU race (#10019)

This commit is contained in:
Sylvestre Ledru
2026-06-04 16:19:26 +02:00
committed by Dorian Péron
parent 44087eb515
commit ca0c842e71
3 changed files with 105 additions and 5 deletions
+35
View File
@@ -1074,3 +1074,38 @@ fn test_touch_device_files() {
.succeeds()
.no_output();
}
// Touching a symlink to an existing file must not truncate the target, like
// GNU touch. The target exists, so this exercises the update_times path, not
// the create path changed for #10019 — it guards the general "touch never
// truncates" contract. The create-path fix itself is covered by the
// create_without_truncate unit tests in src/touch.rs and the syscall-flag
// check in util/check-safe-traversal.sh.
#[test]
#[cfg(unix)]
fn test_touch_does_not_truncate_symlink_target() {
use std::os::unix::fs::symlink;
let (at, mut ucmd) = at_and_ucmd!();
at.write("victim", "do not truncate me");
symlink(at.plus("victim"), at.plus("link")).unwrap();
ucmd.arg("link").succeeds();
assert_eq!(at.read("victim"), "do not truncate me");
}
// Touching a dangling symlink creates its target as an empty file, like GNU.
#[test]
#[cfg(unix)]
fn test_touch_through_dangling_symlink_creates_target() {
use std::os::unix::fs::symlink;
let (at, mut ucmd) = at_and_ucmd!();
symlink(at.plus("missing"), at.plus("link")).unwrap();
ucmd.arg("link").succeeds();
assert!(at.file_exists("missing"));
assert_eq!(at.read("missing"), "");
}