mirror of https://github.com/golang/go.git
archive/tar, archive/zip: disable insecure file name checks with GODEBUG
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 <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Damien Neil <dneil@google.com> Reviewed-by: Russ Cox <rsc@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
parent
f60c77026b
commit
85a2c19b32
|
|
@ -293,6 +293,10 @@ proxyHandler := &httputil.ReverseProxy{
|
||||||
Programs that want to operate on archives containing insecure file names may
|
Programs that want to operate on archives containing insecure file names may
|
||||||
ignore this error.
|
ignore this error.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
Insecure tar file name checks may be entirely disabled by setting the
|
||||||
|
<code>GODEBUG=tarinsecurepath=1</code> environment variable.
|
||||||
|
</p>
|
||||||
</dd>
|
</dd>
|
||||||
</dl><!-- archive/tar -->
|
</dl><!-- archive/tar -->
|
||||||
|
|
||||||
|
|
@ -308,6 +312,10 @@ proxyHandler := &httputil.ReverseProxy{
|
||||||
Programs that want to operate on archives containing insecure file names may
|
Programs that want to operate on archives containing insecure file names may
|
||||||
ignore this error.
|
ignore this error.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
Insecure zip file name checks may be entirely disabled by setting the
|
||||||
|
<code>GODEBUG=zipinsecurepath=1</code> environment variable.
|
||||||
|
</p>
|
||||||
<p><!-- CL 449955 -->
|
<p><!-- CL 449955 -->
|
||||||
Reading from a directory file that contains file data will now return an error.
|
Reading from a directory file that contains file data will now return an error.
|
||||||
The zip specification does not permit directory files to contain file data,
|
The zip specification does not permit directory files to contain file data,
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ package tar
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"internal/godebug"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"math"
|
"math"
|
||||||
"path"
|
"path"
|
||||||
|
|
@ -26,6 +27,8 @@ import (
|
||||||
// architectures. If a large value is encountered when decoding, the result
|
// architectures. If a large value is encountered when decoding, the result
|
||||||
// stored in Header will be the truncated version.
|
// stored in Header will be the truncated version.
|
||||||
|
|
||||||
|
var tarinsecurepath = godebug.New("tarinsecurepath")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrHeader = errors.New("archive/tar: invalid tar header")
|
ErrHeader = errors.New("archive/tar: invalid tar header")
|
||||||
ErrWriteTooLong = errors.New("archive/tar: write too long")
|
ErrWriteTooLong = errors.New("archive/tar: write too long")
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ func (tr *Reader) Next() (*Header, error) {
|
||||||
}
|
}
|
||||||
hdr, err := tr.next()
|
hdr, err := tr.next()
|
||||||
tr.err = err
|
tr.err = err
|
||||||
if err == nil && !filepath.IsLocal(hdr.Name) {
|
if err == nil && tarinsecurepath.Value() != "1" && !filepath.IsLocal(hdr.Name) {
|
||||||
err = ErrInsecurePath
|
err = ErrInsecurePath
|
||||||
}
|
}
|
||||||
return hdr, err
|
return hdr, err
|
||||||
|
|
|
||||||
|
|
@ -1617,6 +1617,7 @@ func TestFileReader(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsecurePaths(t *testing.T) {
|
func TestInsecurePaths(t *testing.T) {
|
||||||
|
t.Setenv("GODEBUG", "tarinsecurepath=0")
|
||||||
for _, path := range []string{
|
for _, path := range []string{
|
||||||
"../foo",
|
"../foo",
|
||||||
"/foo",
|
"/foo",
|
||||||
|
|
@ -1652,3 +1653,22 @@ func TestInsecurePaths(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDisableInsecurePathCheck(t *testing.T) {
|
||||||
|
t.Setenv("GODEBUG", "tarinsecurepath=1")
|
||||||
|
var buf bytes.Buffer
|
||||||
|
tw := NewWriter(&buf)
|
||||||
|
const name = "/foo"
|
||||||
|
tw.WriteHeader(&Header{
|
||||||
|
Name: name,
|
||||||
|
})
|
||||||
|
tw.Close()
|
||||||
|
tr := NewReader(&buf)
|
||||||
|
h, err := tr.Next()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("tr.Next with tarinsecurepath=1: got err %v, want nil", err)
|
||||||
|
}
|
||||||
|
if h.Name != name {
|
||||||
|
t.Fatalf("tr.Next with tarinsecurepath=1: got name %q, want %q", h.Name, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"hash"
|
"hash"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
|
"internal/godebug"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -21,6 +22,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var zipinsecurepath = godebug.New("zipinsecurepath")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrFormat = errors.New("zip: not a valid zip file")
|
ErrFormat = errors.New("zip: not a valid zip file")
|
||||||
ErrAlgorithm = errors.New("zip: unsupported compression algorithm")
|
ErrAlgorithm = errors.New("zip: unsupported compression algorithm")
|
||||||
|
|
@ -108,6 +111,9 @@ func NewReader(r io.ReaderAt, size int64) (*Reader, error) {
|
||||||
// Zip permits an empty file name field.
|
// Zip permits an empty file name field.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if zipinsecurepath.Value() == "1" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
// The zip specification states that names must use forward slashes,
|
// The zip specification states that names must use forward slashes,
|
||||||
// so consider any backslashes in the name insecure.
|
// so consider any backslashes in the name insecure.
|
||||||
if !filepath.IsLocal(f.Name) || strings.Contains(f.Name, `\`) {
|
if !filepath.IsLocal(f.Name) || strings.Contains(f.Name, `\`) {
|
||||||
|
|
|
||||||
|
|
@ -1290,6 +1290,7 @@ func TestFSModTime(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCVE202127919(t *testing.T) {
|
func TestCVE202127919(t *testing.T) {
|
||||||
|
t.Setenv("GODEBUG", "zipinsecurepath=0")
|
||||||
// Archive containing only the file "../test.txt"
|
// Archive containing only the file "../test.txt"
|
||||||
data := []byte{
|
data := []byte{
|
||||||
0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00,
|
0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00,
|
||||||
|
|
@ -1411,6 +1412,7 @@ func TestCVE202139293(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCVE202141772(t *testing.T) {
|
func TestCVE202141772(t *testing.T) {
|
||||||
|
t.Setenv("GODEBUG", "zipinsecurepath=0")
|
||||||
// Archive contains a file whose name is exclusively made up of '/', '\'
|
// Archive contains a file whose name is exclusively made up of '/', '\'
|
||||||
// characters, or "../", "..\" paths, which would previously cause a panic.
|
// characters, or "../", "..\" paths, which would previously cause a panic.
|
||||||
//
|
//
|
||||||
|
|
@ -1586,6 +1588,7 @@ func TestIssue54801(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsecurePaths(t *testing.T) {
|
func TestInsecurePaths(t *testing.T) {
|
||||||
|
t.Setenv("GODEBUG", "zipinsecurepath=0")
|
||||||
for _, path := range []string{
|
for _, path := range []string{
|
||||||
"../foo",
|
"../foo",
|
||||||
"/foo",
|
"/foo",
|
||||||
|
|
@ -1616,3 +1619,26 @@ func TestInsecurePaths(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDisableInsecurePathCheck(t *testing.T) {
|
||||||
|
t.Setenv("GODEBUG", "zipinsecurepath=1")
|
||||||
|
var buf bytes.Buffer
|
||||||
|
zw := NewWriter(&buf)
|
||||||
|
const name = "/foo"
|
||||||
|
_, err := zw.Create(name)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("zw.Create(%q) = %v", name, err)
|
||||||
|
}
|
||||||
|
zw.Close()
|
||||||
|
zr, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewReader with zipinsecurepath=1: got err %v, want nil", err)
|
||||||
|
}
|
||||||
|
var gotPaths []string
|
||||||
|
for _, f := range zr.File {
|
||||||
|
gotPaths = append(gotPaths, f.Name)
|
||||||
|
}
|
||||||
|
if want := []string{name}; !reflect.DeepEqual(gotPaths, want) {
|
||||||
|
t.Errorf("NewReader with zipinsecurepath=1: got files %q, want %q", gotPaths, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue