facebook / zstd

Zstandard - Fast real-time compression algorithm
http://www.zstd.net
Other
23.2k stars 2.06k forks source link

SIGILL in ZSTD_compressContinue_internal() #749

Closed geeknik closed 7 years ago

geeknik commented 7 years ago

After following the instructions here I compiled zstd with clang-5 and UBSan on Debian 9 x64 and started fuzzing with stream_round_trip. This error is the result:

./stream_round_trip ./crash-0b4920ed8d4e81b93b613e3938ff593a5e0bcd2a
INFO: Seed: 2370722290
INFO: Loaded 1 modules (11932 guards): [0x81b660, 0x8270d0),
./stream_round_trip: Running 1 inputs 1 time(s) each.
Running: ./crash-0b4920ed8d4e81b93b613e3938ff593a5e0bcd2a
==18592== ERROR: libFuzzer: deadly signal
    #0 0x4c6e37 in __sanitizer_print_stack_trace (/root/zstd/tests/fuzz/stream_round_trip+0x4c6e37)
    #1 0x5bd471 in fuzzer::Fuzzer::CrashCallback() /root/zstd/tests/fuzz/./Fuzzer/FuzzerLoop.cpp:195:5
    #2 0x5bd43d in fuzzer::Fuzzer::StaticCrashSignalCallback() /root/zstd/tests/fuzz/./Fuzzer/FuzzerLoop.cpp:179:6
    #3 0x7f837fe3f0bf  (/lib/x86_64-linux-gnu/libpthread.so.0+0x110bf)
    #4 0x53e091 in ZSTD_compressContinue_internal /root/zstd/tests/fuzz/../../lib/compress/zstd_compress.c:2978:20
    #5 0x5407ea in ZSTD_compressEnd /root/zstd/tests/fuzz/../../lib/compress/zstd_compress.c:3310:26
    #6 0x546e04 in ZSTD_compressStream_generic /root/zstd/tests/fuzz/../../lib/compress/zstd_compress.c:3809:38
    #7 0x54850d in ZSTD_endStream /root/zstd/tests/fuzz/../../lib/compress/zstd_compress.c:4018:5
    #8 0x5b218e in compress /root/zstd/tests/fuzz/stream_round_trip.c:80:30
    #9 0x5b218e in LLVMFuzzerTestOneInput /root/zstd/tests/fuzz/stream_round_trip.c:140
    #10 0x5be2b4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /root/zstd/tests/fuzz/./Fuzzer/FuzzerLoop.cpp:460:13
    #11 0x5be523 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long) /root/zstd/tests/fuzz/./Fuzzer/FuzzerLoop.cpp:399:3
    #12 0x5b2ce1 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /root/zstd/tests/fuzz/./Fuzzer/FuzzerDriver.cpp:268:6
    #13 0x5b6bf4 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /root/zstd/tests/fuzz/./Fuzzer/FuzzerDriver.cpp:683:9
    #14 0x5b2a50 in main /root/zstd/tests/fuzz/./Fuzzer/FuzzerMain.cpp:20:10
    #15 0x7f837f48c2b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0)
    #16 0x41f2f9 in _start (/root/zstd/tests/fuzz/stream_round_trip+0x41f2f9)

NOTE: libFuzzer has rudimentary signal handlers.
      Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
Thread 1 "stream_round_tr" received signal SIGILL, Illegal instruction.
0x000000000053e092 in ZSTD_compressContinue_internal
 (cctx=<optimized out>, dst=0x6160000006e8, dstCapacity=384, src=0x0, srcSize=<optimized out>, frame=1, lastFrameChunk=<optimized out>) at ../../lib/compress/zstd_compress.c:2978
