Skip to content

runtimes: the delete guard can be escaped by a symlink inside the user's home #494

Description

@rominf

Current behavior

runtime_install_root_is_protected resolves paths lexically, which is correct for every spelling of a path but is not symlink-safe. Because the home-directory exemption is consulted before the protected-root list, a symlink the user owns is enough to escape it:

$ ln -s /etc "$HOME/link"
runtime_install_root_is_protected("$HOME/link/child")  ->  false   (reported removable)
std::fs::canonicalize("$HOME/link")                    ->  Ok("/etc")

The path is lexically inside $HOME, so the guard takes the exemption's early return and never consults the protected-root list, while the kernel lands in /etc.

Expected behavior

A path whose resolved location is inside a protected system root is refused, including when it reaches that location through a symlink.

Steps to reproduce

Create $HOME/link -> /etc, then ask the guard about $HOME/link/child.

Environment

  • Observed on Linux against main. Platform-independent logic.

Additional context

This is pre-existing and was not introduced by #491, which fixed a different hole (respelled paths such as /etc/, //etc, $HOME/../../etc). It is filed separately because #491's first draft carried a comment asserting that a symlink "can only land the kernel somewhere the lexical answer did not already call safe" — which is false, and is exactly this case. That comment was corrected, but the hole it described remains.

Closing it means deciding how much of a path to canonicalize. The reason lexical resolution was chosen is that these paths frequently do not exist yet — they come from a registry entry — so canonicalize has nothing to resolve. A plausible approach is canonicalizing the longest existing ancestor and appending the remainder, but that is a design decision rather than a small patch.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions