]> Cypherpunks repositories - gostls13.git/commitdiff
archive/zip: fix Writer to validate file
authorAudrey Lim <audreylh@gmail.com>
Sat, 15 Jul 2017 18:33:06 +0000 (12:33 -0600)
committerJoe Tsai <thebrokentoaster@gmail.com>
Sun, 13 Aug 2017 17:33:10 +0000 (17:33 +0000)
The ZIP format uses uint16 to contain the length of the file name and
the length of the Extra section. This change verifies that the length
of these fields fit in an uint16 prior to writing the ZIP file. If not,
an error is returned.

Fixes #17402

Change-Id: Ief9a864d2fe16b89ddb9917838283b801a2c58a4
Reviewed-on: https://go-review.googlesource.com/50250
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/archive/zip/writer.go
src/archive/zip/zip_test.go

index 9f4fceee844b0d1d329456ccfd969b4c7805f368..079917cadc36d12275f4b6d6455afc9b2f8d0085 100644 (file)
@@ -14,6 +14,11 @@ import (
        "unicode/utf8"
 )
 
+var (
+       errLongName  = errors.New("zip: FileHeader.Name too long")
+       errLongExtra = errors.New("zip: FileHeader.Extra too long")
+)
+
 // Writer implements a zip file writer.
 type Writer struct {
        cw          *countWriter
@@ -273,6 +278,14 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
 }
 
 func writeHeader(w io.Writer, h *FileHeader) error {
+       const maxUint16 = 1<<16 - 1
+       if len(h.Name) > maxUint16 {
+               return errLongName
+       }
+       if len(h.Extra) > maxUint16 {
+               return errLongExtra
+       }
+
        var buf [fileHeaderLen]byte
        b := writeBuf(buf[:])
        b.uint32(uint32(fileHeaderSignature))
index 18c2171ba6c15ba13937336c286e6857aaace10c..7d1546c91f95c028b6bec5d31724778c100d4809 100644 (file)
@@ -650,6 +650,44 @@ func TestHeaderTooShort(t *testing.T) {
        testValidHeader(&h, t)
 }
 
+func TestHeaderTooLongErr(t *testing.T) {
+       var headerTests = []struct {
+               name    string
+               extra   []byte
+               wanterr error
+       }{
+               {
+                       name:    strings.Repeat("x", 1<<16),
+                       extra:   []byte{},
+                       wanterr: errLongName,
+               },
+               {
+                       name:    "long_extra",
+                       extra:   bytes.Repeat([]byte{0xff}, 1<<16),
+                       wanterr: errLongExtra,
+               },
+       }
+
+       // write a zip file
+       buf := new(bytes.Buffer)
+       w := NewWriter(buf)
+
+       for _, test := range headerTests {
+               h := &FileHeader{
+                       Name:  test.name,
+                       Extra: test.extra,
+               }
+               _, err := w.CreateHeader(h)
+               if err != test.wanterr {
+                       t.Errorf("error=%v, want %v", err, test.wanterr)
+               }
+       }
+
+       if err := w.Close(); err != nil {
+               t.Fatal(err)
+       }
+}
+
 func TestHeaderIgnoredSize(t *testing.T) {
        h := FileHeader{
                Name:   "foo.txt",