1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-26 21:57:41 +03:00

lzxpress: add bounds checking to lzxpress_decompress()

lzxpress_decompress() would wander past the end of the array in
numerous locations.

Credit to OSS-Fuzz.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14190
REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=19382
REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20083
REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=22485
REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=22667

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>

Autobuild-User(master): Douglas Bagnall <dbagnall@samba.org>
Autobuild-Date(master): Sun Aug  9 00:30:26 UTC 2020 on sn-devel-184
This commit is contained in:
Stefan Metzmacher 2019-11-07 10:03:36 +01:00 committed by Douglas Bagnall
parent f50987df03
commit a97c78fb22

View File

@ -252,8 +252,24 @@ ssize_t lzxpress_decompress(const uint8_t *input,
offset = 0;
nibble_index = 0;
#define __CHECK_BYTES(__size, __index, __needed) do { \
if (unlikely(__index >= __size)) { \
return -1; \
} else { \
uint32_t __avail = __size - __index; \
if (unlikely(__needed > __avail)) { \
return -1; \
} \
} \
} while(0)
#define CHECK_INPUT_BYTES(__needed) \
__CHECK_BYTES(input_size, input_index, __needed)
#define CHECK_OUTPUT_BYTES(__needed) \
__CHECK_BYTES(max_output_size, output_index, __needed)
do {
if (indicator_bit == 0) {
CHECK_INPUT_BYTES(4);
indicator = PULL_LE_UINT32(input, input_index);
input_index += sizeof(uint32_t);
indicator_bit = 32;
@ -266,10 +282,13 @@ ssize_t lzxpress_decompress(const uint8_t *input,
* check whether the 4th bit of the value in indicator is set
*/
if (((indicator >> indicator_bit) & 1) == 0) {
CHECK_INPUT_BYTES(1);
CHECK_OUTPUT_BYTES(1);
output[output_index] = input[input_index];
input_index += sizeof(uint8_t);
output_index += sizeof(uint8_t);
} else {
CHECK_INPUT_BYTES(2);
length = PULL_LE_UINT16(input, input_index);
input_index += sizeof(uint16_t);
offset = length / 8;
@ -277,6 +296,7 @@ ssize_t lzxpress_decompress(const uint8_t *input,
if (length == 7) {
if (nibble_index == 0) {
CHECK_INPUT_BYTES(1);
nibble_index = input_index;
length = input[input_index] % 16;
input_index += sizeof(uint8_t);
@ -286,9 +306,11 @@ ssize_t lzxpress_decompress(const uint8_t *input,
}
if (length == 15) {
CHECK_INPUT_BYTES(1);
length = input[input_index];
input_index += sizeof(uint8_t);
if (length == 255) {
CHECK_INPUT_BYTES(2);
length = PULL_LE_UINT16(input, input_index);
input_index += sizeof(uint16_t);
length -= (15 + 7);
@ -299,10 +321,16 @@ ssize_t lzxpress_decompress(const uint8_t *input,
}
length += 3;
if (length == 0) {
return -1;
}
if (offset >= output_index) {
return -1;
}
CHECK_OUTPUT_BYTES(length);
do {
if ((output_index >= max_output_size) || ((offset + 1) > output_index)) break;
output[output_index] = output[output_index - offset - 1];
output_index += sizeof(uint8_t);