CVE Patch Review

CVE-2026-35338: Root Path Canonicalization Fix for chmod --preserve-root

CVE-2026-35338 · Updated 2026-07-06 Root-cause

Summary

The patch replaces a raw string/path equality check against "/" with canonical path resolution before evaluating the --preserve-root guard in recursive chmod. This directly addresses the reported bypass using unnormalized paths such as '/../' that resolve to the filesystem root. The added regression test demonstrates the intended blocked case. Residual considerations remain around canonicalization error handling and platform/path semantics, but the change appears to fix the stated root cause for the disclosed issue.

Analysis

Vulnerability

CVE-2026-35338 describes a local path validation bypass in uutils/coreutils chmod when used recursively with --preserve-root. The vulnerable logic compared the user-supplied path directly to /:

if self.recursive && self.preserve_root && file == Path::new("/") {

This check is syntactic rather than semantic. A path such as /../ is not equal to / as a raw Path, but it resolves to the same filesystem location. As a result, recursive execution could proceed despite the safety flag, enabling destructive permission changes on the root filesystem. The issue and affected context are tracked in the NVD record and CVE record.

Patch

The patch in uutils/coreutils PR #10033 changes the guard from direct path equality to canonicalized root detection:

if self.recursive && self.preserve_root && Self::is_root(file) {
    fn is_root(file: impl AsRef<Path>) -> bool {
        matches!(fs::canonicalize(&file), Ok(p) if p == Path::new("/"))
    }

This is the critical behavioral change: the code now resolves path components before deciding whether the target is root. The patch also adds a regression test for the disclosed bypass case:

#[test]
fn test_chmod_preserve_root_with_paths_that_resolve_to_root() {
    new_ucmd!()
        .arg("-R")
        .arg("--preserve-root")
        .arg("755")
        .arg("/../")
        .fails_with_code(1)
        .stderr_contains("chmod: it is dangerous to operate recursively on '/'");
}

The test is source-grounded evidence that the patch specifically targets unnormalized paths resolving to root, matching the vulnerability summary in the advisory sources.

Review

Pros

  • The patch addresses the actual trust boundary failure: it validates the resolved filesystem object rather than the literal input string.
  • fs::canonicalize is an appropriate primitive for collapsing ., .., and symlink traversal into a normalized absolute path before comparison.
  • The new regression test covers the reported exploit form /../, which was previously missed by the raw equality check.
  • The fix is narrowly scoped and low-complexity, reducing the chance of unrelated behavioral regressions in chmod.

Cons

  • The helper returns false on canonicalization failure, which is safe for the disclosed case only if later execution paths do not create a different bypass condition. The patch snippet does not show broader error-handling semantics around inaccessible or race-prone paths.
  • canonicalize introduces filesystem-dependent behavior and symlink resolution, so the exact semantics should be validated across supported platforms, especially if uutils targets non-Unix environments.
  • The added test covers one representative path but does not demonstrate a broader matrix of equivalent root-resolving inputs such as repeated traversal segments or symlink-mediated resolution to /.
  • The reviewable snippet does not indicate whether similar preserve-root checks exist elsewhere in the codebase and might still rely on lexical path comparison.

Verdict

Root-cause.

Based on the available patch diff, the vulnerability stems from lexical comparison of a user-controlled path against / instead of comparing the canonical resolved target. Replacing file == Path::new("/") with a canonicalization-based is_root check directly fixes that root cause for the disclosed bypass pattern. The regression test aligns with the advisory description and demonstrates the intended blocked behavior. Subject to normal follow-up validation for platform semantics and adjacent call sites, this is a technically sound fix for the patched code path, consistent with the issue described by NVD and MITRE.

Sources