mode: comma-separated mode strings accept forms GNU rejects
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 24.1k
- Forks
- 2k
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 365
Description
Version
uutils/coreutils main at d1dd5f9, tested on 2026-09-07 (arm64 macOS) against GNU
coreutils 9.11.
Summary
GNU accepts either one bare octal mode or a comma-separated list of symbolic
clauses. It rejects any list containing an octal clause, and rejects empty
clauses. We accept both. chmod, mkdir, install, mkfifo and mknod are
affected, and two of them disagree with each other on the same input.
Reproduction
Octal inside a comma list — GNU errors, we accept:
mode GNU chmod ours GNU mkdir ours
644,u+x error 744 error 744
u+x,644 error 644 error 644
a-w,644 error 644 error 644
644,644 error 644 error 644
g+s,755 error 755 error 755
755,g+s error 2755 error 755
755,g+s also disagrees between our own utils: chmod applies setgid, mkdir
loses it at mkdir(2) (that part is #12709).
Empty clauses — GNU errors, and chmod happens to error, but the others accept:
mode GNU chmod mkdir install mkfifo
'' error error 777 000 666
' ' error error 777 000 666
',,' error error 777 000 666
'644,' error error 644 644 644
',644' error error 644 644 644
'u+x,,g+x' error error 777 110 776
a+x,u+x, g=u, u+7, u=7, 0 and 00 all agree, so the divergence is
specifically an octal clause inside a list, plus empty clauses.
Cause
There are two separate implementations of the same comma-list loop:
uucore::mode::parse_chmod(src/uucore/src/lib/features/mode.rs:322-351),
used by mkdir, install, mkfifo and mknod. It skips empty clauses at
mode.rs:338-340, which is why those four accept the second table.chmod::calculate_new_mode(src/uu/chmod/src/chmod.rs:327-362), which
reimplements the loop and does not skip empty clauses, so they reach
parse_symbolic("")and error. chmod passing the second table is accidental,
not intended.
Both dispatch per clause on "contains an ASCII digit, so treat it as numeric"
(mode.rs:342, chmod.rs:331). That is what allows an octal clause anywhere in
a list; GNU's grammar only allows a bare octal as the whole argument.
Impact
Mostly accepting invalid input rather than producing wrong permissions, but
install -m '' src dst exits 0 and leaves a mode 000 file, and mkdir -m ''
silently uses 0777 because the empty string leaves parse_chmod's starting
value untouched.
Suggested fix
Implement GNU's grammar once in uucore::mode: a bare octal accepted only as
the entire string, otherwise a non-empty list of symbolic clauses with empty
clauses rejected. Then delete chmod's duplicate loop and route it through the
same entry point, keeping its naive-mode/umask diagnostic behavior.
Note that five existing unit tests assert the current behavior and would need
removing rather than re-pinning: mode.rs:496, :534-535, :541-543,
:583-584, :591-594 — including a test_parse_mixed_numeric_and_symbolic
named after the incompatible form.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with uucore::mode::parse_chmod in src/uucore/src/lib/features/mode.rs and chmod::calculate_new_mode in src/uu/chmod/src/chmod.rs, then read the mode unit tests around the cited lines. Run the affected Rust tests before changing behavior. Done means the shared parsing follows the stated GNU grammar across chmod, mkdir, install, mkfifo and mknod, with incompatible tests removed or updated.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100