Repository: commons-compress Updated Branches: refs/heads/COMPRESS-424 [created] ccf4ce767
COMPRESS-424 add array bounds checks, detect corrupted input Project: http://git-wip-us.apache.org/repos/asf/commons-compress/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-compress/commit/ccf4ce76 Tree: http://git-wip-us.apache.org/repos/asf/commons-compress/tree/ccf4ce76 Diff: http://git-wip-us.apache.org/repos/asf/commons-compress/diff/ccf4ce76 Branch: refs/heads/COMPRESS-424 Commit: ccf4ce767a6cc07f1a88a0c33393e394af3c328b Parents: 34b75c6 Author: Stefan Bodewig <[email protected]> Authored: Thu Dec 28 17:02:43 2017 +0100 Committer: Stefan Bodewig <[email protected]> Committed: Thu Dec 28 17:02:43 2017 +0100 ---------------------------------------------------------------------- .../bzip2/BZip2CompressorInputStream.java | 74 +++++++++++++++----- 1 file changed, 58 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-compress/blob/ccf4ce76/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java b/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java index 17937e8..06e2bee 100644 --- a/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java +++ b/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java @@ -399,12 +399,23 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements return bsR(bin, 32); } + private static void checkBounds(final int checkVal, final int limitInclusive, String name) + throws IOException { + if (checkVal < 0) { + throw new IOException("Corrupted input, " + name + " value negative"); + } + if (checkVal > limitInclusive) { + throw new IOException("Corrupted input, " + name + " value too big"); + } + } + /** * Called by createHuffmanDecodingTables() exclusively. */ private static void hbCreateDecodeTables(final int[] limit, final int[] base, final int[] perm, final char[] length, - final int minLen, final int maxLen, final int alphaSize) { + final int minLen, final int maxLen, final int alphaSize) + throws IOException { for (int i = minLen, pp = 0; i <= maxLen; i++) { for (int j = 0; j < alphaSize; j++) { if (length[j] == i) { @@ -419,7 +430,9 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements } for (int i = 0; i < alphaSize; i++) { - base[length[i] + 1]++; + final int l = length[i]; + checkBounds(l, MAX_ALPHA_SIZE - 1, "length"); + base[l + 1]++; } for (int i = 1, b = base[0]; i < MAX_CODE_LEN; i++) { @@ -474,6 +487,9 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements /* Now the selectors */ final int nGroups = bsR(bin, 3); final int nSelectors = bsR(bin, 15); + checkBounds(alphaSize, MAX_ALPHA_SIZE, "alphaSize"); + checkBounds(nGroups, N_GROUPS, "nGroups"); + checkBounds(nSelectors, MAX_SELECTORS, "nSelectors"); for (int i = 0; i < nSelectors; i++) { int j = 0; @@ -490,6 +506,7 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements for (int i = 0; i < nSelectors; i++) { int v = selectorMtf[i] & 0xff; + checkBounds(v, N_GROUPS - 1, "selectorMtf"); final byte tmp = pos[v]; while (v > 0) { // nearly all times v is zero, 4 in most other cases @@ -522,7 +539,7 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements * Called by recvDecodingTables() exclusively. */ private void createHuffmanDecodingTables(final int alphaSize, - final int nGroups) { + final int nGroups) throws IOException { final Data dataShadow = this.data; final char[][] len = dataShadow.temp_charArray2d; final int[] minLens = dataShadow.minLens; @@ -579,9 +596,10 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements int groupNo = 0; int groupPos = G_SIZE - 1; final int eob = this.nInUse + 1; - int nextSym = getAndMoveToFrontDecode0(0); + int nextSym = getAndMoveToFrontDecode0(); int lastShadow = -1; int zt = selector[groupNo] & 0xff; + checkBounds(zt, N_GROUPS - 1, "zt"); int[] base_zt = base[zt]; int[] limit_zt = limit[zt]; int[] perm_zt = perm[zt]; @@ -602,7 +620,9 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements if (groupPos == 0) { groupPos = G_SIZE - 1; - zt = selector[++groupNo] & 0xff; + checkBounds(++groupNo, MAX_SELECTORS - 1, "groupNo"); + zt = selector[groupNo] & 0xff; + checkBounds(zt, N_GROUPS - 1, "zt"); base_zt = base[zt]; limit_zt = limit[zt]; perm_zt = perm[zt]; @@ -612,15 +632,20 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements } int zn = minLens_zt; + checkBounds(zn, MAX_ALPHA_SIZE - 1, "zn"); int zvec = bsR(bin, zn); while(zvec > limit_zt[zn]) { - zn++; + checkBounds(++zn, MAX_ALPHA_SIZE - 1, "zn"); zvec = (zvec << 1) | bsR(bin, 1); } - nextSym = perm_zt[zvec - base_zt[zn]]; + final int tmp = zvec - base_zt[zn]; + checkBounds(tmp, MAX_ALPHA_SIZE - 1, "zvec"); + nextSym = perm_zt[tmp]; } - final byte ch = seqToUnseq[yy[0]]; + final int yy_0 = yy[0]; + checkBounds(yy_0, 255, "yy"); + final byte ch = seqToUnseq[yy_0]; unzftab[ch & 0xff] += s + 1; while (s-- >= 0) { @@ -634,8 +659,10 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements if (++lastShadow >= limitLast) { throw new IOException("block overrun"); } + checkBounds(nextSym, 256, "nextSym"); final char tmp = yy[nextSym - 1]; + checkBounds(tmp, 255, "yy"); unzftab[seqToUnseq[tmp] & 0xff]++; ll8[lastShadow] = seqToUnseq[tmp]; @@ -656,7 +683,9 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements if (groupPos == 0) { groupPos = G_SIZE - 1; - zt = selector[++groupNo] & 0xff; + checkBounds(++groupNo, MAX_SELECTORS - 1, "groupNo"); + zt = selector[groupNo] & 0xff; + checkBounds(zt, N_GROUPS - 1, "zt"); base_zt = base[zt]; limit_zt = limit[zt]; perm_zt = perm[zt]; @@ -666,30 +695,37 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements } int zn = minLens_zt; + checkBounds(zn, MAX_ALPHA_SIZE - 1, "zn"); int zvec = bsR(bin, zn); while(zvec > limit_zt[zn]) { - zn++; + checkBounds(++zn, MAX_ALPHA_SIZE - 1, "zn"); zvec = (zvec << 1) | bsR(bin, 1); } - nextSym = perm_zt[zvec - base_zt[zn]]; + final int idx = zvec - base_zt[zn]; + checkBounds(idx, MAX_ALPHA_SIZE - 1, "zvec"); + nextSym = perm_zt[idx]; } } this.last = lastShadow; } - private int getAndMoveToFrontDecode0(final int groupNo) throws IOException { + private int getAndMoveToFrontDecode0() throws IOException { final Data dataShadow = this.data; - final int zt = dataShadow.selector[groupNo] & 0xff; + final int zt = dataShadow.selector[0] & 0xff; + checkBounds(zt, N_GROUPS - 1, "zt"); final int[] limit_zt = dataShadow.limit[zt]; int zn = dataShadow.minLens[zt]; + checkBounds(zn, MAX_ALPHA_SIZE - 1, "zn"); int zvec = bsR(bin, zn); while (zvec > limit_zt[zn]) { - zn++; + checkBounds(++zn, MAX_ALPHA_SIZE - 1, "zn"); zvec = (zvec << 1) | bsR(bin, 1); } + final int tmp = zvec - dataShadow.base[zt][zn]; + checkBounds(tmp, MAX_ALPHA_SIZE - 1, "zvec"); - return dataShadow.perm[zt][zvec - dataShadow.base[zt][zn]]; + return dataShadow.perm[zt][tmp]; } private int setupBlock() throws IOException { @@ -709,7 +745,9 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements } for (int i = 0, lastShadow = this.last; i <= lastShadow; i++) { - tt[cftab[ll8[i] & 0xff]++] = i; + final int tmp = cftab[ll8[i] & 0xff]++; + checkBounds(tmp, this.last, "tt index"); + tt[tmp] = i; } if ((this.origPtr < 0) || (this.origPtr >= tt.length)) { @@ -733,6 +771,7 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements if (this.su_i2 <= this.last) { this.su_chPrev = this.su_ch2; int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff; + checkBounds(this.su_tPos, this.data.tt.length - 1, "su_tPos"); this.su_tPos = this.data.tt[this.su_tPos]; if (this.su_rNToGo == 0) { this.su_rNToGo = Rand.rNums(this.su_rTPos) - 1; @@ -758,6 +797,7 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements this.su_chPrev = this.su_ch2; final int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff; this.su_ch2 = su_ch2Shadow; + checkBounds(this.su_tPos, this.data.tt.length - 1, "su_tPos"); this.su_tPos = this.data.tt[this.su_tPos]; this.su_i2++; this.currentState = NO_RAND_PART_B_STATE; @@ -777,6 +817,7 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements return setupRandPartA(); } else if (++this.su_count >= 4) { this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff); + checkBounds(this.su_tPos, this.data.tt.length - 1, "su_tPos"); this.su_tPos = this.data.tt[this.su_tPos]; if (this.su_rNToGo == 0) { this.su_rNToGo = Rand.rNums(this.su_rTPos) - 1; @@ -815,6 +856,7 @@ public class BZip2CompressorInputStream extends CompressorInputStream implements this.su_count = 1; return setupNoRandPartA(); } else if (++this.su_count >= 4) { + checkBounds(this.su_tPos, this.data.ll8.length - 1, "su_tPos"); this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff); this.su_tPos = this.data.tt[this.su_tPos]; this.su_j2 = 0;
