Commit message: bunzip2: fix runCnt overflow from bug 10431

This particular corrupted file can be dealth with by using "unsigned".
If there will be cases where it genuinely overflows, there is a disabled
code to deal with that too.

function                                             old     new   delta
get_next_block                                      1678    1667     -11

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
CVE: CVE-2017-15873
CWE: CWE-190
Vulnerability description: The get_next_block function in archival/libarchive/decompress_bunzip2.c in BusyBox 1.27.2 has an Integer Overflow that may lead to a write access violation.

Project: busybox

void FAST_FUNC dealloc_bunzip(bunzip_data *bd)
{
	free(bd->dbuf);
	free(bd);
}

Project: busybox

static unsigned get_bits(bunzip_data *bd, int bits_wanted)
{
	unsigned bits = 0;
	/* Cache bd->inbufBitCount in a CPU register (hopefully): */
	int bit_count = bd->inbufBitCount;

	/* If we need to get more data from the byte buffer, do so.  (Loop getting
	   one byte at a time to enforce endianness and avoid unaligned access.) */
	while (bit_count < bits_wanted) {

		/* If we need to read more data from file into byte buffer, do so */
		if (bd->inbufPos == bd->inbufCount) {
			/* if "no input fd" case: in_fd == -1, read fails, we jump */
			bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE);
			if (bd->inbufCount <= 0)
				longjmp(bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF);
			bd->inbufPos = 0;
		}

		/* Avoid 32-bit overflow (dump bit buffer to top of output) */
		if (bit_count >= 24) {
			bits = bd->inbufBits & ((1U << bit_count) - 1);
			bits_wanted -= bit_count;
			bits <<= bits_wanted;
			bit_count = 0;
		}

		/* Grab next 8 bits of input from buffer. */
		bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
		bit_count += 8;
	}

	/* Calculate result */
	bit_count -= bits_wanted;
	bd->inbufBitCount = bit_count;
	bits |= (bd->inbufBits >> bit_count) & ((1 << bits_wanted) - 1);

	return bits;
}

Project: busybox

int main(int argc, char **argv)
{
	char c;

	int i = unpack_bz2_stream(0, 1);
	if (i < 0)
		fprintf(stderr, "%s\n", bunzip_errors[-i]);
	else if (read(STDIN_FILENO, &c, 1))
		fprintf(stderr, "Trailing garbage ignored\n");
	return -i;
}

Project: busybox

int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len)
{
	const uint32_t *dbuf;
	int pos, current, previous;
	uint32_t CRC;

	/* If we already have error/end indicator, return it */
	if (bd->writeCount < 0)
		return bd->writeCount;

	dbuf = bd->dbuf;

	/* Register-cached state (hopefully): */
	pos = bd->writePos;
	current = bd->writeCurrent;
	CRC = bd->writeCRC; /* small loss on x86-32 (not enough regs), win on x86-64 */

	/* We will always have pending decoded data to write into the output
	   buffer unless this is the very first call (in which case we haven't
	   Huffman-decoded a block into the intermediate buffer yet). */
	if (bd->writeCopies) {

 dec_writeCopies:
		/* Inside the loop, writeCopies means extra copies (beyond 1) */
		--bd->writeCopies;

		/* Loop outputting bytes */
		for (;;) {

			/* If the output buffer is full, save cached state and return */
			if (--len < 0) {
				/* Unlikely branch.
				 * Use of "goto" instead of keeping code here
				 * helps compiler to realize this. */
				goto outbuf_full;
			}

			/* Write next byte into output buffer, updating CRC */
			*outbuf++ = current;
			CRC = (CRC << 8) ^ bd->crc32Table[(CRC >> 24) ^ current];

			/* Loop now if we're outputting multiple copies of this byte */
			if (bd->writeCopies) {
				/* Unlikely branch */
				/*--bd->writeCopies;*/
				/*continue;*/
				/* Same, but (ab)using other existing --writeCopies operation
				 * (and this if() compiles into just test+branch pair): */
				goto dec_writeCopies;
			}
 decode_next_byte:
			if (--bd->writeCount < 0)
				break; /* input block is fully consumed, need next one */

			/* Follow sequence vector to undo Burrows-Wheeler transform */
			previous = current;
			pos = dbuf[pos];
			current = (uint8_t)pos;
			pos >>= 8;

			/* After 3 consecutive copies of the same byte, the 4th
			 * is a repeat count.  We count down from 4 instead
			 * of counting up because testing for non-zero is faster */
			if (--bd->writeRunCountdown != 0) {
				if (current != previous)
					bd->writeRunCountdown = 4;
			} else {
				/* Unlikely branch */
				/* We have a repeated run, this byte indicates the count */
				bd->writeCopies = current;
				current = previous;
				bd->writeRunCountdown = 5;

				/* Sometimes there are just 3 bytes (run length 0) */
				if (!bd->writeCopies) goto decode_next_byte;

				/* Subtract the 1 copy we'd output anyway to get extras */
				--bd->writeCopies;
			}
		} /* for(;;) */

		/* Decompression of this input block completed successfully */
		bd->writeCRC = CRC = ~CRC;
		bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ CRC;

		/* If this block had a CRC error, force file level CRC error */
		if (CRC != bd->headerCRC) {
			bd->totalCRC = bd->headerCRC + 1;
			return RETVAL_LAST_BLOCK;
		}
	}

	/* Refill the intermediate buffer by Huffman-decoding next block of input */
	{
		int r = get_next_block(bd);
		if (r) { /* error/end */
			bd->writeCount = r;
			return (r != RETVAL_LAST_BLOCK) ? r : len;
		}
	}

	CRC = ~0;
	pos = bd->writePos;
	current = bd->writeCurrent;
	goto decode_next_byte;

 outbuf_full:
	/* Output buffer is full, save cached state and return */
	bd->writePos = pos;
	bd->writeCurrent = current;
	bd->writeCRC = CRC;

	bd->writeCopies++;

	return 0;
}

