-
Notifications
You must be signed in to change notification settings - Fork 18k
path/filepath: mishandling of Windows UNC paths #56336
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Change https://go.dev/cl/444280 mentions this issue: |
Another mishandling: one can skip UNC path normalization by prefixing a UNC path ( You can test this in the command line: echo 1234>\\?\UNC\localhost\c$\temp\foo.txt
type \\?\UNC\localhost\c$\temp\foo.txt The same applies to the |
This seems like a breaking change to me. At Caddy, we're trying to build on Go 1.20, but our tests are failing on Windows now. caddyserver/caddy#5353 We run this code:
Before, on Go 1.19.5:
After, on Go 1.20.0:
This is a problem for us, because this would allow escaping the root. The reason we add I figure we might be able to fix it by cleaning once, then prepending the slash and cleaning again. But that seems like a bad idea. |
Using |
The point is, this was a breaking change. It wasn't properly documented in the release notes as such, and is surprising behaviour. |
Yes, I agree with that. The documentation of |
Can this issue be reopened? |
@francislavoie It sounds like you are using path/filepath with a URL, which sounds odd to me. URLs are normally handled by path or by net/url. path/filepath has always been intended to work with paths in the file system. Since paths starting with The only room for adjustment I see here is that your path starts with So you're correct that the behavior changed, but it seems to me that it became more correct. I'm sorry for the breakage, but from a compatibility point of view this we've always reserved the right to change behavior in order to fix cases where the code does not match its documentation. I agree that the release notes needs to be updated (ping @neild) but I'm not yet seeing an argument for rolling back this change. Such an argument would show us why the new behavior contradicts the documented behavior of the filepath functions. |
We're doing this to take a user input HTTP URL path (which happens to always be using |
That turns out to be surprisingly subtle — see #57151. |
I agree, it's a very subtle problem. See our function to try to do a safe join of a configured "webroot" with an input URL, mapping to a filesystem path: We'd gladly take a properly supported stdlib function to do this same operation in a smarter way. |
Also before, on Go 1.19.5:
What's going on here is quite subtle. On Windows, Previous versions of Go recognize paths such as Part of the pre-Go 1.20 behavior was to detect no volume name when the third character of the path is ".", and to truncate the volume name to just before the first "." following the first four characters of the path. So in Go 1.19.5:
This parsing behavior doesn't really correspond to the actual Windows path semantics, but it does have the property which is that a volume name, considered as a slash-separated string, will never contain a ".." component. Caddy contains this function:
I do not believe However, while incorrect, prior to Go 1.20 this function is (I think) safe from directory traversal attacks thanks to the fact that we never recognize
I think this function should be changed to use
Note that we're still going from a /-separated path to an OS path here. We're still open to surprising behaviors when
If #57151 is accepted, we'll have a better approach to converting /-separated paths to OS paths:
All that notwithstanding, I think we can do a better job of defending against mistakes by changing Windows volume name detection to explicitly reject any volume name where a path component is "..". So far as I know, no valid Windows volume names contain ".." (unlike "."), and this will ensure that |
Ah yeah, that definitely makes more sense. 🤦♂️ Thanks for pointing that out.
Makes sense. We won't be able to change to minimum Go 1.20 for another 6 months to a year for packaging reasons, so that's not a solution we can use right now. Looking forwards to it, though. |
Recommendation from golang/go#56336 (comment)
Created a new issue #58451 to reject volume names containing a ".." path component, closing this issue in favor of that one. |
UNC paths with a
.
host are not recognized as UNC paths:This causes
Abs
to produce incorrect results when cleaning the path of reserved device names:Clean
converts a path starting with\\
to one starting with only one\
if the path doesn't contain non-zero host and share components, andJoin
will drop the leading\\
from the first joined element:VolumeName
does not normalize separator characters; this is inconsistent with most otherfilepath
functions whichClean
their results:The proper handling of incomplete UNC paths is somewhat ambiguous, since
\\a
(for example) is not a valid Windows filename. Ideally, we'd return an error for invalid paths, but most of these functions do not return errors. I think the simplest behavior is to always preserve a leading\\
when present, so@qmuntal
The text was updated successfully, but these errors were encountered: