Skip to content

chmod -R -L --preserve-root: a descendant symlink to / bypasses the root-preservation guard

High
sylvestre published GHSA-2745-m2g5-p3mw Aug 7, 2026

Package

cargo uu_chmod (Rust)

Affected versions

<= 0.9.0

Patched versions

0.10.0

Description

--preserve-root is only checked against the top-level operands (chmod.rs:402); the recursive walker walk_dir_with_context performs no is_root re-check. Under chmod -R -L --preserve-root, a descendant symlink pivot -> / is followed during recursion and the operation proceeds onto /. (chown's walker does re-check root at perms.rs:498; chmod's does not.)

Verified (chroot model): uutils chmodded the modeled root / itself and an off-tree file to 0777 and exited 0, despite --preserve-root; GNU refused with "it is dangerous to operate recursively on '...' (same as '/')" (exit 1).

Impact: a privileged chmod -R -L --preserve-root MODE <tree> over attacker-influenced content can be redirected onto the whole root filesystem -- exactly what --preserve-root is supposed to prevent. Fix: re-check is_root inside the recursive walker (and treat a descendant symlink resolving to / as the guard does at top level).


Source: Cantina audit (2026-05-03). Independently verified 2026-05-30 against uutils/coreutils e0ad63471 with a sandboxed PoC; GNU coreutils 9.7 used as control. See cantina-report/VERIFICATION-2026-05-30.md.

Fix

Fixed in 0.10.0 — commit a203c654c (#13621, merged 2026-07-31; 0.10.0 released 2026-08-05).

--preserve-root was only enforced for the paths named on the command line (the operand loop in Chmoder::chmod). The recursive walker never re-checked, so with -R -L a symlink met inside the tree that resolves to / was followed and the recursion walked into the real root.

Re-confirmed on 0.9.0-575-g0d02663c6 in a bubblewrap sandbox with a throwaway /: a tree containing link -> / under chmod -R -L --preserve-root 777 tree took an unrelated 0700 directory to 0777. GNU coreutils 9.10 refused the identical case in the same sandbox.

The fix re-checks the guard at every descent, in both walk_dir_with_context variants so unix, non-unix and redox are covered. Only symlinks are canonicalized, so ordinary recursive trees are unaffected. Behaviour now matches GNU: diagnose with the (same as '/') wording, skip the subtree, continue, and exit 1.

Note: PR #10033 ("Chmod preserve root", merged 2026-01-07) is easily mistaken for a complete fix but only covered the operand-level resolves-to-/ case.

Re-verified on the released 0.10.0 tag (2026-08-07) behaviourally, not by re-reading the diff, under bwrap with a throwaway minimal / holding tree/link -> / and an off-tree victim directory at 0700:

$ chmod -R -L --preserve-root 777 /tree
0.9.0 : exit 1, victim 0777      <- escaped the tree
0.10.0: exit 1, victim 0700, "chmod: it is dangerous to operate recursively on '/tree/link' (same as '/')"
GNU   : exit 1, victim 0700, byte-identical message

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Local
Attack complexity
Low
Privileges required
Low
User interaction
Required
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H

CVE ID

No known CVE

Weaknesses

Improper Link Resolution Before File Access ('Link Following')

The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource. Learn more on MITRE.

Time-of-check Time-of-use (TOCTOU) Race Condition

The product checks the state of a resource before using that resource, but the resource's state can change between the check and the use in a way that invalidates the results of the check. Learn more on MITRE.

Protection Mechanism Failure

The product does not use or incorrectly uses a protection mechanism that provides sufficient defense against directed attacks against the product. Learn more on MITRE.

Credits