summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author/dev/humancontroller <devhc@example.com>2017-08-14 14:04:02 +0200
committer/dev/humancontroller <devhc@example.com>2017-08-14 14:04:02 +0200
commit57a3338110978b37baab6f7c45935a1dff5db603 (patch)
treea9b6be3eb4b16c1e8053e8ae64b79cd0b9377181
parenta150f425666146fbdca921ea44838b81889ec9e9 (diff)
apply the security patch for incoming-packet VoIP-data parsing and Huffman decompression
TODO: improve this description
-rw-r--r--src/qcommon/huffman.c29
-rw-r--r--src/qcommon/msg.c43
-rw-r--r--src/qcommon/qcommon.h6
-rw-r--r--src/server/sv_client.c2
4 files changed, 62 insertions, 18 deletions
diff --git a/src/qcommon/huffman.c b/src/qcommon/huffman.c
index aa8ee226..ecec416b 100644
--- a/src/qcommon/huffman.c
+++ b/src/qcommon/huffman.c
@@ -280,9 +280,15 @@ 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) {
+ // overflow
+ *ch = 0;
+ *offset = maxoffset + 1;
+ return;
+ }
if (get_bit(fin)) {
node = node->right;
} else {
@@ -299,11 +305,16 @@ 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) {
+ // overflow
+ bloc = maxoffset + 1;
+ return;
+ }
if (node->right == child) {
add_bit(1, fout);
} else {
@@ -313,22 +324,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;
}
@@ -414,7 +425,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/src/qcommon/msg.c b/src/qcommon/msg.c
index 8258abdd..22347633 100644
--- a/src/qcommon/msg.c
+++ b/src/qcommon/msg.c
@@ -111,9 +111,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;
}
@@ -141,6 +139,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;
@@ -169,6 +172,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);
@@ -178,8 +185,12 @@ 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;
@@ -194,6 +205,11 @@ int MSG_ReadBits( msg_t *msg, int bits ) {
int i, nbits;
// FILE* fp;
+ if ( msg->readcount > msg->cursize ) {
+ // overflowed
+ return 0;
+ }
+
value = 0;
if ( bits < 0 ) {
@@ -204,6 +220,12 @@ int MSG_ReadBits( msg_t *msg, int bits ) {
}
if (msg->oob) {
+ if (msg->readcount + (bits>>3) > msg->cursize) {
+ // overflowed
+ msg->readcount = msg->cursize + 1;
+ return 0;
+ }
+
if(bits==8)
{
value = msg->data[msg->readcount];
@@ -231,6 +253,11 @@ int MSG_ReadBits( msg_t *msg, int bits ) {
nbits = 0;
if (bits&7) {
nbits = bits&7;
+ if (msg->bit + nbits > msg->cursize << 3) {
+ // overflowed
+ msg->readcount = msg->cursize + 1;
+ return 0;
+ }
for(i=0;i<nbits;i++) {
value |= (Huff_getBit(msg->data, &msg->bit)<<i);
}
@@ -239,9 +266,15 @@ 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) {
+ // overflowed
+ msg->readcount = msg->cursize + 1;
+ return 0;
+ }
}
// fclose(fp);
}
diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h
index 5dc5ab0c..f6111c39 100644
--- a/src/qcommon/qcommon.h
+++ b/src/qcommon/qcommon.h
@@ -1165,9 +1165,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 --git a/src/server/sv_client.c b/src/server/sv_client.c
index 126a9d05..f3a0494f 100644
--- a/src/server/sv_client.c
+++ b/src/server/sv_client.c
@@ -1565,7 +1565,7 @@ void SV_UserVoip(client_t *cl, msg_t *msg, qboolean ignoreData)
}
packetsize = MSG_ReadShort(msg);
- if (msg->readcount > msg->cursize)
+ if (msg->readcount + packetsize > msg->cursize)
return; // short/invalid packet, bail.
if (packetsize > sizeof (encoded)) { // overlarge packet?