@@ -11,12 +11,25 @@ import (
1111
1212// untar is a shared helper for untarring an archive. The reader should provide
1313// an uncompressed view of the tar archive.
14- func untar (input io.Reader , dst , src string , dir bool , umask os.FileMode ) error {
14+ func untar (input io.Reader , dst , src string , dir bool , umask os.FileMode , fileSizeLimit int64 , filesLimit int ) error {
1515tarR := tar .NewReader (input )
1616done := false
1717dirHdrs := []* tar.Header {}
1818now := time .Now ()
19+
20+ var (
21+ fileSize int64
22+ filesCount int
23+ )
24+
1925for {
26+ if filesLimit > 0 {
27+ filesCount ++
28+ if filesCount > filesLimit {
29+ return fmt .Errorf ("tar archive contains too many files: %d > %d" , filesCount , filesLimit )
30+ }
31+ }
32+
2033hdr , err := tarR .Next ()
2134if err == io .EOF {
2235if ! done {
@@ -45,7 +58,15 @@ func untar(input io.Reader, dst, src string, dir bool, umask os.FileMode) error
4558path = filepath .Join (path , hdr .Name )
4659}
4760
48- if hdr .FileInfo ().IsDir () {
61+ fileInfo := hdr .FileInfo ()
62+
63+ fileSize += fileInfo .Size ()
64+
65+ if fileSizeLimit > 0 && fileSize > fileSizeLimit {
66+ return fmt .Errorf ("tar archive larger than limit: %d" , fileSizeLimit )
67+ }
68+
69+ if fileInfo .IsDir () {
4970if ! dir {
5071return fmt .Errorf ("expected a single file: %s" , src )
5172}
@@ -81,8 +102,8 @@ func untar(input io.Reader, dst, src string, dir bool, umask os.FileMode) error
81102// Mark that we're done so future in single file mode errors
82103done = true
83104
84- // Open the file for writing
85- err = copyReader (path , tarR , hdr .FileInfo ().Mode (), umask )
105+ // Size limit is tracked using the returned file info.
106+ err = copyReader (path , tarR , hdr .FileInfo ().Mode (), umask , 0 )
86107if err != nil {
87108return err
88109}
@@ -127,7 +148,19 @@ func untar(input io.Reader, dst, src string, dir bool, umask os.FileMode) error
127148
128149// TarDecompressor is an implementation of Decompressor that can
129150// unpack tar files.
130- type TarDecompressor struct {}
151+ type TarDecompressor struct {
152+ // FileSizeLimit limits the total size of all
153+ // decompressed files.
154+ //
155+ // The zero value means no limit.
156+ FileSizeLimit int64
157+
158+ // FilesLimit limits the number of files that are
159+ // allowed to be decompressed.
160+ //
161+ // The zero value means no limit.
162+ FilesLimit int
163+ }
131164
132165func (d * TarDecompressor ) Decompress (dst , src string , dir bool , umask os.FileMode ) error {
133166// If we're going into a directory we should make that first
@@ -146,5 +179,5 @@ func (d *TarDecompressor) Decompress(dst, src string, dir bool, umask os.FileMod
146179}
147180defer f .Close ()
148181
149- return untar (f , dst , src , dir , umask )
182+ return untar (f , dst , src , dir , umask , d . FileSizeLimit , d . FilesLimit )
150183}
0 commit comments