Skip to main content

resolves_within

Function resolves_within 

Source
pub fn resolves_within(path: &Path, root: &Path) -> bool
Expand description

Whether path still lands inside root once symlinks are followed.

A lexical starts_with check is not containment. It answers “does this string begin with that string”, and a symlink at <root>/link pointing at / satisfies it while pointing anywhere on the filesystem. Every file tool in Leviath was relying on exactly that check.

path need not exist - a write_file creating a new file is the common case. The deepest existing ancestor is canonicalized (which is where any symlink lives) and the unresolved tail re-appended, so a not-yet-created file under a symlinked parent is still caught.

root is canonicalized here too rather than trusted: on macOS /tmp is a symlink to /private/tmp, so a root that was stored uncanonicalized would never prefix-match a canonicalized path and every access would be refused.

This is not TOCTOU-proof - a symlink planted between this call and the subsequent open still wins. Closing that needs openat/O_NOFOLLOW throughout. This stops the planted-symlink case, which is the one an agent can arrange for itself.