-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
archive/tar, archive/zip: add ErrInsecurePath #55356
Comments
It isn't clear to me whether the proposal includes returning |
Using |
I find that behavior to be fairly surprising. Suppose someone were writing a service that you can send ZIP and TAR files to and it would report whether they are "safe". I would expect the answer given by the service to be agnostic to the platform it is running on. The example might seem esoteric, but it's not that far fetched from how Gmail auto-scans attachments for viruses. |
In general, I would not expect The only OS-specific behavior is isolated within functionality that deal with |
I expect that many users of the |
So far as I can see, we can:
Of these options, OS-specific behavior seems the least objectionable to me. |
There are also variations on (1) and (3) that we could consider: we could add a field or method to the 1a. Call an archive containing the file (1a) provides better default security, but (3a) provides better backward-compatibility for existing users on Unix. 🤔 |
Hmm. It's not clear to me how would override that behavior if (for example) one is writing the data to an isolated in-memory database rather than the local filesystem. Would it make sense to return the error from the |
We would return
|
Personally, I'm more of a fan of option 1 in #55356 (comment). Even though ZIP has its heritage in Windows, and TAR has its heritage in Unix, there's no doubt that they've functionally become cross-platform archive formats when people construct archives on one system and pass it to another system. I'm just not comfortable with the idea of a ZIP or TAR file being valid solely based on what OS it is executing on. That said, I haven't studied in depth the implications of option 2:
|
https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file states:
I'm not certain if If we're willing to do path sanitization on archive filenames, perhaps we can convert these reserved filenames into safe paths such as "./COM1". If we're going the sanitization route, however, then perhaps we should sanitize all filenames and add an |
Apparently those names are global as they predate the introduction of directories in DOS (!!!) https://devblogs.microsoft.com/oldnewthing/20031022-00/?p=42073 |
This proposal has been added to the active column of the proposals project |
The general approach sounds right but I'm not sure we can make the behavior completely portable. What do we do about paths with backslashes or colons? Are those insecure on all systems? It seems like they can't be treated the same on all systems. A file named \a\b is fine on Unix, as is com1. Programs that really need to defend against cross-operating-system problems will still need their own rules, like the go command refuses to have 'com1' in a module path. |
Also what about symlinks? Do we reject symlinks containing absolute or other "insecure" paths? A tar file could contain x -> / followed by x/etc/passwd |
This proposal doesn't address symlinks. The vast majority of path vulnerabilities caused by the current archive/tar and archive/zip behavior have been in programs that don't process symlinks. Perhaps we should do something to address the case of an archive that creates a symlink and then writes to it, but addressing the simpler case of path traversal via filenames gets us 99% of the way there and is worth doing on its own. |
It seems to me that a lot of those security issues emerged because we don't provide an easy, secure way to extract an archive out of the box, at least for the simple case of extracting (a subset of) regular files and directories. However, adding such facility would be a completely separate proposal and wouldn't help with the existing insecure code out in the wild now. As such, I think adding It seems to me that the path checking should use OS-specific behavior. We want to guard against paths that are written to directly or when used with The zip format specifies that the filenames:
It seems that checking the above for ZIP files should be safe on all platforms. Of course additional checks for If we add |
@martin-sucha's example about #c/cons being invalid on Plan 9 but valid elsewhere seems like a good argument for OS-dependent behavior. Assuming we make the disallow list OS-dependent, does anyone object to adding ErrInsecurePath and accepting this proposal? |
It's not the behavior I would prefer, but SGTM. As @neild noted in #55356 (comment), there just doesn't seem like many good options. |
This is great! One opinion on the color of the bike shed. I feel like surfacing the file handle as part of the error would be cleaner than returning a handle and a non-nil error. That is, having a |
I have now tested this, and this does indeed write to the COM1 device. So does I think this makes it clear that filename sanitization needs to be OS-dependent; the set of filenames which are unsafe on Windows but perfectly valid elsewhere is large. Assuming #56217 is resolved by changing |
Change https://go.dev/cl/449937 mentions this issue: |
Change https://go.dev/cl/452495 mentions this issue: |
It appears that Docker images frequently contain tar files containing absolute paths. This change causes problems for programs which operate on these tar files. Since Docker is not a small or uncommon use case, reopening this issue to evaluate whether this influences our willingness to make this change. One obvious point is that there should be a GODEBUG flag to restore the original behavior; https://go.dev/cl/452495 adds Possible courses of action I see here:
|
Add GODEBUG=tarinsecurepath=1 and GODEBUG=zipinsecurepath=1 settings to disable file name validation. For #55356. Change-Id: Iaacdc629189493e7ea3537a81660215a59dd40a4 Reviewed-on: https://go-review.googlesource.com/c/go/+/452495 Reviewed-by: Bryan Mills <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Damien Neil <[email protected]> Reviewed-by: Russ Cox <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]>
Add GODEBUG=tarinsecurepath=1 and GODEBUG=zipinsecurepath=1 settings to disable file name validation. For golang#55356. Change-Id: Iaacdc629189493e7ea3537a81660215a59dd40a4 Reviewed-on: https://go-review.googlesource.com/c/go/+/452495 Reviewed-by: Bryan Mills <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Damien Neil <[email protected]> Reviewed-by: Russ Cox <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]>
Change https://go.dev/cl/452616 mentions this issue: |
This change is being made late in the release cycle. Disable it by default. Insecure path checks may be enabled by setting GODEBUG=tarinsecurepath=0 or GODEBUG=zipinsecurepath=0. We can enable this by default in Go 1.21 after publicizing the change more broadly and giving users a chance to adapt to the change. For #55356. Change-Id: I549298b3c85d6c8c7fd607c41de1073083f79b1d Reviewed-on: https://go-review.googlesource.com/c/go/+/452616 TryBot-Result: Gopher Robot <[email protected]> Auto-Submit: Damien Neil <[email protected]> Reviewed-by: Russ Cox <[email protected]> Run-TryBot: Damien Neil <[email protected]>
Change https://go.dev/cl/458875 mentions this issue: |
CL 452616 disables path security checks by default, enabling them only when GODEBUG=tarinsecurepath=0 or GODEBUG=zipinsecurepath=0 is set. Remove now-obsolete documenation of the path checks. For #55356 Change-Id: I4ae57534efe9e27368d5e67773a502dd0e56eff4 Reviewed-on: https://go-review.googlesource.com/c/go/+/458875 Reviewed-by: Russ Cox <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Damien Neil <[email protected]>
Notably includes golang/go#66869 and `RemoveInsecurePaths()` for golang/go#55356 Updates CI.
Notably includes golang/go#66869 and `RemoveInsecurePaths()` for golang/go#55356
This is an alternative fix for #25849, as proposed by @dsnet in #25849 (comment).
The
archive/tar
andarchive/zip
readers return unsanitized paths from archives. Careless use of these paths leads to path traversal attacks.Proposal:
An insecure filename is an absolute path, or a path containing a relative path component (
../
).When
tar.Reader.Next
reads a file with an insecure filename, it returnstar.ErrInsecurePath
.When
zip.NewReader
opens an archive containing an insecure filename, it returnszip.ErrInsecurePath
.In both cases, the function also returns a usable object (a
*tar.Header
or*zip.Reader
).In the case where the caller wants to handle archives with insecure filenames, they may ignore the
ErrInsecurePath
error and perform whatever sanitization they find appropriate. If the caller takes no action, they get an error when processing an unsafe archive.The advantage over automatically sanitizing filenames is that we don't silently change the semantics of archives. A tar archive may legitimately contain absolute path names; silently converting these to relative names seems more surprising than reporting an error. In addition, there isn't always an obvious sanitized name--we probably want to reject the name
COM1
on Windows, but what would we rewrite it into?The text was updated successfully, but these errors were encountered: