]> Cypherpunks repositories - gostls13.git/commitdiff
compress/bzip2: prevent zero-length Huffman codes
authorJoe Tsai <joetsai@digital-static.net>
Wed, 2 Mar 2016 11:22:00 +0000 (03:22 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Wed, 2 Mar 2016 16:32:46 +0000 (16:32 +0000)
Unlike RFC 1951 (DEFLATE), bzip2 does not use zero-length Huffman codes
to indicate that the symbol is missing. Instead, bzip2 uses a sparse
bitmap to indicate which symbols are present. Thus, it is undefined what
happens when a length of zero is used. Thus, fix the parsing logic so that
the length cannot ever go below 1-bit similar to how the C logic does things.

To confirm that the C bzip2 utility chokes on this data:
$ echo "425a6836314159265359b1f7404b000000400040002000217d184682ee48
a70a12163ee80960" | xxd -r -p | bzip2 -d

bzip2: Data integrity error when decompressing

For reference see:
bzip2-1.0.6/decompress.c:320

Change-Id: Ic1568f8e7f80cdea51d887b4d712cc239c2fe85e
Reviewed-on: https://go-review.googlesource.com/20119
Run-TryBot: Joe Tsai <joetsai@digital-static.net>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/compress/bzip2/bzip2.go
src/compress/bzip2/bzip2_test.go

index b2063590c8bd8e2c628f9a95ef3fbcee206b72ca..71e5372972a19c40c9d0286f6b67bd32b199a397 100644 (file)
@@ -319,6 +319,9 @@ func (bz2 *reader) readBlock() (err error) {
                length := br.ReadBits(5)
                for j := range lengths {
                        for {
+                               if length < 1 || length > 20 {
+                                       return StructuralError("Huffman length out of range")
+                               }
                                if !br.ReadBit() {
                                        break
                                }
@@ -328,9 +331,6 @@ func (bz2 *reader) readBlock() (err error) {
                                        length++
                                }
                        }
-                       if length < 0 || length > 20 {
-                               return StructuralError("Huffman length out of range")
-                       }
                        lengths[j] = uint8(length)
                }
                huffmanTrees[i], err = newHuffmanTree(lengths)
index 2acf40290ce51bb3df3635925057085135fc9eb1..82f1a42d837aa0dc8229bfbf58af1f3c834f2a21 100644 (file)
@@ -172,6 +172,8 @@ const rand3Hex = "1744b384d68c042371244e13500d4bfb98c6244e3d71a5b700224420b59c59
 
 const badBlockSize = "425a683131415926535936dc55330063ffc0006000200020a40830008b0008b8bb9229c28481b6e2a998"
 
+const badHuffmanDelta = "425a6836314159265359b1f7404b000000400040002000217d184682ee48a70a12163ee80960"
+
 const (
        digits = iota
        twain
@@ -278,6 +280,13 @@ func TestBadBlockSize(t *testing.T) {
        }
 }
 
+func TestBadHuffmanDelta(t *testing.T) {
+       _, err := decompressHex(badHuffmanDelta)
+       if err == nil {
+               t.Errorf("unexpected success")
+       }
+}
+
 var bufferOverrunBase64 string = `
 QlpoNTFBWSZTWTzyiGcACMP/////////////////////////////////3/7f3///
 ////4N/fCZODak2Xo44GIHZgkGzDRbFAuwAAKoFV7T6AO6qwA6APb6s2rOoAkAAD