Skip to content
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

Port Decompression bomb security changes from v1 #418

Merged
merged 1 commit into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 32 additions & 17 deletions decompress.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,25 @@ type Decompressor interface {
Decompress(dst, src string, dir bool, umask os.FileMode) error
}

// Decompressors is the mapping of extension to the Decompressor implementation
// that will decompress that extension/type.
var Decompressors map[string]Decompressor

func init() {
tarDecompressor := new(TarDecompressor)
tbzDecompressor := new(TarBzip2Decompressor)
tgzDecompressor := new(TarGzipDecompressor)
txzDecompressor := new(TarXzDecompressor)
tzstDecompressor := new(TarZstdDecompressor)
// LimitedDecompressors creates the set of Decompressors, but with each compressor configured
// with the given filesLimit and/or fileSizeLimit where applicable.
func LimitedDecompressors(filesLimit int, fileSizeLimit int64) map[string]Decompressor {
tarDecompressor := &TarDecompressor{FilesLimit: filesLimit, FileSizeLimit: fileSizeLimit}
tbzDecompressor := &TarBzip2Decompressor{FilesLimit: filesLimit, FileSizeLimit: fileSizeLimit}
tgzDecompressor := &TarGzipDecompressor{FilesLimit: filesLimit, FileSizeLimit: fileSizeLimit}
txzDecompressor := &TarXzDecompressor{FilesLimit: filesLimit, FileSizeLimit: fileSizeLimit}
tzstDecompressor := &TarZstdDecompressor{FilesLimit: filesLimit, FileSizeLimit: fileSizeLimit}
bzipDecompressor := &Bzip2Decompressor{FileSizeLimit: fileSizeLimit}
gzipDecompressor := &GzipDecompressor{FileSizeLimit: fileSizeLimit}
xzDecompressor := &XzDecompressor{FileSizeLimit: fileSizeLimit}
zipDecompressor := &ZipDecompressor{FilesLimit: filesLimit, FileSizeLimit: fileSizeLimit}
zstDecompressor := &ZstdDecompressor{FileSizeLimit: fileSizeLimit}

Decompressors = map[string]Decompressor{
"bz2": new(Bzip2Decompressor),
"gz": new(GzipDecompressor),
"xz": new(XzDecompressor),
return map[string]Decompressor{
"bz2": bzipDecompressor,
"gz": gzipDecompressor,
"xz": xzDecompressor,
"tar": tarDecompressor,
"tar.bz2": tbzDecompressor,
"tar.gz": tgzDecompressor,
"tar.xz": txzDecompressor,
Expand All @@ -41,12 +45,23 @@ func init() {
"tgz": tgzDecompressor,
"txz": txzDecompressor,
"tzst": tzstDecompressor,
"zip": new(ZipDecompressor),
"tar": tarDecompressor,
"zst": new(ZstdDecompressor),
"zip": zipDecompressor,
"zst": zstDecompressor,
}
}

const (
noFilesLimit = 0
noFileSizeLimit = 0
)

// Decompressors is the mapping of extension to the Decompressor implementation
// configured with default settings that will decompress that extension/type.
//
// Note: these decompressors by default do not limit the number of files or the
// maximum file size created by the decompressed payload.
var Decompressors = LimitedDecompressors(noFilesLimit, noFileSizeLimit)

// containsDotDot checks if the filepath value v contains a ".." entry.
// This will check filepath components by splitting along / or \. This
// function is copied directly from the Go net/http implementation.
Expand Down
50 changes: 50 additions & 0 deletions decompress_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package getter

import (
"testing"
)

func TestLimitedDecompressors(t *testing.T) {
const (
maxFiles = 111
maxSize = 222
)

checkFileSizeLimit := func(limit int64) {
if limit != maxSize {
t.Fatalf("expected FileSizeLimit of %d, got %d", maxSize, limit)
}
}

checkFilesLimit := func(limit int) {
if limit != maxFiles {
t.Fatalf("expected FilesLimit of %d, got %d", maxFiles, limit)
}
}

decompressors := LimitedDecompressors(maxFiles, maxSize)

checkFilesLimit(decompressors["tar"].(*TarDecompressor).FilesLimit)
checkFileSizeLimit(decompressors["tar"].(*TarDecompressor).FileSizeLimit)

checkFilesLimit(decompressors["tar.bz2"].(*TarBzip2Decompressor).FilesLimit)
checkFileSizeLimit(decompressors["tar.bz2"].(*TarBzip2Decompressor).FileSizeLimit)

checkFilesLimit(decompressors["tar.gz"].(*TarGzipDecompressor).FilesLimit)
checkFileSizeLimit(decompressors["tar.gz"].(*TarGzipDecompressor).FileSizeLimit)

checkFilesLimit(decompressors["tar.xz"].(*TarXzDecompressor).FilesLimit)
checkFileSizeLimit(decompressors["tar.xz"].(*TarXzDecompressor).FileSizeLimit)

checkFilesLimit(decompressors["tar.zst"].(*TarZstdDecompressor).FilesLimit)
checkFileSizeLimit(decompressors["tar.zst"].(*TarZstdDecompressor).FileSizeLimit)

checkFilesLimit(decompressors["zip"].(*ZipDecompressor).FilesLimit)
checkFileSizeLimit(decompressors["zip"].(*ZipDecompressor).FileSizeLimit)

// ones with file size limit only
checkFileSizeLimit(decompressors["bz2"].(*Bzip2Decompressor).FileSizeLimit)
checkFileSizeLimit(decompressors["gz"].(*GzipDecompressor).FileSizeLimit)
checkFileSizeLimit(decompressors["xz"].(*XzDecompressor).FileSizeLimit)
checkFileSizeLimit(decompressors["zst"].(*ZstdDecompressor).FileSizeLimit)
}