Skip to content

Conversation

@sgmarz
Copy link

@sgmarz sgmarz commented Jan 5, 2026

Fixes #10019

The metadata() function calls stat at the OS level, which was being checked before File::create() causing a potential race condition between the stat'd file and the opened file (i.e., Time-of-check/time-of-usage problem). This PR uses OpenOptions instead with options to turn off O_TRUNC. It also uses additional flags (O_NOCTTY and O_NONBLOCK) on UNIX targets using OpenOptionsExt. These are POSIX compliant options, so I used cfg(unix) rather than target = "linux". I also had to handle ENXIO separately as touching a FIFO should be fine, but with O_NONBLOCK, this will cause an error. However, the error is not something we care about as it's just telling us it couldn't do anything with the FIFO, so for UNIX targets, that error is ignored like it is for GNU coreutils.

now uutils (after PR):

openat(AT_FDCWD, "abc", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_CLOEXEC, 0666) = 3
utimensat(AT_FDCWD, "abc", [UTIME_NOW, UTIME_NOW], 0) = 0

stat has been removed as a system call and open now is used to both create and test file errors. To align the error messages with GNU coreutils, such as permission denied, this PR adds an error message to the 'touch-error-cannot-touch' error.

main branch:

$ uu_touch /root/cant_write
touch: setting times of '/root/cant_write': Permission denied
$ gnu_touch /root/cant_write
touch: cannot touch '/root/cant_write': Permission denied

after PR:

$ uu_touch /root/cant_write
touch: cannot touch '/root/cant_write': Permission denied (os error 13)

I did not see it necessary to remove the (os error 13), but can easily be done, but I see it in other utilities, such as install, so I figured it could be left here too.

@github-actions
Copy link

github-actions bot commented Jan 5, 2026

GNU testsuite comparison:

GNU test failed: tests/cp/perm. tests/cp/perm is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/fail-diag. tests/touch/fail-diag is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/no-create-missing. tests/touch/no-create-missing is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/read-only. tests/touch/read-only is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/trailing-slash. tests/touch/trailing-slash is passing on 'main'. Maybe you have to rebase?
Skip an intermittent issue tests/timeout/timeout (fails in this run but passes in the 'main' branch)

@sgmarz
Copy link
Author

sgmarz commented Jan 5, 2026

Guess my assumption of (os error XX) being OK in the string was wrong as it's causing these to fail.

Some of the failing tests don't align with GNU either:

  TRY 3 FAIL [   0.071s] coreutils::tests test_touch::test_touch_trailing_slash
  stdout ───

    running 1 test
    bin: "/home/runner/work/coreutils/coreutils/target/debug/coreutils"
    run: /home/runner/work/coreutils/coreutils/target/debug/coreutils touch no-file/
    test test_touch::test_touch_trailing_slash ... FAILED

    failures:

    failures:
        test_touch::test_touch_trailing_slash

    test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 4575 filtered out; finished in 0.06s
    
  stderr ───

    thread 'test_touch::test_touch_trailing_slash' panicked at tests/by-util/test_touch.rs:783:39:
    assertion failed: `(left == right)`

    Diff < left / right > :
    <touch: setting times of 'no-file/': No such file or directory
    >touch: cannot touch 'no-file/': No such file or directory

On main branch, I get this:

$ uu_touch no-file/
touch: cannot touch 'no-file/': No such file or directory
$ gnu_touch no-file/
touch: setting times of 'no-file/': No such file or directory

with my PR, it has this behavior:

$ uu_touch no-file/
touch: setting times of 'no-file/': No such file or directory
$ gnu_touch no-file/
touch: setting times of 'no-file/': No such file or directory

The test is failing because it's looking for the behavior of what's currently in the main branch, but I don't think it's in line with GNU coreutil's error message.

Edited to add this test was done with GNU coreutils 9.9 from Arch Linux.

@github-actions
Copy link

github-actions bot commented Jan 5, 2026

GNU testsuite comparison:

GNU test failed: tests/cksum/md5sum. tests/cksum/md5sum is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/cp/perm. tests/cp/perm is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/no-create-missing. tests/touch/no-create-missing is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/read-only. tests/touch/read-only is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/trailing-slash. tests/touch/trailing-slash is passing on 'main'. Maybe you have to rebase?
Skipping an intermittent issue tests/timeout/timeout (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/basenc/bounded-memory is now passing!
Note: The gnu test tests/dd/no-allocate was skipped on 'main' but is now failing.

jfinkels and others added 5 commits January 5, 2026 08:29
Set the default line width to 72 for all page headers in `pr`,
regardless of whether a custom date format is being used. Before, a
single space was used to separate the three components of the header
(date, filename, and page number) if a custom date format was not given.
@github-actions
Copy link

github-actions bot commented Jan 5, 2026

GNU testsuite comparison:

GNU test failed: tests/cp/perm. tests/cp/perm is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/no-create-missing. tests/touch/no-create-missing is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/read-only. tests/touch/read-only is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/trailing-slash. tests/touch/trailing-slash is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/tty/tty-eof. tests/tty/tty-eof is passing on 'main'. Maybe you have to rebase?
Congrats! The gnu test tests/basenc/bounded-memory is now passing!
Note: The gnu test tests/dd/no-allocate was skipped on 'main' but is now failing.

@sgmarz sgmarz marked this pull request as draft January 5, 2026 13:42
@sgmarz sgmarz marked this pull request as ready for review January 5, 2026 14:06
@github-actions
Copy link

github-actions bot commented Jan 5, 2026

GNU testsuite comparison:

GNU test failed: tests/cp/perm. tests/cp/perm is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/no-create-missing. tests/touch/no-create-missing is passing on 'main'. Maybe you have to rebase?
GNU test failed: tests/touch/read-only. tests/touch/read-only is passing on 'main'. Maybe you have to rebase?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

touch create path TOCTOU: stat then create leading to truncate via race

5 participants