Commit message:
[release-branch.go1.26] os: properly handle trailing slashes in paths in Root
This change fixes a significant mechanism by which
operations in a Root can escape the root.
The implementation of Root on platforms supporting the openat
family of functions assumed that openat(parent, "f/", O_NOFOLLOW)
would not resolve symlinks in "f". This is not correct; the
trailing slash causes f to be resolved.
This permits Root operations to escape when the target filename
ends in a slash and the target is a symlink to a directory outside the
root. This does not permit directly accessing non-directory files
outside a root, since the trailing slash adds a requirement that the
target be a directory. However, under some circumstances an attacker
might exploit this flaw to access non-directory files outside
a root, for example by first renaming a directory outside the root
to a location within it and then accessing files within that directory.
This change adjusts Root's handling of slash-terminated paths.
Trailing slashes are removed from the path at the start of an
operation, and the presence of slashes is tracked as a boolean.
Slashes are never reattached to a path component.
In addition, the doInRoot helper function now automatically
handles trailing slashes in a POSIX-compatible fashion.
When a path ends in one or more slashes:
- symlinks in the final component are resolved; and
- the final path component after symlink resolutions
must reference a directory.
This change also adds a new sets of tests to exercise Root's
behavior in a wider variety of circumstances. These tests
run through a matrix of file configurations, such as:
- path "target", a regular file
- path "dir/../target", a directory
- path "target/", a symlink to "dir/../target/", which does not exist
- etc.
These tests execute Root operations and the corresponding unrooted
operation, validate specific expected results for some configurations,
and verify that the rooted and unrooted versions of the operation
produce the same result.
Thanks to Mundur (https://github.com/M0nd0R) for reporting this issue.
Fixes #79005
Fixes CVE-2026-39822