Skip to content

touch: use UTIME_OMIT for the time not being changed - #16201

Open
brkozer wants to merge 1 commit into
uutils:mainfrom
brkozer:touch-utime-omit
Open

brkozer wants to merge 1 commit into
uutils:mainfrom
brkozer:touch-utime-omit

Conversation

@brkozer

@brkozer brkozer commented Nov 5, 2026

Copy link
Copy Markdown

touch -a/-m read the other timestamp by path and wrote it back, so the path could be swapped for a symlink in between and the symlink target's time overwritten. Now the unchanged time is passed as UTIME_OMIT, following the suggested fix in the issue.

This also fixes touch -h -a - and touch -h -m -, which copied the times of the /dev/stdout symlink itself onto the file.

Redox, Windows and WASI still read the other time back. The race is covered by a new check in util/check-toctou.sh.

Fixes #15794
Related: #14686 (a different race, not fixed here)

@sylvestre

Copy link
Copy Markdown
Contributor

this is a lot of new code, could you please make it smaller?

@brkozer

brkozer commented Nov 5, 2026

Copy link
Copy Markdown
Author

Okay, thanks. I reworked it around a utime_omit() next to utime_now(), it's much smaller now.

Comment thread src/uu/touch/src/touch.rs Outdated
return set_symlink_file_times(path, atime, mtime).map_err_context(
#[cfg(all(unix, not(target_os = "redox")))]
let result = rustix::fs::utimensat(
rustix::fs::CWD,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

almost the same code as set_times_by_path, could you add a flags param to it instead?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, thanks. Fixed.

Comment thread tests/by-util/test_touch.rs Outdated
// read from the `/dev/stdout` symlink itself and written to the file.
#[uutests::wasi_ignore(NoStdoutFileRedirection)]
#[test]
#[cfg(target_os = "linux")]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why only linux? UTIME_OMIT is used on every unix now

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, it's not Linux specific anymore. It runs on all unix now, except Redox.

With -a or -m, touch read the other time by path and wrote it back, so
the path could be swapped for a symlink in between and that file's time
overwritten. Pass UTIME_OMIT instead, as utimensat allows. This also
stops `touch -h -a -` and `touch -h -m -` from copying the times of the
/dev/stdout symlink itself onto the file. Redox, Windows and WASI still
read the other time back.

Fixes uutils#15794

This branch has not been deployed

No deployments
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 -a: TOCTOU race lets local user forge mtime of root-owned files

2 participants