inikep / lizard

Lizard (formerly LZ5) is an efficient compressor with very fast decompression. It achieves compression ratio that is comparable to zip/zlib and zstd/brotli (at low and medium compression levels) at decompression speed of 1000 MB/s and faster.
Other
644 stars 40 forks source link

Fixed use-of-uninitialized-value MSAN warning in Lizard_decompress_LIZv1 #26

Open nmoinvaz opened 3 years ago

nmoinvaz commented 3 years ago

When reading compressed input it is possible to read past the end of the input due to missing check for 2 bytes before the call to MEM_readLE16.

Here is the memory sanitizer warning:

==141574==WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 0x4af776 in Lizard_decompress_LIZv1 /home/nathan/Source/lizard/cmake_unofficial/../lib/lizard_decompress_liz.h:166:81
    #1 0x4af776 in Lizard_decompress_generic /home/nathan/Source/lizard/lib/lizard_decompress.c:241:19
    #2 0x4af776 in Lizard_decompress_safe /home/nathan/Source/lizard/lib/lizard_decompress.c:269:12
    #3 0x91bf15 in main /home/nathan/Source/lizard/programs/liztest.c:30:18
    #4 0x7ffff7c4b0b2 in __libc_start_main /build/glibc-ZN95T4/glibc-2.31/csu/../csu/libc-start.c:308:16
    #5 0x41f29d in _start (/home/nathan/Source/lizard/build/lizardx+0x41f29d)

  Uninitialized value was stored to memory at
    #0 0x4ad1e9 in Lizard_decompress_LIZv1 /home/nathan/Source/lizard/cmake_unofficial/../lib/lizard_decompress_liz.h:102:26
    #1 0x4ad1e9 in Lizard_decompress_generic /home/nathan/Source/lizard/lib/lizard_decompress.c:241:19
    #2 0x4ad1e9 in Lizard_decompress_safe /home/nathan/Source/lizard/lib/lizard_decompress.c:269:12
    #3 0x91bf15 in main /home/nathan/Source/lizard/programs/liztest.c:30:18
    #4 0x7ffff7c4b0b2 in __libc_start_main /build/glibc-ZN95T4/glibc-2.31/csu/../csu/libc-start.c:308:16

  Uninitialized value was stored to memory at
    #0 0x4acf85 in Lizard_decompress_LIZv1 /home/nathan/Source/lizard/cmake_unofficial/../lib/lizard_decompress_liz.h:100:26
    #1 0x4acf85 in Lizard_decompress_generic /home/nathan/Source/lizard/lib/lizard_decompress.c:241:19
    #2 0x4acf85 in Lizard_decompress_safe /home/nathan/Source/lizard/lib/lizard_decompress.c:269:12
    #3 0x91bf15 in main /home/nathan/Source/lizard/programs/liztest.c:30:18
    #4 0x7ffff7c4b0b2 in __libc_start_main /build/glibc-ZN95T4/glibc-2.31/csu/../csu/libc-start.c:308:16

  Uninitialized value was stored to memory at
    #0 0x583051 in MEM_readLE16 /home/nathan/Source/lizard/cmake_unofficial/../lib/entropy/mem.h:226:9
    #1 0x4acf11 in Lizard_decompress_LIZv1 /home/nathan/Source/lizard/cmake_unofficial/../lib/lizard_decompress_liz.h:100:36
    #2 0x4acf11 in Lizard_decompress_generic /home/nathan/Source/lizard/lib/lizard_decompress.c:241:19
    #3 0x4acf11 in Lizard_decompress_safe /home/nathan/Source/lizard/lib/lizard_decompress.c:269:12
    #4 0x91bf15 in main /home/nathan/Source/lizard/programs/liztest.c:30:18
    #5 0x7ffff7c4b0b2 in __libc_start_main /build/glibc-ZN95T4/glibc-2.31/csu/../csu/libc-start.c:308:16

  Uninitialized value was stored to memory at
    #0 0x424e06 in __msan_memcpy (/home/nathan/Source/lizard/build/lizardx+0x424e06)
    #1 0x583559 in MEM_read16 /home/nathan/Source/lizard/cmake_unofficial/../lib/entropy/mem.h:146:14
    #2 0x582fe5 in MEM_readLE16 /home/nathan/Source/lizard/cmake_unofficial/../lib/entropy/mem.h:226:16
    #3 0x4acf11 in Lizard_decompress_LIZv1 /home/nathan/Source/lizard/cmake_unofficial/../lib/lizard_decompress_liz.h:100:36
    #4 0x4acf11 in Lizard_decompress_generic /home/nathan/Source/lizard/lib/lizard_decompress.c:241:19
    #5 0x4acf11 in Lizard_decompress_safe /home/nathan/Source/lizard/lib/lizard_decompress.c:269:12
    #6 0x91bf15 in main /home/nathan/Source/lizard/programs/liztest.c:30:18
    #7 0x7ffff7c4b0b2 in __libc_start_main /build/glibc-ZN95T4/glibc-2.31/csu/../csu/libc-start.c:308:16

  Uninitialized value was created by a heap allocation
    #0 0x42b47d in malloc (/home/nathan/Source/lizard/build/lizardx+0x42b47d)
    #1 0x49af7b in Lizard_decompress_generic /home/nathan/Source/lizard/lib/lizard_decompress.c:150:33
    #2 0x49af7b in Lizard_decompress_safe /home/nathan/Source/lizard/lib/lizard_decompress.c:269:12
    #3 0x91bf15 in main /home/nathan/Source/lizard/programs/liztest.c:30:18
    #4 0x7ffff7c4b0b2 in __libc_start_main /build/glibc-ZN95T4/glibc-2.31/csu/../csu/libc-start.c:308:16

SUMMARY: MemorySanitizer: use-of-uninitialized-value /home/nathan/Source/lizard/cmake_unofficial/../lib/lizard_decompress_liz.h:166:81 in Lizard_decompress_LIZv1
Exiting

Here is a sample app that can reproduce it:

#include <stdio.h>
#include <stdlib.h>

#include "lizard_decompress.h"

int main(int argc, const char** argv) {
    char output[1024], *input;
    int input_size = 0;

    if (argc <= 1) {
        printf("Missing input file to decompress\n");
        return -1;
    }

    FILE *f = fopen(argv[1], "rb");
    fseek(f, 0, SEEK_END);

    input_size = ftell(f);
    input = (char *)malloc(input_size);
    if (input == NULL) {
        fclose(f);
        return -1;
    }

    fseek(f, 0, SEEK_SET);
    fread(input, input_size, 1, f);
    fclose(f);

    int length = Lizard_decompress_safe((const char *)input, output,
        input_size, sizeof(output));

    if (length > 0)
        printf("Decompressed bytes %d\n", length);
    else
        printf("Unexpected error %d\n", length);

    return length;
}

Here is the arguments I use when compiling with Clang:

-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -O0

Here is the environment variables I use when running:

export MSAN_OPTIONS=print_stacktrace=1:abort_on_error=1

Here is the input file that can be used with the sample app above: https://www.dropbox.com/s/6jatquukhngdxzh/msan.bin?dl=0

Here is the original OSS-fuzz test case, but you won't have access to it. https://oss-fuzz.com/testcase-detail/5673261951877120