Commit Graph
5018 Commits
Author SHA1 Message Date
Sylvestre LedruandGitHub 7d27b3baa1 head: add TOCTOU regression tests and fix comment typo (#12637)
Follow-up to the metadata TOCTOU fix (#11972, PR #12439):

- Add a syscall-level regression guard in util/check-safe-traversal.sh:
  under strace, head must read metadata from the open descriptor
  (fstat/statx on the fd) and must not stat the path before opening it.
  Verified this fails on the pre-fix code and passes after.
- Add an integration test asserting that an unreadable file produces an
  error but no "==> name <==" header, matching GNU (the header is only
  printed after a successful open).
- Fix a stray paren in the Windows-branch comment.
2026-06-05 15:21:40 +02:00
mattsuandGitHub 533edad992 kill: replace nix::sys::signal with rustix::process (#12326) 2026-06-05 13:09:15 +02:00
weiliandDaniel Hofstetter abcdcdca53 pr: reject a non-positive expand-tab width (-e0)
`pr -e0` on input containing a tab aborted with a remainder-by-zero panic
(`chunk.len() % expand_options.width` in `apply_expand_tab`). The
`-e[char][width]` parser accepted a width of `0` — and a negative width via
e.g. `-eX-5` — without validation, so the zero/negative reached the chunk
arithmetic.

Reject `width <= 0` while parsing `-e`, emitting the same invalid-argument
error GNU produces (`pr: '-e' extra characters or invalid number in the
argument: '0'`, exit 1) instead of crashing.
2026-06-05 11:19:08 +02:00
Sylvestre LedruandDaniel Hofstetter 6d015356dd pwd: ignore non-option arguments, drop getcwd disabling from pwd-long test 2026-06-05 09:44:04 +02:00
DevelandGitHub bd9f32f7ae numfmt: prevent panic if float precision specifier > 65535 (#12600) 2026-06-04 17:03:36 +02:00
Sylvestre LedruandDorian Péron ca0c842e71 touch: drop O_TRUNC on create to close TOCTOU race (#10019) 2026-06-04 16:19:26 +02:00
Lorenzo RossiandGitHub cfc6457681 chown: restrict no-dereference symlink ctime test to Linux (#12556) 2026-06-03 17:40:14 +02:00
Daniel HofstetterandSylvestre Ledru f1073d7c9e dircolors: turn integration test into unit test 2026-06-02 11:38:32 +02:00
Nikola LukovicandGitHub 3fbcb79a30 chmod/chown: symlink cycles detection (#11805) 2026-06-01 15:13:58 +02:00
oech3andDaniel Hofstetter 10ef28ddc1 pipes:rs: replace unnecessary splice by read-ahead hint 2026-06-01 13:33:27 +02:00
Wei LiandGitHub bcdd134352 shuf: fix panic/abort on large -i range without small --head-count (#12501)
* shuf: fix panic/abort on large -i range without small --head-count

NonrepeatingIterator::new sized its sparse hash map to
min(head_count, range_len) and allocated it with the infallible
with_capacity_and_hasher. head_count defaults to u64::MAX when -n is
absent (and can be passed a huge value explicitly), so for a large -i
range the map was asked to reserve the whole range:

  shuf -i 1-9999999999999999999                       # no -n
  shuf -i 1-9999999999999999999 -n 9999999999999999999

Both aborted (exit 134) with a hashbrown "Hash table capacity overflow"
panic or an allocator abort, where GNU prints "memory exhausted" and
exits 1.

Reserve fallibly with try_reserve (mirroring the Vec branch) and map
the failure to a clean error, so an unsatisfiable request errors like
GNU instead of crashing. A small --head-count still works unchanged.

Closes #12500.

* shuf: assert full stderr (incl. program prefix) in memory-exhausted tests

Per review on #12501: switch the two memory-exhausted regression tests
from stderr_contains to stderr_only("shuf: memory exhausted\n") so they
verify the whole stderr, including the `shuf:` program-name prefix.
2026-06-01 07:50:35 +02:00
Daniel HofstetterandSylvestre Ledru b5fcae085d dircolors: use stdout_only in tests where possible 2026-05-30 16:17:14 +02:00
Daniel HofstetterandSylvestre Ledru 4834b3187d dircolors: improve test by ensuring stderr output 2026-05-30 16:17:14 +02:00
Lorenzo RossiandGitHub ed15a26a6a chown: -h on symlink to directory operates on link, not target (#12522)
closes: #11887
2026-05-30 14:29:58 +02:00
gabrielhnfandDaniel Hofstetter 840c36d396 shred: fix --remove=unlink with relative paths 2026-05-30 10:44:52 +02:00
fullwoodenshovelandGitHub 395d703593 stat: fix %N quoting of filenames containing control characters (#12330) 2026-05-29 18:51:06 +02:00
b22013ab79 ls: ls -lF symlink target indicators (#11554)
---------

Co-authored-by: Guillem L. Jara <4lon3ly0@tutanota.com>
Co-authored-by: Sylvestre Ledru <sylvestre@debian.org>
2026-05-28 13:08:08 +02:00
AnthonyandGitHub 179b977b93 ln: add WASI support via symlink_path (#11713) 2026-05-28 12:53:59 +02:00
Dima GerasimovandDaniel Hofstetter 565f118f8c sort: add a test reproducing failure during sort --merge
sort -m takes: 3 lines, 96003 bytes

and emits: 4 lines, 96004 bytes

The output line lengths before the fix are:

```
a x 32000
b x 23809
b x 8191
c x 32000
```

So it splits one of the lines into two (23809 + 8191 = 32000).

In addition, the output becomes unsorted because the shorter 'b' fragment sorts before the longer 'b' fragment.

The issue is that in `chunks.rs`, `sep_iter` is relatve to `search_start`. But the returned value needs to be absolute position relative to the `buffer`.

We end up with these particular numbers because
- in merge.rs, initial chunk is created as `RecycledChunk::new(8 * 1024)` (8192 bytes)
- `search_start = 8192`; newline is at absolute buffer index `32000`
- `memchr_iter` returns `32000 - 8192 = 23808`, and newline adds + 1 byte
2026-05-28 10:38:12 +02:00
Daniel HofstetterandSylvestre Ledru 2c37153c7e mktemp: ensure that "-q XX" shows error msg 2026-05-27 20:39:52 +02:00
yor1xdandDaniel Hofstetter 9d3bafc23e mktemp: fix hidden file creation with dot prefix 2026-05-26 15:52:32 +02:00
Etienne CordonnierandDaniel Hofstetter 76c63ee6fd install: update comments and tests
Fix doc comments in safe_traversal that still described the old behavior
of replacing symlinks with real directories. Rename and deduplicate tests
that were originally written as race-condition regression tests but now
just verify symlink-following behavior.

Signed-off-by: Etienne Cordonnier <ecordonnier@snap.com>
2026-05-26 10:14:21 +02:00
Jake AbendrothandGitHub 21fda8cd9f fix(install): follow symlink components in destination path with -D
## Summary

Fixes #11469

`install -D` was replacing pre-existing symlinks in the destination path with real directories instead of following them. This broke any workflow where part of the install prefix is a symlink; including BOSH deployments, Homebrew, Nix, stow, and any `make install` targeting a symlinked prefix.

**Reproduction (from the issue):**
```sh
mkdir -p /tmp/target
ln -s /tmp/target /tmp/link
echo hello > /tmp/file.txt
install -D -m 644 /tmp/file.txt /tmp/link/subdir/file.txt
# GNU coreutils 8.32: /tmp/link stays a symlink, file lands in /tmp/target/subdir/file.txt
# uutils 0.7.0:       /tmp/link is replaced with a real directory — wrong
```

## Root cause

PR #10140 introduced `create_dir_all_safe()` in `safe_traversal.rs` to prevent TOCTOU symlink race conditions. The fix was correct in intent but too aggressive: `open_or_create_subdir()` unconditionally unlinked and recreated any symlink it encountered, including pre-existing legitimate ones.

## Changes

**`src/uucore/src/lib/features/safe_traversal.rs`**
- `open_or_create_subdir`: when `stat_at` returns `S_IFLNK`, call `open_subdir(Follow)` instead of `unlink_at + mkdir_at`. The `O_DIRECTORY` flag already in `open_subdir` means dangling or non-directory symlinks still return an error cleanly.
- `find_existing_ancestor`: switch from `fs::symlink_metadata` to `fs::metadata` so that a symlink-to-directory is recognised as an existing ancestor rather than a component to recreate (this was already the stated intent in the function's doc comment).

**`src/uu/install/src/install.rs`**
- Align the `dir_exists` check and the `DirFd::open` call to also follow symlinks, consistent with the above.

**`tests/by-util/test_install.rs`**
- Update the two tests added by #10140 — they were asserting the buggy behavior (symlink replaced). Flip the assertions to document the correct GNU behavior.
- Add `test_install_d_follows_symlink_prefix` as a direct regression test for the issue's reproduction case.

## TOCTOU / security note

The true TOCTOU race (a symlink *injected during the operation* into a not-yet-existing path component) is still blocked: `mkdirat` fails with `EEXIST` if an attacker creates a symlink between `stat_at` returning `ENOENT` and our `mkdir_at`. Newly-created directories are still opened with `O_NOFOLLOW`.

What changes is that *pre-existing* symlinks are now followed — which is exactly what GNU coreutils 8.32 does. The previous behavior was stricter than GNU in this regard.
2026-05-25 22:11:50 +02:00
oech3andEtienne Cordonnier db7b8a6e58 stdbuf: build on Windows (depending on cygwin dll) 2026-05-25 12:23:51 +02:00
Sylvestre LedruandDorian Péron a8d51a2cfd mkdir: simplify umask shaping and add regression tests 2026-05-25 11:11:48 +02:00