ref: a214a46731b1636f8f78582885294145989d60d1
parent: fc96bb9cc7c59f99b03f8d1225cc708451b8bf45
author: Timothy B. Terriberry <tterribe@xiph.org>
date: Wed Jul 24 07:36:08 EDT 2024
Fix overflow and OOB read for large ext lengths. With an 8+ MB packet it is possible to craft an extension length that would overflow, bypassing the checks to ensure the extension data remains inside the packet. This patch fixes that and adds a test for it.
--- a/src/extensions.c
+++ b/src/extensions.c
@@ -69,24 +69,23 @@
return 0;
} else {opus_int32 bytes=0;
+ opus_int32 lacing;
*header_size = 1;
do {(*data)++;
len--;
- if (len == 0)
+ if (len < 1)
return -1;
- bytes += **data;
+ lacing = **data;
+ bytes += lacing;
(*header_size)++;
- } while (**data == 255);
+ len -= lacing;
+ } while (lacing == 255);
+ if (len < 1)
+ return -1;
(*data)++;
len--;
- if (bytes <= len)
- {- len -= bytes;
- *data += bytes;
- } else {- return -1;
- }
+ *data += bytes;
return len;
}
}
--- a/tests/test_opus_extensions.c
+++ b/tests/test_opus_extensions.c
@@ -303,6 +303,20 @@
len = opus_packet_extensions_generate(packet, sizeof(packet), ext, 4, 0);
result = opus_packet_extensions_parse(packet, len, ext_out, &nb_ext);
expect_true(result == OPUS_BUFFER_TOO_SMALL, "expected OPUS_BUFFER_TOO_SMALL");
+
+ /* overflow for long extension length */
+ {+ /* about 8 MB */
+#define LENSIZE ((1U<<31)/255 + 1)
+ unsigned char *buf = malloc(LENSIZE+1);
+ len = LENSIZE+1;
+ buf[0] = 33<<1 | 1;
+ memset(buf + 1, 0xFF, LENSIZE - 1);
+ buf[LENSIZE] = 0xFE;
+ result = opus_packet_extensions_parse(buf, len, ext_out, &nb_ext);
+ expect_true(result == OPUS_INVALID_PACKET, "expected OPUS_INVALID_PACKET");
+ free(buf);
+ }
}
#define NB_RANDOM_EXTENSIONS 100000000
--
⑨