Skip to content

Commit c162f19

Browse files
authored
Merge #233, Fix infinite loop on bad literal data
* Fix infinite loop on bad literal data * Fixes #229. * Rewrite dynamic table header decoding * No more gotos (!) * Easier to read * Handles bad table lengths correctly
1 parent e831547 commit c162f19

File tree

3 files changed

+76
-128
lines changed

3 files changed

+76
-128
lines changed

src/ICSharpCode.SharpZipLib/Zip/Compression/InflaterDynHeader.cs

Lines changed: 63 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -6,164 +6,100 @@ namespace ICSharpCode.SharpZipLib.Zip.Compression
66
class InflaterDynHeader
77
{
88
#region Constants
9-
const int LNUM = 0;
10-
const int DNUM = 1;
11-
const int BLNUM = 2;
12-
const int BLLENS = 3;
13-
const int LENS = 4;
14-
const int REPS = 5;
15-
16-
static readonly int[] repMin = { 3, 3, 11 };
17-
static readonly int[] repBits = { 2, 3, 7 };
189

1910
static readonly int[] BL_ORDER =
2011
{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
2112
#endregion
2213

2314
public bool Decode(StreamManipulator input)
2415
{
25-
decode_loop:
26-
for (;;) {
27-
switch (mode) {
28-
case LNUM:
29-
lnum = input.PeekBits(5);
30-
if (lnum < 0) {
31-
return false;
32-
}
33-
lnum += 257;
34-
input.DropBits(5);
35-
// System.err.println("LNUM: "+lnum);
36-
mode = DNUM;
37-
goto case DNUM; // fall through
38-
case DNUM:
39-
dnum = input.PeekBits(5);
40-
if (dnum < 0) {
41-
return false;
42-
}
43-
dnum++;
44-
input.DropBits(5);
45-
// System.err.println("DNUM: "+dnum);
46-
num = lnum + dnum;
47-
litdistLens = new byte[num];
48-
mode = BLNUM;
49-
goto case BLNUM; // fall through
50-
case BLNUM:
51-
blnum = input.PeekBits(4);
52-
if (blnum < 0) {
53-
return false;
54-
}
55-
blnum += 4;
56-
input.DropBits(4);
57-
blLens = new byte[19];
58-
ptr = 0;
59-
// System.err.println("BLNUM: "+blnum);
60-
mode = BLLENS;
61-
goto case BLLENS; // fall through
62-
case BLLENS:
63-
while (ptr < blnum) {
64-
int len = input.PeekBits(3);
65-
if (len < 0) {
66-
return false;
67-
}
68-
input.DropBits(3);
69-
// System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len);
70-
blLens[BL_ORDER[ptr]] = (byte)len;
71-
ptr++;
16+
try
17+
{
18+
lnum = input.GrabBits(5) + 257;
19+
dnum = input.GrabBits(5) + 1;
20+
blnum = input.GrabBits(4) + 4;
21+
num = lnum + dnum;
22+
23+
lengths = new byte[19];
24+
25+
for (int i = 0; i < blnum; i++)
26+
{
27+
lengths[BL_ORDER[i]] = (byte)input.GrabBits(3, true);
28+
}
29+
blTree = new InflaterHuffmanTree(lengths);
30+
lengths = new byte[num];
31+
32+
int index = 0;
33+
while (index < lnum + dnum)
34+
{
35+
byte len;
36+
37+
int symbol = blTree.GetSymbol(input);
38+
if (symbol < 0)
39+
return false;
40+
if (symbol < 16)
41+
lengths[index++] = (byte)symbol;
42+
else
43+
{
44+
len = 0;
45+
if (symbol == 16)
46+
{
47+
if (index == 0)
48+
return false; // No last length!
49+
len = lengths[index - 1];
50+
symbol = input.GrabBits(2, true) + 3;
7251
}
73-
blTree = new InflaterHuffmanTree(blLens);
74-
blLens = null;
75-
ptr = 0;
76-
mode = LENS;
77-
goto case LENS; // fall through
78-
case LENS: {
79-
int symbol;
80-
while (((symbol = blTree.GetSymbol(input)) & ~15) == 0) {
81-
/* Normal case: symbol in [0..15] */
82-
83-
// System.err.println("litdistLens["+ptr+"]: "+symbol);
84-
litdistLens[ptr++] = lastLen = (byte)symbol;
85-
86-
if (ptr == num) {
87-
/* Finished */
88-
return true;
89-
}
90-
}
91-
92-
/* need more input ? */
93-
if (symbol < 0) {
94-
return false;
95-
}
96-
97-
/* otherwise repeat code */
98-
if (symbol >= 17) {
99-
/* repeat zero */
100-
// System.err.println("repeating zero");
101-
lastLen = 0;
102-
} else {
103-
if (ptr == 0) {
104-
throw new SharpZipBaseException();
105-
}
106-
}
107-
repSymbol = symbol - 16;
52+
else if (symbol == 17)
53+
{
54+
// repeat zero 3..10 times
55+
symbol = input.GrabBits(3, true) + 3;
10856
}
109-
mode = REPS;
110-
goto case REPS; // fall through
111-
case REPS: {
112-
int bits = repBits[repSymbol];
113-
int count = input.PeekBits(bits);
114-
if (count < 0) {
115-
return false;
116-
}
117-
input.DropBits(bits);
118-
count += repMin[repSymbol];
119-
// System.err.println("litdistLens repeated: "+count);
120-
121-
if (ptr + count > num) {
122-
throw new SharpZipBaseException();
123-
}
124-
while (count-- > 0) {
125-
litdistLens[ptr++] = lastLen;
126-
}
127-
128-
if (ptr == num) {
129-
/* Finished */
130-
return true;
131-
}
57+
else
58+
{
59+
// (symbol == 18), repeat zero 11..138 times
60+
symbol = input.GrabBits(7, true) + 11;
13261
}
133-
mode = LENS;
134-
goto decode_loop;
62+
63+
if (index + symbol > lnum + dnum)
64+
return false; // too many lengths!
65+
66+
// repeat last or zero symbol times
67+
while (symbol-- > 0)
68+
lengths[index++] = len;
69+
}
13570
}
71+
72+
if (lengths[256] == 0)
73+
return false; // No end-of-block code!
74+
75+
return true;
76+
}
77+
catch (Exception x)
78+
{
79+
return false;
13680
}
13781
}
13882

13983
public InflaterHuffmanTree BuildLitLenTree()
14084
{
14185
byte[] litlenLens = new byte[lnum];
142-
Array.Copy(litdistLens, 0, litlenLens, 0, lnum);
86+
Array.Copy(lengths, 0, litlenLens, 0, lnum);
14387
return new InflaterHuffmanTree(litlenLens);
14488
}
14589

14690
public InflaterHuffmanTree BuildDistTree()
14791
{
14892
byte[] distLens = new byte[dnum];
149-
Array.Copy(litdistLens, lnum, distLens, 0, dnum);
93+
Array.Copy(lengths, lnum, distLens, 0, dnum);
15094
return new InflaterHuffmanTree(distLens);
15195
}
15296

15397
#region Instance Fields
154-
byte[] blLens;
155-
byte[] litdistLens;
98+
byte[] lengths;
15699

157100
InflaterHuffmanTree blTree;
158101

159-
/// <summary>
160-
/// The current decode mode
161-
/// </summary>
162-
int mode;
163102
int lnum, dnum, blnum, num;
164-
int repSymbol;
165-
byte lastLen;
166-
int ptr;
167103
#endregion
168104

169105
}

src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ public override int Read(byte[] buffer, int offset, int count)
600600
if (inf.IsNeedingInput) {
601601
Fill();
602602
} else if (bytesRead == 0) {
603-
throw new ZipException("Dont know what to do");
603+
throw new ZipException("Invalid input data");
604604
}
605605
}
606606
return count - remainingBytes;

src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/StreamManipulator.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ public int PeekBits(int bitCount)
4141
return (int)(buffer_ & ((1 << bitCount) - 1));
4242
}
4343

44+
/// <summary>
45+
/// Grabs the next n bits from the input and throws if <paramref name="allowZero"/> is false and the result is 0.
46+
/// </summary>
47+
public int GrabBits(int bitCount, bool allowZero = false)
48+
{
49+
var val = PeekBits(bitCount);
50+
if (!allowZero && val == 0)
51+
throw new SharpZipBaseException(bitCount + "-bit value cannot be zero");
52+
DropBits(bitCount);
53+
return val;
54+
}
55+
4456
/// <summary>
4557
/// Drops the next n bits from the input. You should have called PeekBits
4658
/// with a bigger or equal n before, to make sure that enough bits are in

0 commit comments

Comments
 (0)