On Sat, 12 Aug 2017 at 15:33:34 +0200, Moritz Mühlenhoff wrote: > Feel free to simply upload an untested package for jessie-security, > I'm flying back on Sunday evening, I can run tests on jessie sometime > next week.
I was able to do a smoke-test on a virtual machine (llvmpipe is much better than I remembered, apparently) so there is now a briefly tested jessie-security version in the queue. Any additional testing would likely be useful - the patch is to netcode, so hosting or joining an openarena server is an appropriate test. See attached debdiff. S
diffstat for ioquake3-1.36+u20140802+gca9eebb ioquake3-1.36+u20140802+gca9eebb changelog | 10 patches/security/Fix-improve-buffer-overflow-in-MSG_ReadBits-MSG_WriteBits.patch | 213 ++++++++++ patches/series | 1 3 files changed, 224 insertions(+) diff -Nru ioquake3-1.36+u20140802+gca9eebb/debian/changelog ioquake3-1.36+u20140802+gca9eebb/debian/changelog --- ioquake3-1.36+u20140802+gca9eebb/debian/changelog 2017-03-14 18:29:48.000000000 -0400 +++ ioquake3-1.36+u20140802+gca9eebb/debian/changelog 2017-08-12 10:15:49.000000000 -0400 @@ -1,3 +1,13 @@ +ioquake3 (1.36+u20140802+gca9eebb-2+deb8u2) jessie-security; urgency=medium + + * Add patch from upstream: + + Address read buffer overflow in + MSG_ReadBits (CVE-2017-11721) (Closes: #870725) + + Check buffer boundary exactly in MSG_WriteBits, instead of + potentially failing with a few bytes still available + + -- Simon McVittie <s...@debian.org> Sat, 12 Aug 2017 10:15:49 -0400 + ioquake3 (1.36+u20140802+gca9eebb-2+deb8u1) jessie-security; urgency=high * d/gbp.conf: switch branch to debian/jessie diff -Nru ioquake3-1.36+u20140802+gca9eebb/debian/patches/security/Fix-improve-buffer-overflow-in-MSG_ReadBits-MSG_WriteBits.patch ioquake3-1.36+u20140802+gca9eebb/debian/patches/security/Fix-improve-buffer-overflow-in-MSG_ReadBits-MSG_WriteBits.patch --- ioquake3-1.36+u20140802+gca9eebb/debian/patches/security/Fix-improve-buffer-overflow-in-MSG_ReadBits-MSG_WriteBits.patch 1969-12-31 19:00:00.000000000 -0500 +++ ioquake3-1.36+u20140802+gca9eebb/debian/patches/security/Fix-improve-buffer-overflow-in-MSG_ReadBits-MSG_WriteBits.patch 2017-08-12 10:15:49.000000000 -0400 @@ -0,0 +1,213 @@ +From: Zack Middleton <z...@cloemail.com> +Date: Wed, 2 Aug 2017 14:55:10 -0500 +Subject: 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. + +Origin: upstream, commit:d2b1d124d4055c2fcbe5126863487c52fd58cca1 +Bug-CVE: CVE-2017-11721 +Bug-Debian: https://bugs.debian.org/870725 +--- + code/qcommon/huffman.c | 27 ++++++++++++++++++--------- + code/qcommon/msg.c | 40 +++++++++++++++++++++++++++++++++++----- + code/qcommon/qcommon.h | 6 +++--- + 3 files changed, 56 insertions(+), 17 deletions(-) + +diff --git a/code/qcommon/huffman.c b/code/qcommon/huffman.c +index c1b9f24..1f42498 100644 +--- a/code/qcommon/huffman.c ++++ b/code/qcommon/huffman.c +@@ -279,9 +279,14 @@ int Huff_Receive (node_t *node, int *ch, byte *fin) { + } + + /* Get a symbol */ +-void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) { ++void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset, int maxoffset) { + bloc = *offset; + while (node && node->symbol == INTERNAL_NODE) { ++ if (bloc >= maxoffset) { ++ *ch = 0; ++ *offset = maxoffset + 1; ++ return; ++ } + if (get_bit(fin)) { + node = node->right; + } else { +@@ -298,11 +303,15 @@ void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) { + } + + /* Send the prefix code for this node */ +-static void send(node_t *node, node_t *child, byte *fout) { ++static void send(node_t *node, node_t *child, byte *fout, int maxoffset) { + if (node->parent) { +- send(node->parent, node, fout); ++ send(node->parent, node, fout, maxoffset); + } + if (child) { ++ if (bloc >= maxoffset) { ++ bloc = maxoffset + 1; ++ return; ++ } + if (node->right == child) { + add_bit(1, fout); + } else { +@@ -312,22 +321,22 @@ static void send(node_t *node, node_t *child, byte *fout) { + } + + /* Send a symbol */ +-void Huff_transmit (huff_t *huff, int ch, byte *fout) { ++void Huff_transmit (huff_t *huff, int ch, byte *fout, int maxoffset) { + int i; + if (huff->loc[ch] == NULL) { + /* node_t hasn't been transmitted, send a NYT, then the symbol */ +- Huff_transmit(huff, NYT, fout); ++ Huff_transmit(huff, NYT, fout, maxoffset); + for (i = 7; i >= 0; i--) { + add_bit((char)((ch >> i) & 0x1), fout); + } + } else { +- send(huff->loc[ch], NULL, fout); ++ send(huff->loc[ch], NULL, fout, maxoffset); + } + } + +-void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset) { ++void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset, int maxoffset) { + bloc = *offset; +- send(huff->loc[ch], NULL, fout); ++ send(huff->loc[ch], NULL, fout, maxoffset); + *offset = bloc; + } + +@@ -413,7 +422,7 @@ void Huff_Compress(msg_t *mbuf, int offset) { + + for (i=0; i<size; i++ ) { + ch = buffer[i]; +- Huff_transmit(&huff, ch, seq); /* Transmit symbol */ ++ Huff_transmit(&huff, ch, seq, size<<3); /* Transmit symbol */ + Huff_addRef(&huff, (byte)ch); /* Do update */ + } + +diff --git a/code/qcommon/msg.c b/code/qcommon/msg.c +index 5623b9b..ac7a954 100644 +--- a/code/qcommon/msg.c ++++ b/code/qcommon/msg.c +@@ -110,9 +110,7 @@ void MSG_WriteBits( msg_t *msg, int value, int bits ) { + + oldsize += bits; + +- // this isn't an exact overflow check, but close enough +- if ( msg->maxsize - msg->cursize < 4 ) { +- msg->overflowed = qtrue; ++ if ( msg->overflowed ) { + return; + } + +@@ -140,6 +138,11 @@ void MSG_WriteBits( msg_t *msg, int value, int bits ) { + bits = -bits; + } + if (msg->oob) { ++ if ( msg->cursize + ( bits >> 3 ) > msg->maxsize ) { ++ msg->overflowed = qtrue; ++ return; ++ } ++ + if(bits==8) + { + msg->data[msg->cursize] = value; +@@ -168,6 +171,10 @@ void MSG_WriteBits( msg_t *msg, int value, int bits ) { + if (bits&7) { + int nbits; + nbits = bits&7; ++ if ( msg->bit + nbits > msg->maxsize << 3 ) { ++ msg->overflowed = qtrue; ++ return; ++ } + for(i=0;i<nbits;i++) { + Huff_putBit((value&1), msg->data, &msg->bit); + value = (value>>1); +@@ -177,8 +184,13 @@ void MSG_WriteBits( msg_t *msg, int value, int bits ) { + if (bits) { + for(i=0;i<bits;i+=8) { + // fwrite(bp, 1, 1, fp); +- Huff_offsetTransmit (&msgHuff.compressor, (value&0xff), msg->data, &msg->bit); ++ Huff_offsetTransmit( &msgHuff.compressor, (value & 0xff), msg->data, &msg->bit, msg->maxsize << 3 ); + value = (value>>8); ++ ++ if ( msg->bit > msg->maxsize << 3 ) { ++ msg->overflowed = qtrue; ++ return; ++ } + } + } + msg->cursize = (msg->bit>>3)+1; +@@ -193,6 +205,10 @@ int MSG_ReadBits( msg_t *msg, int bits ) { + int i, nbits; + // FILE* fp; + ++ if ( msg->readcount > msg->cursize ) { ++ return 0; ++ } ++ + value = 0; + + if ( bits < 0 ) { +@@ -203,6 +219,11 @@ int MSG_ReadBits( msg_t *msg, int bits ) { + } + + if (msg->oob) { ++ if (msg->readcount + (bits>>3) > msg->cursize) { ++ msg->readcount = msg->cursize + 1; ++ return 0; ++ } ++ + if(bits==8) + { + value = msg->data[msg->readcount]; +@@ -230,6 +251,10 @@ int MSG_ReadBits( msg_t *msg, int bits ) { + nbits = 0; + if (bits&7) { + nbits = bits&7; ++ if (msg->bit + nbits > msg->cursize << 3) { ++ msg->readcount = msg->cursize + 1; ++ return 0; ++ } + for(i=0;i<nbits;i++) { + value |= (Huff_getBit(msg->data, &msg->bit)<<i); + } +@@ -238,9 +263,14 @@ int MSG_ReadBits( msg_t *msg, int bits ) { + if (bits) { + // fp = fopen("c:\\netchan.bin", "a"); + for(i=0;i<bits;i+=8) { +- Huff_offsetReceive (msgHuff.decompressor.tree, &get, msg->data, &msg->bit); ++ Huff_offsetReceive (msgHuff.decompressor.tree, &get, msg->data, &msg->bit, msg->cursize<<3); + // fwrite(&get, 1, 1, fp); + value |= (get<<(i+nbits)); ++ ++ if (msg->bit > msg->cursize<<3) { ++ msg->readcount = msg->cursize + 1; ++ return 0; ++ } + } + // fclose(fp); + } +diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h +index d0cc9d6..6b86329 100644 +--- a/code/qcommon/qcommon.h ++++ b/code/qcommon/qcommon.h +@@ -1179,9 +1179,9 @@ void Huff_Decompress(msg_t *buf, int offset); + void Huff_Init(huffman_t *huff); + void Huff_addRef(huff_t* huff, byte ch); + int Huff_Receive (node_t *node, int *ch, byte *fin); +-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); ++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); + void Huff_putBit( int bit, byte *fout, int *offset); + int Huff_getBit( byte *fout, int *offset); + diff -Nru ioquake3-1.36+u20140802+gca9eebb/debian/patches/series ioquake3-1.36+u20140802+gca9eebb/debian/patches/series --- ioquake3-1.36+u20140802+gca9eebb/debian/patches/series 2017-03-14 18:29:48.000000000 -0400 +++ ioquake3-1.36+u20140802+gca9eebb/debian/patches/series 2017-08-12 10:15:49.000000000 -0400 @@ -6,3 +6,4 @@ security/Don-t-load-.pk3s-as-.dlls-and-don-t-load-user-config-file.patch security/Don-t-open-.pk3-files-as-OpenAL-drivers.patch security/Merge-some-file-writing-extension-checks-from-OpenJK.patch +security/Fix-improve-buffer-overflow-in-MSG_ReadBits-MSG_WriteBits.patch