CVE-2017-11721 (C, published 2017-08-03T08:29Z)
Description: value: Buffer overflow in ioquake3 before 2017-08-02 allows remote attackers to cause a denial of service (application crash) or possibly have unspecified other impact via a crafted packet.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-119 \u2014 Improper Restriction of Operations within the Bounds of a Memory Buffer
The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
Repository: https://github.com/ioquake/ioq3
Files changed:
code/qcommon/huffman.c
code/qcommon/msg.c
code/qcommon/qcommon.h
Commit message: Fix/improve buffer overflow in MSG_ReadBits/MSG_WriteBits

Prevent reading past end of message in MSG_ReadBits. If read past
end of msg->data buffer (16348 bytes) the engine could SEGFAULT.
Make MSG_WriteBits use an exact buffer overflow check instead of
possibly failing with a few bytes left.


Vulnerable code:
void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) {
static void send(node_t *node, node_t *child, byte *fout) {
		send(node->parent, node, fout);
void Huff_transmit (huff_t *huff, int ch, byte *fout) {
		Huff_transmit(huff, NYT, fout);
		send(huff->loc[ch], NULL, fout);
void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset) {
	send(huff->loc[ch], NULL, fout);
		Huff_transmit(&huff, ch, seq);						/* Transmit symbol */
	// this isn't an exact overflow check, but close enough
	if ( msg->maxsize - msg->cursize < 4 ) {
		msg->overflowed = qtrue;
				Huff_offsetTransmit( &msgHuff.compressor, (value & 0xff), msg->data, &msg->bit );
				Huff_offsetReceive (msgHuff.decompressor.tree, &get, msg->data, &msg->bit);
void	Huff_transmit (huff_t *huff, int ch, byte *fout);
void	Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset);
void	Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset);

Fixed code:
void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset, int maxoffset) {
		if (bloc >= maxoffset) {
			*ch = 0;
			*offset = maxoffset + 1;
			return;
		}
static void send(node_t *node, node_t *child, byte *fout, int maxoffset) {
		send(node->parent, node, fout, maxoffset);
		if (bloc >= maxoffset) {
			bloc = maxoffset + 1;
			return;
		}
void Huff_transmit (huff_t *huff, int ch, byte *fout, int maxoffset) {
		Huff_transmit(huff, NYT, fout, maxoffset);
		send(huff->loc[ch], NULL, fout, maxoffset);
void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset, int maxoffset) {
	send(huff->loc[ch], NULL, fout, maxoffset);
		Huff_transmit(&huff, ch, seq, size<<3);						/* Transmit symbol */
	if ( msg->overflowed ) {
		if ( msg->cursize + ( bits >> 3 ) > msg->maxsize ) {
			msg->overflowed = qtrue;
			return;
		}

			if ( msg->bit + nbits > msg->maxsize << 3 ) {
				msg->overflowed = qtrue;
				return;
			}
				Huff_offsetTransmit( &msgHuff.compressor, (value & 0xff), msg->data, &msg->bit, msg->maxsize << 3 );

				if ( msg->bit > msg->maxsize << 3 ) {
					msg->overflowed = qtrue;
					return;
				}
	if ( msg->readcount > msg->cursize ) {
		return 0;
	}

		if (msg->readcount + (bits>>3) > msg->cursize) {
			msg->readcount = msg->cursize + 1;
			return 0;
		}

			if (msg->bit + nbits > msg->cursize << 3) {
				msg->readcount = msg->cursize + 1;
				return 0;
			}
				Huff_offsetReceive (msgHuff.decompressor.tree, &get, msg->data, &msg->bit, msg->cursize<<3);

				if (msg->bit > msg->cursize<<3) {
					msg->readcount = msg->cursize + 1;
					return 0;
				}
void	Huff_transmit (huff_t *huff, int ch, byte *fout, int maxoffset);
void	Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset, int maxoffset);
void	Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset, int maxoffset);