From 816deacc70f48d14638104e284b3b75d5b1e8036 Mon Sep 17 00:00:00 2001 From: Audrey Lim Date: Sat, 15 Jul 2017 12:33:06 -0600 Subject: [PATCH] archive/zip: fix Writer to validate file 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 Run-TryBot: Joe Tsai TryBot-Result: Gobot Gobot --- src/archive/zip/writer.go | 13 +++++++++++++ src/archive/zip/zip_test.go | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go index 9f4fceee84..079917cadc 100644 --- a/src/archive/zip/writer.go +++ b/src/archive/zip/writer.go @@ -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)) diff --git a/src/archive/zip/zip_test.go b/src/archive/zip/zip_test.go index 18c2171ba6..7d1546c91f 100644 --- a/src/archive/zip/zip_test.go +++ b/src/archive/zip/zip_test.go @@ -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",