Skip to content

mkdir,mkfifo: reject comma-separated numeric modes - #16024

Open
Logic769 wants to merge 10 commits into
uutils:mainfrom
Logic769:mkdir-reject-numeric-comma-mode
Open

Logic769 wants to merge 10 commits into
uutils:mainfrom
Logic769:mkdir-reject-numeric-comma-mode

Conversation

@Logic769

@Logic769 Logic769 commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

mkdir -m and mkfifo --mode accepted a numeric mode with a comma such as 1,2 and silently applied only the last clause: mkdir -m 1,2 d created d with mode 0002 and exited 0. GNU rejects it:

mkdir: invalid mode '1,2'

GNU reads a comma-separated mode as a list of symbolic clauses, so a bare octal is only valid as the whole mode string. A numeric clause with an explicit +, - or = operator stays valid inside a list, as in GNU's own =7777,-5022 test case.

The rule now lives in uucore::mode::parse_chmod (is_numeric_clause), so it covers every caller at once: mkdir, mkfifo, mknod and chmod, which keeps its own clause loop and got the same check. 755,u+w, u+w,755, a=rx,700, u=r,2, 1,u=w and +1,2 are all rejected now, and 755,u+w no longer leaves a mode behind. Comma-separated symbolic modes such as u=rwx,g=rx,o= still work.

Two behaviours that GNU has and we did not are fixed along the way, because the old code called parse_numeric on the first operator only:

  • a run of operators before the number, as in =+755, ++755 or -+755, is accepted, and = still keeps a directory's setuid/setgid bits like GNU does;
  • parse_numeric no longer accepts whitespace between the operators and the digits, so u+x,+ 755 is rejected like GNU.

Tests:

  • tests/by-util/test_chmod.rs::test_numeric_mode_must_be_the_whole_mode
  • tests/by-util/test_mkdir.rs::diagnostics::test_comma_separated_mode_is_rejected
  • tests/by-util/test_mkfifo.rs::test_comma_separated_numeric_mode_is_rejected and ::test_comma_separated_symbolic_mode_is_accepted
  • tests/by-util/test_mknod.rs::test_mknod_comma_separated_numeric_mode_is_rejected
  • src/uucore/src/lib/features/mode.rs::test_numeric_mode_must_stand_alone and ::test_parse_considering_dir

Closes #16001

@fixfon

fixfon commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

Mixed clauses still get through. On the PR head (e316716), these modes return rc 0 for both mkdir -m and mkfifo -m, while GNU 9.7 rejects them as invalid mode:

  • 755,u+w (mkdir creates drwxr-xr-x)
  • u+w,755
  • a=rx,700 (mkdir creates drwx------)

755,, ,755, 0755,0 and 1,2 are rejected correctly.

The check looks at the whole string, so a numeric clause next to a symbolic one passes. Checking each clause would fix it: a numeric mode is valid only as the single clause.

#15378 does this per clause in uucore::mode for chmod, install, mkdir, mkfifo and mknod, and its tests include 644,u+x and u+x,644. It may be simpler to align this PR with that one, or fold it in.

@xtqqczze

Copy link
Copy Markdown
Collaborator

@fixfon Thanks for investigating, but please compare against GNU coreutils 9.12 or GNU coreutils master branch.

@Logic769
Logic769 force-pushed the mkdir-reject-numeric-comma-mode branch from e316716 to 0433c4f Compare October 30, 2026 13:02
Comment thread src/uu/mkdir/src/mkdir.rs Resolved
Comment thread src/uu/mkfifo/src/mkfifo.rs Resolved
Comment thread src/uu/mkfifo/src/mkfifo.rs Resolved
Comment thread tests/by-util/test_mkfifo.rs Resolved
Comment thread tests/by-util/test_mkdir.rs Resolved
@fixfon

fixfon commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

@xtqqczze Re-checked against GNU coreutils 9.12 (built locally on Linux, same results as 9.7) with the current head (0433c4f).

GNU rejects all of these with invalid mode and creates nothing. The PR still accepts them and creates the directory or fifo, for both mkdir -m and mkfifo -m:

  • 755,u+w
  • u+w,755
  • a=rx,700
  • u=r,2
  • 1,u=w
  • +1,2

