-
Notifications
You must be signed in to change notification settings - Fork 10
Description
The code that is responsible for reading this data into the "of" variable [1] on line 73. inside lz4D.c ->
--> [1] RET_WHEN_ERR(LZ4_read(pp_src, p_src_limit, 2, &of));
RET_ERR_IF(R_CORRUPT, of==0);
if (ml == 15) {
do {
RET_WHEN_ERR(LZ4_read(pp_src, p_src_limit, 1, &byte));
ml += byte;
} while (byte == 255);
}
--->[2] p_match = (*pp_dst) - of;
---> [3] RET_WHEN_ERR(LZ4_copy(&p_match, p_dst_limit, pp_dst, p_dst_limit, (ml+MIN_ML))); // copy match
computes the p_match by substracting the current address of the pp_dst where the decompressed file should be written from that value.
The size for a 64 bit machine is 0x80000000 and mmap will be used to allocate a special region below the heap.
When the address of pp_dst is substracted from the computed value of "of" to create the p_match variable [2] it will end in a out of
bounds address that is later written to the destination in this code [3].
This will cause the program to segfault because it tries to dereference an invalid pointer later inside LZ4_copy [4].
static int LZ4_copy (uint8_t **pp_src, uint8_t *p_src_limit, uint8_t **pp_dst, uint8_t *p_dst_limit, uint64_t n_bytes) {
RET_ERR_IF(R_SRC_OVERFLOW, (n_bytes > p_src_limit - *pp_src));
RET_ERR_IF(R_DST_OVERFLOW, (n_bytes > p_dst_limit - *pp_dst));
for (; n_bytes>0; n_bytes--) {
--> [4] **pp_dst = **pp_src;
(*pp_src) ++;
(*pp_dst) ++;
}
return R_OK;
}
pp_src is the match variable from above which is computed from substracting the pp_dst variable from the "of" variable,
both of them are known and gives a write what where primitive.
Payload used:
00000000: 0422 4d18 6070 7305 0000 0000 2041 410a ."M.`ps..... AA.
00000010: 0000 0000 ....
73 05 00 00 = 0x00000573 = 1395 bytes -> size of compressed data
Reproduce:
./tinyZZZ -d --lz4 crash_lz4.lz4 test.txt