Fedora Account System
Red Hat Associate
Red Hat Customer
AI_ONLY_REPORT package: cockpit-files-36-1.el10 ------ Summary: Symlink Race in chown/chmod Operations: privileged pathname-based ownership and permission changes can be redirected through a symlink swap in attacker-writable directories Requirements to exploit: A local attacker must be able to modify entries in the directory being operated on, a Cockpit Files session must perform one of the affected operations with `superuser: "require"` or with `superuser: "try"` successfully elevated, and the attacker must win a timing race that replaces the intended pathname with a symlink before the privileged `chown` or `chmod` runs. Component affected: `cockpit-files-36-1.el10`, privileged file metadata operations in `src/dialogs/create-file.tsx`, `src/dialogs/mkdir.tsx`, `src/upload-button.tsx`, `src/dialogs/copyPasteOwnership.tsx`, and `src/dialogs/permissions.tsx` Version affected: `cockpit-files-36-1.el10` Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not notified. CVSS: CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:H/A:H - 6.4 (MEDIUM) AV:L - Exploitation requires local access to a writable directory processed by the application. AC:H - The attacker must win a symlink race against a privileged filesystem operation. PR:L - The attacker needs the ability to create or replace entries in the target directory. UI:R - A privileged user must trigger the affected file creation, upload, ownership, or permission change flow. S:U - The impact remains within the same system security scope. C:N - The observed effect is unauthorized metadata change rather than direct information disclosure. I:H - Ownership or mode changes on an unintended target can materially alter system or application state. A:H - Incorrect privileged metadata changes can render files or services unusable. Impact: Moderate. The flaw can affect integrity and availability in a meaningful way, but exploitation is not straightforward: it is local-only, depends on a privileged user operating on an attacker-writable path, and requires winning a race. Under Red Hat's severity guidance, this is better classified as Moderate than Important because the security impact is real but workflow- and configuration-dependent and less easily exploitable. Embargo: no Reason: The issue appears to be a local race condition with non-trivial prerequisites and practical mitigations, so it does not appear to warrant embargo handling. Acknowledgement: Aisle Research Vulnerability Details: Several code paths perform privileged `chown` or `chmod` operations on pathnames after separate create, selection, copy, or upload steps. When the acted-on directory is attacker-writable, that pathname can be replaced with a symlink before the privileged metadata change executes. In that case, the operation can be redirected to an unintended target. The following exact call sites illustrate the pattern: ```tsx // src/dialogs/create-file.tsx:45 await cockpit.spawn(["chown", owner, filename], { superuser: "require" }); // src/dialogs/mkdir.tsx:45 await cockpit.spawn(["chown", owner, path], opts); // src/upload-button.tsx:268 await cockpit.spawn(["chown", owner, destination], { superuser: "try" }); // src/dialogs/copyPasteOwnership.tsx:44-49 await cockpit.spawn([ "chown", "--recursive", ownerStr, ...clipboard.files.map(file => dstPath + "/" + file.name), ], { superuser: "require" }); // src/dialogs/permissions.tsx:170-174 await cockpit.spawn(["chmod", "-R", mode_to_args(mode), full_path], { superuser: "try", err: "message" }); await cockpit.spawn(["chown", "-R", owner + ":" + group, full_path], { superuser: "try", err: "message" }); // src/dialogs/permissions.tsx:191-192 await cockpit.spawn(["chmod", mode.toString(8), ...file_paths], { superuser: "try", err: "message" }); ``` For `chown`, the absence of `--no-dereference` means a symlink operand is resolved to its target. For `chmod`, operating on a symlink pathname likewise affects the referenced file rather than the link itself. Because these operations are issued against mutable pathnames rather than stable descriptors, an attacker who controls the directory namespace can attempt a symlink swap between the earlier UI action and the later privileged metadata change. The practical impact depends on runtime conditions. If the affected flow is used only in directories not writable by untrusted users, or if privileged escalation is unavailable, exploitability is substantially reduced. Where a privileged user does operate on attacker-writable directories, the bug can result in unintended ownership or permission changes on arbitrary files reachable through the symlink target. Steps to reproduce: 1. Use a Cockpit session where privileged filesystem operations are available, so that `superuser: "require"` or `superuser: "try"` results in an elevated `chown` or `chmod`. 2. Choose a directory writable by a low-privileged attacker and accessible through the Files UI. 3. Select one affected flow, for example creating a file with an owner, creating a directory with an owner, uploading with owner adjustment, or applying recursive ownership or permission changes. 4. In parallel, continuously replace the intended pathname in that writable directory with a symlink to a chosen target file. 5. Trigger the UI action as the privileged user. 6. Observe that the target file's ownership or mode changes, rather than only the originally intended filesystem object. Mitigation: Until a fix is available, avoid using privileged ownership or permission changes in directories writable by untrusted users. Where possible, restrict or disable superuser-backed file operations for shared writable paths. Operationally, prefer workflows that perform metadata changes only on trusted directories. Proposed Fix: Add `--no-dereference` and `--` to the affected `chown` and `chmod` invocations so that symlink operands are not followed on these path-based operations. A minimal patch is below. ```diff diff --git a/src/dialogs/create-file.tsx b/src/dialogs/create-file.tsx @@ await cockpit.spawn(["chown", owner, filename], { superuser: "require" }); + await cockpit.spawn(["chown", "-no-dereference", owner, "-", filename], { superuser: "require" }); diff --git a/src/dialogs/mkdir.tsx b/src/dialogs/mkdir.tsx @@ await cockpit.spawn(["chown", owner, path], opts); + await cockpit.spawn(["chown", "-no-dereference", owner, "-", path], opts); diff --git a/src/upload-button.tsx b/src/upload-button.tsx @@ await cockpit.spawn(["chown", owner, destination], { superuser: "try" }); + await cockpit.spawn(["chown", "--no-dereference", owner, "--", destination], { superuser: "try" }); diff --git a/src/dialogs/copyPasteOwnership.tsx b/src/dialogs/copyPasteOwnership.tsx @@ "chown", "--recursive", ownerStr, ...clipboard.files.map(file => dstPath + "/" + file.name), + "chown", "--no-dereference", "--recursive", ownerStr, "--", ...clipboard.files.map(file => dstPath + "/" + file.name), diff --git a/src/dialogs/permissions.tsx b/src/dialogs/permissions.tsx @@ await cockpit.spawn(["chmod", "-R", mode_to_args(mode), full_path], { superuser: "try", err: "message" }); await cockpit.spawn(["chown", "-R", owner + ":" + group, full_path], { superuser: "try", err: "message" }); + await cockpit.spawn(["chmod", "--no-dereference", "-R", mode_to_args(mode), "--", full_path], { superuser: "try", err: "message" }); + await cockpit.spawn(["chown", "--no-dereference", "-R", owner + ":" + group, "--", full_path], { superuser: "try", err: "message" }); @@ await cockpit.spawn(["chmod", mode.toString(8), ...file_paths], { superuser: "try", err: "message" }); + await cockpit.spawn(["chmod", "--no-dereference", mode.toString(8), "--", ...file_paths], { superuser: "try", err: "message" }); ``` ------ This report was generated using AI technology. Always review AI-generated content prior to use