The purely numeric lists (755,, ,755, 0755,0, 1,2) are rejected and nothing is created, same as GNU. u=rwx,g=rx,o= still works.

So this matches what @sylvestre pointed out. Rejecting a numeric clause in parse_chmod unless it's the whole mode string should cover all six.

@Logic769
Logic769 force-pushed the mkdir-reject-numeric-comma-mode branch from 7ea68c0 to 04a4d3c Compare October 31, 2026 02:30
@Logic769

Copy link
Copy Markdown
Contributor Author

Moved the rule into uucore::mode::parse_chmod: a comma-separated mode is a list of symbolic clauses, so 755,u+w and u=r,2 are invalid. That covers mkdir, mkfifo and mknod; chmod keeps its own clause loop, so it got the same check. Tests cover the FIFO not being created, u=r,2, 1,u=w, and u=rwx,g=rx,o= still being accepted.

Comment thread src/uu/chmod/src/chmod.rs Resolved
Comment thread src/uu/chmod/src/chmod.rs Resolved
Comment thread src/uucore/src/lib/features/mode.rs Resolved
Comment thread tests/by-util/test_mkdir.rs Resolved
Comment thread tests/by-util/test_mkfifo.rs Resolved
@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown

GNU testsuite comparison:

GNU test failed: tests/chmod/setgid. tests/chmod/setgid is passing on 'main'. Maybe you have to rebase?

@codspeed

codspeed Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Merging this PR will degrade performance by 3.83%

2 warnings, 1 note

⚠️ 123 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

⚠️ 2 benchmarks with a significant change ran on different hardware

Their base and head results were measured on machines with a different CPU, core count or memory, so the changes might not come from the code. Run base and head on the same runner type.

Learn more about Macro Runners

See affected benchmarks

ℹ️ 1 benchmark has no flamegraph

The flamegraph wasn't generated: most of the time was spent in runtime internals, which would leave nothing useful to analyze.

See affected benchmarks

❌ 2 regressed benchmarks
✅ 399 untouched benchmarks
⏩ 70 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
❌ CPU Simulation df_deep_directory 887.4 µs 930.4 µs -4.62%
❌ CPU Simulation du_wide_tree[(5000, 500)] 15.2 ms 15.7 ms -3.04%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing Logic769:mkdir-reject-numeric-comma-mode (3b64036) with main (6c880ea)2

Open in CodSpeed

Footnotes

  1. 70 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

  2. No successful run was found on main (36a00ef) during the generation of this report, so 6c880ea was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@Logic769
Logic769 force-pushed the mkdir-reject-numeric-comma-mode branch 2 times, most recently from 4c20081 to 608b658 Compare November 2, 2026 13:44
Comment thread src/uu/chmod/src/chmod.rs Resolved
Comment thread src/uucore/src/lib/features/mode.rs Resolved
GNU reads a comma-separated mode as a list of symbolic clauses, so a
clause that is plain octal makes the whole mode invalid. Checking the
rule in uucore::mode::parse_chmod covers mkdir, mkfifo and mknod in one
place; chmod keeps its own clause loop, so it needs the same guard.
Remove the redundant numeric-comma precheck so parse_symbolic produces the standard invalid-mode diagnostic, and add mkdir/mkfifo/mknod coverage for the rejection path.
A numeric clause in a list may carry a run of operators before the number,
as in `=+755`, `++755` or `-+755`. `parse_numeric` now consumes the
whole run, and an `=` inside it resets the ordinary permission bits while
keeping a directory's setuid/setgid bits: `chmod =+755` on a 6755 directory
leaves it at 6755, as GNU does, instead of dropping to 755.

Whitespace between the operators still keeps the clause symbolic, so
`u+x,+ 755` stays an invalid mode.

The tests also check that rejected modes leave the target untouched and that
mkfifo applies an accepted symbolic mode.
Clippy rejects the loop/let-else form as while_let_loop.
The rule is documented on is_numeric_clause, so the copies in chmod and parse_chmod only repeat it.
@Logic769
Logic769 force-pushed the mkdir-reject-numeric-comma-mode branch from b514ba1 to 3b64036 Compare November 3, 2026 15:53

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.

mkdir: -m 1,2 should be rejected as an invalid mode

4 participants