tomasilluminati commented on PR #776:
URL: https://github.com/apache/commons-compress/pull/776#issuecomment-4959954578

   > > @garydgregory Thanks, this is a great direction, I'm keen to reuse 
PathFence instead of carrying my own containment code.
   > > The syntactic part is a clean fit. toAbsolutePath().normalize() plus the 
within-root check is generic, and Compress, Configuration and Text can all 
share it as-is.
   > > Links are the tricky bit, and I'd lean toward composing rather than 
folding them in. Part of why they resist living in a path predicate is that 
during extraction the entry doesn't exist yet, so I can't just toRealPath() the 
target. The real protection ends up being operational, resolve each component 
no-follow, create with CREATE_NEW so an existing link is never followed, and on 
Linux write relative to the directory handle (SecureDirectoryStream) to close 
the TOCTOU window. That's bound to the act of creating files, not to judging a 
path.
   > > Where @ppkarwasz point lands well is the already-on-disk case, like a 
trusted config dir. There a resolving check (toRealPath then the same 
within-root test) makes sense, and that could be an optional mode in PathFence. 
The extractor would lean on the syntactic decision and keep its no-follow 
creation layer on top.
   > > So my vote is composed. PathFence owns the containment decision, 
extraction-specific link safety sits around it, and PathFence stays light 
enough for Configuration to reuse.
   > > Happy to dig into the IO PR with you and Piotr whenever it's a good 
time, and to bring over the link cases I already cover as tests. Thanks.
   > 
   > Let's iron out the PathFence in Commons IO if you are available. I'd love 
to get that out and reuse it as it fits best. If we need a separate link 
utility, that sounds like a good Commons IO addition as well. Then we could 
compose in Compress, Configuration, Text, and maybe others like JEXL. WDYT?
   
   @garydgregory
   
   I'm in, happy to help with you and @ppkarwasz.
   
   On "one class or composed", I'd compose and keep PathFence a purely lexical 
predicate (toAbsolutePath().normalize() then startsWith, no filesystem access), 
so it stays trivially reusable for Configuration, Text and JEXL.
   
   One thing I'd make explicit in its contract though: lexical containment 
alone does not stop symlink traversal. normalize() never touches the 
filesystem, so a symlinked component slips straight through. It should 
therefore state plainly that PathFence is a syntactic gate, safe on its own 
only for trusted or link-free trees, and must be paired with real resolution 
for untrusted input.
   
   That resolution is the separate utility you mentioned. Refining my own 
earlier comment, I'd keep the toRealPath check in the utility rather than as a 
mode inside PathFence, so PathFence never touches the filesystem. It carries 
the two modes the cases need:
   
   - toRealPath then containment for the trusted on-disk case (the 
CATALINA_BASE conf symlink). It resolves links but needs the path to exist, so 
it fits reads, not targets that don't exist yet.
   - no-follow resolution for untrusted input and for creation, never following 
a link, which is what the Extractor already does.
   
   That puts the security-sensitive resolution in one place and keeps PathFence 
small enough to reuse everywhere.
   
   If that sounds right to you, I can start there.
   
   Meanwhile I'll keep #776 moving on @Marcono1234 two points, neither depends 
on PathFence.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to