Project: busybox

int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd,
		const void *inbuf, int len)
{
	bunzip_data *bd;
	unsigned i;
	enum {
		BZh0 = ('B' << 24) + ('Z' << 16) + ('h' << 8) + '0',
		h0 = ('h' << 8) + '0',
	};

	/* Figure out how much data to allocate */
	i = sizeof(bunzip_data);
	if (in_fd != -1) i += IOBUF_SIZE;

	/* Allocate bunzip_data.  Most fields initialize to zero. */
	bd = *bdp = xzalloc(i);

	/* Setup input buffer */
	bd->in_fd = in_fd;
	if (-1 == in_fd) {
		/* in this case, bd->inbuf is read-only */
		bd->inbuf = (void*)inbuf; /* cast away const-ness */
	} else {
		bd->inbuf = (uint8_t*)(bd + 1);
		memcpy(bd->inbuf, inbuf, len);
	}
	bd->inbufCount = len;

	/* Init the CRC32 table (big endian) */
	crc32_filltable(bd->crc32Table, 1);

	/* Setup for I/O error handling via longjmp */
	i = setjmp(bd->jmpbuf);
	if (i) return i;

	/* Ensure that file starts with "BZh['1'-'9']." */
	/* Update: now caller verifies 1st two bytes, makes .gz/.bz2
	 * integration easier */
	/* was: */
	/* i = get_bits(bd, 32); */
	/* if ((unsigned)(i - BZh0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA; */
	i = get_bits(bd, 16);
	if ((unsigned)(i - h0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA;

	/* Fourth byte (ascii '1'-'9') indicates block size in units of 100k of
	   uncompressed data.  Allocate intermediate buffer for block. */
	/* bd->dbufSize = 100000 * (i - BZh0); */
	bd->dbufSize = 100000 * (i - h0);

	/* Cannot use xmalloc - may leak bd in NOFORK case! */
	bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(bd->dbuf[0]));
	if (!bd->dbuf) {
		free(bd);
		xfunc_die();
	}
	return RETVAL_OK;
}

Project: busybox

unpack_bz2_stream(transformer_state_t *xstate)
{
	IF_DESKTOP(long long total_written = 0;)
	bunzip_data *bd;
	char *outbuf;
	int i;
	unsigned len;

	if (check_signature16(xstate, BZIP2_MAGIC))
		return -1;

	outbuf = xmalloc(IOBUF_SIZE);
	len = 0;
	while (1) { /* "Process one BZ... stream" loop */

		i = start_bunzip(&bd, xstate->src_fd, outbuf + 2, len);

		if (i == 0) {
			while (1) { /* "Produce some output bytes" loop */
				i = read_bunzip(bd, outbuf, IOBUF_SIZE);
				if (i < 0) /* error? */
					break;
				i = IOBUF_SIZE - i; /* number of bytes produced */
				if (i == 0) /* EOF? */
					break;
				if (i != transformer_write(xstate, outbuf, i)) {
					i = RETVAL_SHORT_WRITE;
					goto release_mem;
				}
				IF_DESKTOP(total_written += i;)
			}
		}

		if (i != RETVAL_LAST_BLOCK
		/* Observed case when i == RETVAL_OK:
		 * "bzcat z.bz2", where "z.bz2" is a bzipped zero-length file
		 * (to be exact, z.bz2 is exactly these 14 bytes:
		 * 42 5a 68 39 17 72 45 38  50 90 00 00 00 00).
		 */
		 && i != RETVAL_OK
		) {
			bb_error_msg("bunzip error %d", i);
			break;
		}
		if (bd->headerCRC != bd->totalCRC) {
			bb_error_msg("CRC error");
			break;
		}

		/* Successfully unpacked one BZ stream */
		i = RETVAL_OK;

		/* Do we have "BZ..." after last processed byte?
		 * pbzip2 (parallelized bzip2) produces such files.
		 */
		len = bd->inbufCount - bd->inbufPos;
		memcpy(outbuf, &bd->inbuf[bd->inbufPos], len);
		if (len < 2) {
			if (safe_read(xstate->src_fd, outbuf + len, 2 - len) != 2 - len)
				break;
			len = 2;
		}
		if (*(uint16_t*)outbuf != BZIP2_MAGIC) /* "BZ"? */
			break;
		dealloc_bunzip(bd);
		len -= 2;
	}

 release_mem:
	dealloc_bunzip(bd);
	free(outbuf);

	return i ? i : IF_DESKTOP(total_written) + 0;
}