2978            cctx->base -= delta;
(gdb) bt
#0  0x000000000053e092 in ZSTD_compressContinue_internal (cctx=<optimized out>, dst=0x6160000006e8, dstCapacity=384, src=0x0, srcSize=<optimized out>, frame=1, lastFrameChunk=<optimized out>) at ../../lib/compress/zstd_compress.c:2978
#1  0x00000000005407eb in ZSTD_compressEnd (cctx=0x617000000080, dst=0x6160000006e2, dstCapacity=390, src=0x10007fff7e00, srcSize=2415882239) at ../../lib/compress/zstd_compress.c:3310
#2  0x0000000000546e05 in ZSTD_compressStream_generic (zcs=<optimized out>, output=<optimized out>, input=<optimized out>, flushMode=<optimized out>) at ../../lib/compress/zstd_compress.c:3809
#3  0x000000000054850e in ZSTD_endStream (zcs=0x617000000080, output=0x7fffffffc800) at ../../lib/compress/zstd_compress.c:4018
#4  0x00000000005b218f in compress (dst=0x6160000006e2 "(\265", <incomplete sequence \375>, capacity=486, src=<optimized out>, srcSize=6) at stream_round_trip.c:80
#5  LLVMFuzzerTestOneInput (src=<optimized out>, size=<optimized out>) at stream_round_trip.c:140
#6  0x00000000005be2b5 in fuzzer::Fuzzer::ExecuteCallback (this=0x614000000040, Data=0x611000000040 "(\265/\375d\a\016e*", Size=229) at ./Fuzzer/FuzzerLoop.cpp:460
#7  0x00000000005be524 in fuzzer::Fuzzer::RunOne (this=0x614000000040, Data=0x611000000040 "(\265/\375d\a\016e*", Size=17594333494784) at ./Fuzzer/FuzzerLoop.cpp:399
#8  0x00000000005b2ce2 in fuzzer::RunOneTest (F=0x614000000040, InputFilePath=0x604000000110 "crash-0b4920ed8d4e81b93b613e3938ff593a5e0bcd2a", MaxLen=<optimized out>) at ./Fuzzer/FuzzerDriver.cpp:268
#9  0x00000000005b6bf5 in fuzzer::FuzzerDriver (argc=<optimized out>, argv=<optimized out>, Callback=0x5b1c80 <LLVMFuzzerTestOneInput>) at ./Fuzzer/FuzzerDriver.cpp:683
#10 0x00000000005b2a51 in main (argc=2, argv=0x7fffffffe278) at ./Fuzzer/FuzzerMain.cpp:20
(gdb) list
2973            /* not contiguous */
2974            ptrdiff_t const delta = cctx->nextSrc - ip;
2975            cctx->lowLimit = cctx->dictLimit;
2976            cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2977            cctx->dictBase = cctx->base;
2978            cctx->base -= delta;
2979            cctx->nextToUpdate = cctx->dictLimit;
2980            if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit;   /* too small extDict */
2981        }
2982
(gdb) i r
rax            0x10007fff7600   17594333492736
rbx            0x100    256
rcx            0x10007fff7e00   17594333494784
rdx            0x10007fff7e00   17594333494784
rsi            0x0      0
rdi            0x0      0
rbp            0x7fffffffc4d0   0x7fffffffc4d0
rsp            0x7fffffffc370   0x7fffffffc370
r8             0x8fff6fff       2415882239
r9             0x0      0
r10            0x100    256
r11            0x617000000088   107133664231560
r12            0x61700000009c   107133664231580
r13            0xc2e00000013    13391708028947
r14            0xc2e00000010    13391708028944
r15            0x0      0
rip            0x53e092 0x53e092 <ZSTD_compressContinue_internal+5746>
eflags         0x10206  [ PF IF RF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0

crash-0b4920ed8d4e81b93b613e3938ff593a5e0bcd2a.gz

Cyan4973 commented 7 years ago

cc @terrelln

terrelln commented 7 years ago

I'm not sure why the SIGILL occurs, but on clang-5 you need to need to compile with -fno-sanitize=pointer-overflow, because the computations with cctx->base can underflow. I'll add it to the documentation.

geeknik commented 7 years ago

When I build with -O2 -fno-omit-frame-pointer -g -fsanitize=address,undefined -fsanitize-coverage=trace-pc-guard -fno-sanitize=pointer-overflow I still see this happening:

 ./stream_round_trip crash-65b151ca798cc7e33dbbc059d767e6570017c668
INFO: Seed: 1847299958
INFO: Loaded 1 modules (11932 guards): [0x81b660, 0x8270d0),
./stream_round_trip: Running 1 inputs 1 time(s) each.
Running: crash-65b151ca798cc7e33dbbc059d767e6570017c668
==24757== ERROR: libFuzzer: deadly signal
    #0 0x4c6e37 in __sanitizer_print_stack_trace (/root/zstd/tests/fuzz/stream_round_trip+0x4c6e37)
    #1 0x5bd49c in fuzzer::Fuzzer::CrashCallback() /root/test/Fuzzer/FuzzerLoop.cpp:195:5
    #2 0x5bd46a in fuzzer::Fuzzer::StaticCrashSignalCallback() /root/test/Fuzzer/FuzzerLoop.cpp:179:6
    #3 0x7f085b7400bf  (/lib/x86_64-linux-gnu/libpthread.so.0+0x110bf)
    #4 0x53e091 in ZSTD_compressContinue_internal /root/zstd/tests/fuzz/../../lib/compress/zstd_compress.c:2978:20
    #5 0x5407ea in ZSTD_compressEnd /root/zstd/tests/fuzz/../../lib/compress/zstd_compress.c:3310:26
    #6 0x546e04 in ZSTD_compressStream_generic /root/zstd/tests/fuzz/../../lib/compress/zstd_compress.c:3809:38
    #7 0x54850d in ZSTD_endStream /root/zstd/tests/fuzz/../../lib/compress/zstd_compress.c:4018:5
    #8 0x5b218e in compress /root/zstd/tests/fuzz/stream_round_trip.c:80:30
    #9 0x5b218e in LLVMFuzzerTestOneInput /root/zstd/tests/fuzz/stream_round_trip.c:140
    #10 0x5be2ea in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /root/test/Fuzzer/FuzzerLoop.cpp:460:13
    #11 0x5be551 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long) /root/test/Fuzzer/FuzzerLoop.cpp:399:3
    #12 0x5b2ceb in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /root/test/Fuzzer/FuzzerDriver.cpp:268:6
    #13 0x5b6e5f in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /root/test/Fuzzer/FuzzerDriver.cpp:683:9
    #14 0x5b2a50 in main /root/test/Fuzzer/FuzzerMain.cpp:20:10
    #15 0x7f085ad8d2b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0)
    #16 0x41f2f9 in _start (/root/zstd/tests/fuzz/stream_round_trip+0x41f2f9)

NOTE: libFuzzer has rudimentary signal handlers.
      Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal

/third_party/llvm-build/Release+Asserts/bin/clang --version

clang version 5.0.0 (trunk 305735)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /third_party/llvm-build/Release+Asserts/bin

  Registered Targets:
    aarch64    - AArch64 (little endian)
    aarch64_be - AArch64 (big endian)
    amdgcn     - AMD GCN GPUs
    arm        - ARM
    arm64      - ARM64 (little endian)
    armeb      - ARM (big endian)
    bpf        - BPF (host endian)
    bpfeb      - BPF (big endian)
    bpfel      - BPF (little endian)
    hexagon    - Hexagon
    lanai      - Lanai
    mips       - Mips
    mips64     - Mips64 [experimental]
    mips64el   - Mips64el [experimental]
    mipsel     - Mipsel
    msp430     - MSP430 [experimental]
    nvptx      - NVIDIA PTX 32-bit
    nvptx64    - NVIDIA PTX 64-bit
    ppc32      - PowerPC 32
    ppc64      - PowerPC 64
    ppc64le    - PowerPC 64 LE
    r600       - AMD GPUs HD2XXX-HD6XXX
    riscv32    - 32-bit RISC-V
    riscv64    - 64-bit RISC-V
    sparc      - Sparc
    sparcel    - Sparc LE
    sparcv9    - Sparc V9
    systemz    - SystemZ
    thumb      - Thumb
    thumbeb    - Thumb (big endian)
    x86        - 32-bit X86: Pentium-Pro and above
    x86-64     - 64-bit X86: EM64T and AMD64
    xcore      - XCore

Which I get via

git clone https://chromium.googlesource.com/chromium/src/tools/clang
clang/scripts/update.py
terrelln commented 7 years ago

I'll try with the Chromium clang tomorrow, but I couldn't reproduce it on Centos 7 x86_64 with clang-5.0 with these flags.

-DZSTD_DEBUG=1 -DMEM_FORCE_MEMORY_ACCESS=0 -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -g -fno-omit-frame-pointer -g -fsanitize=undefined -fno-sanitize=pointer-overflow
clang version 5.0.0
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/terrelln/bin

  Registered Targets:
    bpf     - BPF (host endian)
    bpfeb   - BPF (big endian)
    bpfel   - BPF (little endian)
    nvptx   - NVIDIA PTX 32-bit
    nvptx64 - NVIDIA PTX 64-bit
    x86     - 32-bit X86: Pentium-Pro and above
    x86-64  - 64-bit X86: EM64T and AMD64
terrelln commented 7 years ago

Can you reproduce the SIGILL without UBSan enabled?

geeknik commented 7 years ago

My previous comment was my bad, had too many windows open, didn't make clean in the right spot. It appears as though the SIGILL does goes away with these flags after all:

-O2 -fno-omit-frame-pointer -g -fsanitize=address,undefined -fsanitize-coverage=trace-pc-guard -fno-sanitize=pointer-overflow