mirror of
https://github.com/google/brotli.git
synced 2026-07-08 17:56:58 +00:00
BrotliDecoderDecompress() crashed if inbuf is part of mmaped file #231
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @torappinfo on GitHub (May 30, 2018).
If data points to mmaped file, the following crashed:
BrotliDecoderDecompress(len,data+offset,&decoded_size,inBuffer);
Adding extra copy fixed the issue:
memcpy(testbuf,data+offset,len);
BrotliDecoderDecompress(len,testbuf,&decoded_size,inBuffer);
Note: in the first case, data+offset is not aligned. Is alignment needed for BrotliDecoderDecompress()?
@eustas commented on GitHub (May 30, 2018):
What is the OS / CPU?
Actually, decoder takes care of alignment:
f9b8c02673/c/dec/bit_reader.c (L37)Going to investigate the problem soon.
@torappinfo commented on GitHub (Jun 2, 2018):
Linux 4.16.6-1-ARCH #1 SMP PREEMPT Mon Apr 30 12:30:03 UTC 2018 x86_64 GNU/Linux
Name : brotli
Version : 1.0.4-1
Description : Brotli compression library
Architecture : x86_64
@torappinfo commented on GitHub (Jun 2, 2018):
If alignment is helpful for performance, this bug needs not to be fixed. We just need to document it.
@eustas commented on GitHub (Jun 5, 2018):
Can't reproduce.
If you like, I can share modified
research/brotli_decoder.cwhich reads from mmapped file from given offset, so you could check if it crashes as well.@jhudsoncedaron commented on GitHub (Jun 15, 2018):
I can give a clue how to try to reproduce this. I think the code tries to read past the end of the buffer and ignores the result. This will crash if the buffer is butt-up against the end of a page and the next page isn't allocated. This is easy to set up with a mmapped file and hard otherwise.
@eustas commented on GitHub (Jun 19, 2018):
I've published branch with demo mmaped file decoder: https://github.com/google/brotli/tree/mmap-read
Could you provide file and offeset that would crash it, please.
@torappinfo commented on GitHub (Jul 27, 2018):
I'v compressed every 64k block of a large file with brotli and then concatenate them together. The compressed file has a header to provide offsets for each blocks.
The header format is as follows:
Here nBlocks=(len_decompressed-1)/64k + 1.
and the offset for the first block is zero, and second offset is the length of compressed first block etc.
In this format, BrotliDecoderDecompress() crashed for the very first block for my testing data.
The first 1MB of compressed file is attached here.
test.log
@torappinfo commented on GitHub (Jul 27, 2018):
The full compressed file (15MB) is here: (ahd.dict.tbr)
https://github.com/torappinfo/century-dictionary/releases/tag/v1
@mraszyk commented on GitHub (Jul 30, 2018):
I managed to successfully decompress the test file, i.e., I was not able to reproduce the crash.
Moreover, the uncompressed file (ahd.dict) has SHA256 hash
2f4197eab677a9344f3b4879fc5a65dcabb4b0b3df1497d50580936efde9a24b
which is different from century.md with SHA256 hash
aac17eb82496ba106cb2161da8016f3580ba23593e224b71fadb2a99d9005416
@torappinfo commented on GitHub (Jul 31, 2018):
The file is not century.md. I just put there as a test file, so the SHA256 is different.
When you decompressed the test file, did you mmap the whole test file (at offset 0)
and use BrotliDecoderDecompress(len,data+offset,&decoded_size,inBuffer) directly on it?
If you read the test file to a buffer, the data is probably properly aligned and nothing will be wrong.
But if you mmap the whole test file (including header) and directly use BrotliDecoderDecompress() on the address space. It crashed me every time.
My latest test is using :
Linux 4.17.2-1-ARCH #1 SMP PREEMPT UTC 2018 x86_64 GNU/Linux
Name : brotli
Version : 1.0.5-1
Description : Brotli compression library
Architecture : x86_64
@jhudsoncedaron commented on GitHub (Aug 3, 2018):
@torappinfo : I'd recommending extracting out and uploading the two dozen lines required to set this up. I only ever got this with corrupted streams...
@torappinfo commented on GitHub (Aug 6, 2018):
@mraszyk, Could you give your code to jhudsoncedaron, as you have already successfully extracted streams. The only thing to make sure segment fault is not to read compressed stream to buffer.
@mraszyk commented on GitHub (Aug 6, 2018):
I used the following code to decompress the test file ahd.dict.tbr and successfully obtained the uncompressed file ahd.dict also on Arch Linux:
https://drive.google.com/file/d/0ByXI7DhQRNE-a2t4bUJKTE54emR6V0pZMFV2eklpLTdlS0JF/view?usp=sharing
Files (with SHA256 hashes):
adbe6fa730efddbcf62a75134ece9ab8a50abf4465ed38af6de7898b11f07061 ahd.dict.tbr
2f4197eab677a9344f3b4879fc5a65dcabb4b0b3df1497d50580936efde9a24b ahd.dict
System: Linux arch 4.17.11-arch1 #1 SMP PREEMPT x86_64 GNU/Linux
Brotli version: 1.0.5
Please check the attached code if it crashes, and if it doesn't, please provide your code which does crash on decompressing ahd.dict.tbr.
@jhudsoncedaron commented on GitHub (Aug 6, 2018):
@torappinfo : What are your FS and OS page sizes? (The FS page size is the size of an empty directory assuming you aren't using an exotic filesystem.) Your processor supports large pages but I can't tell if you're using them.
@torappinfo commented on GitHub (Aug 6, 2018):
My FS and OS page sizes are both 4KB.
@torappinfo commented on GitHub (Aug 6, 2018):
mraszyk's code runs successfully on my machine.
@jhudsoncedaron commented on GitHub (Aug 6, 2018):
I was expecting that. Your code please.
@torappinfo commented on GitHub (Aug 8, 2018):
The segment fault may be inside my code, since simply declaring a global variable fixed the crash:
unsigned char ub1 testbuf[64*1024];
Even though the coredump stack is as follows:
#0 0x00007ffff782bb5f in raise () from /usr/lib/libc.so.6
#1 0x00007ffff7816452 in abort () from /usr/lib/libc.so.6
#2 0x00007ffff786e658 in __libc_message () from /usr/lib/libc.so.6
#3 0x00007ffff7874f6a in malloc_printerr () from /usr/lib/libc.so.6
#4 0x00007ffff78754c4 in munmap_chunk () from /usr/lib/libc.so.6
#5 0x00007ffff7b44a42 in ?? () from /usr/lib/libbrotlidec.so.1
#6 0x00007ffff7b43548 in BrotliDecoderDecompressStream () from /usr/lib/libbrotlidec.so.1
#7 0x00007ffff7b43bac in BrotliDecoderDecompress () from /usr/lib/libbrotlidec.so.1
@jhudsoncedaron commented on GitHub (Aug 8, 2018):
You have heap corruption. It could be anywhere in your code.
@torappinfo commented on GitHub (Aug 28, 2018):
Very weird bug. I decompressed the first block (BrotliDecoderDecompress) to the first cache of the following cache array:
struct dictCACHE {
ub1 cache[65536][DICT_CACHE_SIZE];
//ub1 testbuf[65536]; //this line fixed segment fault
ub4 chunk[DICT_CACHE_SIZE];//index for 64k chunks, (ub4)-1 means invalid
ub4 stamp[DICT_CACHE_SIZE];
};
Whatever DICT_CACHE_SIZE is, without testbuf defined, BrotliDecoderDecompress segment faulted for sure. And even if the testbuf is defined, it is never write-accessed in run (I made the testbuf page read-only, and it never crashed.)
The Valgrind error is as follows:
==593== Memcheck, a memory error detector
==593== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==593== Using Valgrind-3.14.0.GIT and LibVEX; rerun with -h for copyright info
==593== Command: ./tdict_tbr /home/fengcao/dict/ahd hello
==593==
==593== Invalid write of size 8
==593== at 0x483C02B: memcpy@GLIBC_2.2.5 (vg_replace_strmem.c:1033)
==593== by 0x4ACB489: ??? (in /usr/lib/libbrotlidec.so.1.0.5)
==593== by 0x4ACFFBA: BrotliDecoderDecompressStream (in /usr/lib/libbrotlidec.so.1.0.5)
==593== by 0x4AD0BAB: BrotliDecoderDecompress (in /usr/lib/libbrotlidec.so.1.0.5)
==593== by 0x10A98C: content (getcontent_tbr.c:122)
==593== by 0x10B6D7: GetContent (tdict_le.c:187)
==593== by 0x10D3FE: tdict_main (tdictmain.c:261)
==593== by 0x10AB35: main (getcontent_tbr.c:156)
==593== Address 0x121000 is not stack'd, malloc'd or (recently) free'd
==593==
==593==
==593== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==593== Access not within mapped region at address 0x121000
==593== at 0x483C02B: memcpy@GLIBC_2.2.5 (vg_replace_strmem.c:1033)
==593== by 0x4ACB489: ??? (in /usr/lib/libbrotlidec.so.1.0.5)
==593== by 0x4ACFFBA: BrotliDecoderDecompressStream (in /usr/lib/libbrotlidec.so.1.0.5)
==593== by 0x4AD0BAB: BrotliDecoderDecompress (in /usr/lib/libbrotlidec.so.1.0.5)
==593== by 0x10A98C: content (getcontent_tbr.c:122)
==593== by 0x10B6D7: GetContent (tdict_le.c:187)
==593== by 0x10D3FE: tdict_main (tdictmain.c:261)
==593== by 0x10AB35: main (getcontent_tbr.c:156)
==593== If you believe this happened as a result of a stack
==593== overflow in your program's main thread (unlikely but
==593== possible), you can try to increase the size of the
==593== main thread stack using the --main-stacksize= flag.
==593== The main thread stack size used in this run was 8388608.
==593==
==593== HEAP SUMMARY:
==593== in use at exit: 110,457 bytes in 8 blocks
==593== total heap usage: 8 allocs, 0 frees, 110,457 bytes allocated
==593==
==593== LEAK SUMMARY:
==593== definitely lost: 0 bytes in 0 blocks
==593== indirectly lost: 0 bytes in 0 blocks
==593== possibly lost: 0 bytes in 0 blocks
==593== still reachable: 110,457 bytes in 8 blocks
==593== suppressed: 0 bytes in 0 blocks
==593== Rerun with --leak-check=full to see details of leaked memory
==593==
==593== For counts of detected and suppressed errors, rerun with: -v
==593== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)