Fix directory containment bypass via Unicode path collisions on macOS#29442
Fix directory containment bypass via Unicode path collisions on macOS#29442tomasilluminati wants to merge 2 commits into
Conversation
Signed-off-by: Tomas Illuminati Balbin <[email protected]>
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
|
Hi! Just bumping this to see if we can get a reviewer assigned. |
|
Hi @meteorcloudy, saw you touched the labels on this back in May. Any chance you know who could take this for review, or who's the right person to loop in on team-Core? |
|
Closing this in favor of #30245. |
Description
Adds
PathContainmentPolicyinlib/vfs: a platform-aware "is path X contained in path Y?" check that closes the semantic gap between Java's byte-levelString.startsWithcomparisons and APFS's inode resolution on macOS.DEFAULT(Linux, Windows): byte-levelPathFragment.startsWith, identical to today.DARWIN(case-insensitive APFS): fast-path byte check, thenNormalizer.NFKC+toUpperCase().toLowerCase()so NFC/NFD variants, the seven Latin ligatures (ß,fi,fl,ff,ffi,ffl,ſt), and case-folded names that resolve to the same inode are recognised as contained, with a segment-boundary guard to prevent/foofalsely containing/foobar.HOST_POLICYis selected once at init: non-Darwin →DEFAULT; Darwin with-Dbazel.darwin.case_sensitive=trueor a runtimejava.io.tmpdirprobe reporting case-sensitive APFS →DEFAULT; otherwise →DARWIN. This avoids over-folding on case-sensitive APFS, where it would accept symlink targets the kernel would resolve to a different inode.Wired into every destination-escape check in the repository decompressor package:
CompressedTarFunction,ZipDecompressor,SevenZDecompressor,ArFunction,CompressedFunction,PatchUtil.StripPrefixedPathkeeps its byte-level strip (becauserelativeTois byte-level) but exposes a newfoldedPrefixCollision()flag for entries that bypass the byte prefix yet fold to it on the host FS.Motivation
String.startsWithis byte-correct on Linux but not on APFS, which folds NFC/NFD, ligatures, and (by default) case before resolving names. Distinct Java strings therefore resolve to the same inode, allowing an archive entry likepkg_ß/secret.confto bypass apkg_ss/strip prefix, an/Users/Foo/etcsymlink to satisfy a/Users/foo/extractcontainment check, andSECRET.env/secret.envto silently overwrite each other during extraction. Closes the gap at the VFS layer so Linux and Windows builds remain bit-for-bit unchanged. Mitigations cover CWE-176, CWE-22 and CWE-59 on macOS hosts.Build API Changes
No
Checklist
Release Notes
RELNOTES: Fixed a macOS/APFS semantic gap where Unicode normalization, ligature folding, and case-insensitive name resolution could allow path traversal, sandbox escape, or silent overwrites during archive extraction on case-insensitive APFS volumes.