Summary
Running chroot --skip-chdir <NEWROOT> with a NEWROOT that does not exist (or has an unreadable path component) panics during argument validation. To decide whether --skip-chdir is allowed, the code canonicalizes NEWROOT and unwraps the result; canonicalize returns Err when the path does not resolve, so the .unwrap() aborts the process (exit 134). GNU instead reports the usage error option --skip-chdir only permitted if NEWROOT is old '/' and exits 125. The panic happens before any chroot syscall, so no root privileges are needed.
Steps to reproduce
$ chroot --skip-chdir /nonexistent/sub
thread 'main' panicked at src/uu/chroot/src/chroot.rs:174:10:
called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, ... }
$ echo $?
134
Expected behavior
Match GNU: report the error and exit non-zero without crashing.
$ /sbin/chroot --skip-chdir /nonexistent/sub
/sbin/chroot: option --skip-chdir only permitted if NEWROOT is old '/'
Try '/sbin/chroot --help' for more information.
$ echo $?
125
Actual behavior
uutils panics with Result::unwrap() on an Err value and aborts with exit code 134. The failure occurs during argument validation (the --skip-chdir permitted-only-if check), before any chroot syscall, so it reproduces as a non-root user.
Root cause
// src/uu/chroot/src/chroot.rs:168-177
if options.skip_chdir
&& canonicalize(
&options.newroot,
MissingHandling::Normal,
ResolveMode::Logical,
)
.unwrap()
.to_str()
!= Some("/")
With --skip-chdir, the code canonicalizes NEWROOT to test whether it resolves to /. canonicalize(..., MissingHandling::Normal, ...) returns Err whenever NEWROOT (or one of its path components) doesn't exist or isn't readable, and that Err is unwrapped instead of being treated as "not /".
Found by our static analysis tooling.
Summary
Running
chroot --skip-chdir <NEWROOT>with a NEWROOT that does not exist (or has an unreadable path component) panics during argument validation. To decide whether--skip-chdiris allowed, the code canonicalizes NEWROOT and unwraps the result;canonicalizereturnsErrwhen the path does not resolve, so the.unwrap()aborts the process (exit 134). GNU instead reports the usage erroroption --skip-chdir only permitted if NEWROOT is old '/'and exits 125. The panic happens before any chroot syscall, so no root privileges are needed.Steps to reproduce
Expected behavior
Match GNU: report the error and exit non-zero without crashing.
Actual behavior
uutils panics with
Result::unwrap()on anErrvalue and aborts with exit code 134. The failure occurs during argument validation (the--skip-chdirpermitted-only-if check), before any chroot syscall, so it reproduces as a non-root user.Root cause
With
--skip-chdir, the code canonicalizes NEWROOT to test whether it resolves to/.canonicalize(..., MissingHandling::Normal, ...)returnsErrwhenever NEWROOT (or one of its path components) doesn't exist or isn't readable, and thatErris unwrapped instead of being treated as "not/".Found by our static analysis tooling.