Hello,

I have investigated this issue and verified it on Ubuntu Resolute.

Root cause:
The crash happens because safe_du in du, safe_traverse_dir in chmod, and 
safe_traverse_dir in perms (for chown and chgrp) were using recursive function 
calls. Each recursive call allocates stack frames with directory descriptors, 
metadata, and path buffers. On deep directory structures (depths > 2000), the 
thread stack exceeds the default 8MB limit (ulimit -s 8192), causing an 
immediate segmentation fault.

Fix:
I replaced the recursive calls with an iterative heap-allocated stack traversal 
across all four utilities (du, chmod, chown, chgrp). This changes call stack 
usage from O(N) to O(1) and prevents stack exhaustion.

Testing:
I verified the fix on trees with depths of 2000 and 4000 levels. Unpatched 
binaries crash with SIGSEGV; patched binaries complete with exit code 0. 
Existing test suites for uu_du, uu_chmod, uu_chown, and uu_chgrp pass without 
regressions.

Upstream pull request submitted for review:
https://github.com/uutils/coreutils/pull/14887

I have attached a debdiff for resolute (0.10.0-1ubuntu2~26.04.2) and
updated the bug description with the full SRU justification.


** Description changed:

+ [ Impact ]
+ In Ubuntu Resolute and Stonking, rust-coreutils provides the core utilities 
du, chmod, chown, and chgrp. When operating on deeply nested directory trees 
(depths of ~2000 levels or more), all four utilities crash with Segmentation 
fault (core dumped) (SIGSEGV).
+ 
+ The root cause is that directory traversal in du (safe_du), chmod
+ (safe_traverse_dir), and perms (safe_traverse_dir for chown and chgrp)
+ was implemented using recursive function calls. Because each stack frame
+ holds directory descriptors, stat structures, path buffers, and entry
+ lists, deep trees quickly exceed the Linux default thread stack limit of
+ 8MB (ulimit -s 8192).
+ 
+ This is a functional regression compared to GNU coreutils, which
+ processes deep directory hierarchies without crashing. Any automated
+ build system, cache tree, or container environment with deep directory
+ structures triggers this crash.
+ 
+ [ Fix ]
+ Replace recursive directory traversal with an iterative heap-allocated stack 
across all four affected utilities:
+ - src/uu/du/src/du.rs: Replaced recursive safe_du with an iterative traversal 
using a heap-allocated Vec<DuFrame> stack (post-order DFS to correctly 
aggregate subdirectory sizes).
+ - src/uu/chmod/src/chmod.rs: Replaced recursive safe_traverse_dir in Chmoder 
with an iterative traversal using a heap-allocated Vec<ChmodFrame> stack 
(pre-order DFS, preserving cycle detection via ancestors set).
+ - src/uucore/src/lib/features/perms.rs: Replaced recursive safe_traverse_dir 
in PerRequest with an iterative traversal using a heap-allocated 
Vec<PermsFrame> stack (pre-order DFS, preserving cycle detection via ancestors 
set).
+ 
+ This keeps CPU call stack usage strictly O(1) regardless of directory
+ depth, avoiding stack exhaustion.
+ 
+ [ Test Plan ]
+ 1. Reproduce on unpatched rust-coreutils (0.10.0-1ubuntu2~26.04.1):
+    Create a deep directory tree (depth 2000 or more) using openat/mkdirat 
helpers or gnumkdir:
+    $ du a
+    Segmentation fault (core dumped)
+    $ chmod -R 777 a
+    Segmentation fault (core dumped)
+    $ chown -R root:root a
+    Segmentation fault (core dumped)
+    $ chgrp -R root a
+    Segmentation fault (core dumped)
+ 
+ 2. Verify with patched rust-coreutils (0.10.0-1ubuntu2~26.04.2):
+    Run the same commands on deep directory trees (tested up to depth 4000):
+    $ du a
+    (prints size and directory entries without crash, exit code 0)
+    $ chmod -R 777 a
+    (completes without crash, exit code 0)
+    $ chown -R root:root a
+    (completes without crash, exit code 0)
+    $ chgrp -R root a
+    (completes without crash, exit code 0)
+ 
+ 3. Run package test suites:
+    cargo test -p uu_du
+    cargo test -p uu_chmod
+    cargo test -p uu_chown
+    cargo test -p uu_chgrp
+    All tests pass with 0 regressions.
+ 
+ [ Where problems could occur ]
+ The change replaces the call stack with a heap stack for directory traversal.
+ - File descriptor leaks: Each directory frame maintains its DirFd and closes 
it when popped from the heap stack.
+ - Infinite loops / symlink loops: Cycle detection in chmod and perms 
(chown/chgrp) uses ancestors tracking (HashSet<FileInformation>), which is 
preserved across push and pop operations on the stack.
+ - Traversal order: du maintains post-order traversal (children before 
parents) to aggregate block sizes correctly; chmod and chown/chgrp maintain 
pre-order traversal (parents before children).
+ 
+ [ Other Info ]
+ - Upstream PR: https://github.com/uutils/coreutils/pull/14887 (fixes upstream 
issue #10173). Pre-commit CI is passing.
+ - Development branch: Resolute (resolute) is the active development target 
for rust-coreutils. Target debdiff package version is 0.10.0-1ubuntu2~26.04.2.
+ - Full test suites pass with 0 regressions.
+ 
+ --- [ Original Report ]
  ```
  $ podman run --rm -it ubuntu:26.04
  $ apt update -y; apt upgrade -y
  $ ulimit -n
  1048576
  $ gnumkdir -p $(yes a/ | head -n $((32 * 1024)) | tr -d '\n')
  $ chown -R root:root a
  Segmentation fault         (core dumped) chown -R root:root a
  $ chmod -R 777 a
  Segmentation fault         (core dumped) chmod -R 777 a
  $ chgrp -R root a
  Segmentation fault         (core dumped) chgrp -R root a
  $ du a
  Segmentation fault         (core dumped) du a
  ````
  
  All of the GNU programs work fine:
  
  ```
  $ gnuchown -R root:root a; echo $?
  0
  $ gnuchmod -R 777 a; echo $?
  0
  $ gnuchgrp -R 777 a; echo $?
  0
  $ gnudu a | wc -l
  32768
  ```

** Tags added: crash patch regression

** Patch added: "Debdiff for Resolute (0.10.0-1ubuntu2~26.04.2) fixing deep 
directory traversal stack overflow"
   
https://bugs.launchpad.net/ubuntu/+source/rust-coreutils/+bug/2167204/+attachment/6003084/+files/rust-coreutils_0.10.0-1ubuntu2~26.04.2.debdiff

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2167204

Title:
  chown, chmod, chgrp, and du segfault due to recursive calls

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/rust-coreutils/+bug/2167204/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to