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.
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,mkfifoandmknodareaffected, and two of them disagree with each other on the same input.
Reproduction
Octal inside a comma list — GNU errors, we accept:
755,g+salso disagrees between our own utils: chmod applies setgid, mkdirloses it at
mkdir(2)(that part is #12709).Empty clauses — GNU errors, and chmod happens to error, but the others accept:
a+x,u+x,g=u,u+7,u=7,0and00all agree, so the divergence isspecifically 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), whichreimplements 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 ina 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 dstexits 0 and leaves a mode000file, andmkdir -m ''silently uses
0777because the empty string leavesparse_chmod's startingvalue untouched.
Suggested fix
Implement GNU's grammar once in
uucore::mode: a bare octal accepted only asthe 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 atest_parse_mixed_numeric_and_symbolicnamed after the incompatible form.