diff options
author | Ivan Nardi <12729895+IvanNardi@users.noreply.github.com> | 2024-06-29 18:01:05 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-29 18:01:05 +0200 |
commit | ebcea42e2b39a58c9dfa395e1992114fc0baa5ef (patch) | |
tree | c6d0f26f1c241a085aab6b1f90066470781b8277 | |
parent | 83e6e753af1a6123805a4777691da1f8821c01d0 (diff) |
fuzz: improve fuzzers using pl7m (#2486)
For some unclear reasons, fuzzers using pl7m create huge corpus,
triggering OOM in oss-fuzz runs (where the memory RSS limit is set to
2560Mb). Example:
```
==25340== ERROR: libFuzzer: out-of-memory (used: 2564Mb; limit: 2560Mb)
To change the out-of-memory limit use -rss_limit_mb=<N>
Live Heap Allocations: 2364004039 bytes in 133791 chunks; quarantined: 60662293 bytes in 3664 chunks; 176432 other chunks; total chunks: 313887; showing top 95% (at most 8 unique contexts)
1285841683 byte(s) (54%) in 2956 allocation(s)
#0 0x56f814ef4bde in __interceptor_malloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:69:3
#1 0x56f814e04416 in operator new(unsigned long) cxa_noexception.cpp:0
#2 0x56f814de6b2d in assign<unsigned char *, 0> /work/llvm-stage2/runtimes/runtimes-bins/compiler-rt/lib/fuzzer/libcxx_fuzzer_x86_64/include/c++/v1/vector:1443:3
#3 0x56f814de6b2d in operator= /work/llvm-stage2/runtimes/runtimes-bins/compiler-rt/lib/fuzzer/libcxx_fuzzer_x86_64/include/c++/v1/vector:1412:9
#4 0x56f814de6b2d in fuzzer::InputCorpus::AddToCorpus(std::__Fuzzer::vector<unsigned char, std::__Fuzzer::allocator<unsigned char>> const&, unsigned long, bool, bool, bool, std::__Fuzzer::chrono::duration<long long, std::__Fuzzer::ratio<1l, 1000000l>>, std::__Fuzzer::vector<unsigned int, std::__Fuzzer::allocator<unsigned int>> const&, fuzzer::DataFlowTrace const&, fuzzer::InputInfo const*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerCorpus.h:221:10
#5 0x56f814de60e5 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:539:16
#6 0x56f814de7df2 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile>>&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:829:7
#7 0x56f814de8127 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile>>&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:867:3
#8 0x56f814dd6736 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:914:6
#9 0x56f814e02c62 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#10 0x7fa11e2c3082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/libc-start.c:308:16
1031350683 byte(s) (43%) in 2468 allocation(s)
#0 0x56f814ef4bde in __interceptor_malloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:69:3
#1 0x56f814e04416 in operator new(unsigned long) cxa_noexception.cpp:0
#2 0x56f814de6b2d in assign<unsigned char *, 0> /work/llvm-stage2/runtimes/runtimes-bins/compiler-rt/lib/fuzzer/libcxx_fuzzer_x86_64/include/c++/v1/vector:1443:3
#3 0x56f814de6b2d in operator= /work/llvm-stage2/runtimes/runtimes-bins/compiler-rt/lib/fuzzer/libcxx_fuzzer_x86_64/include/c++/v1/vector:1412:9
#4 0x56f814de6b2d in fuzzer::InputCorpus::AddToCorpus(std::__Fuzzer::vector<unsigned char, std::__Fuzzer::allocator<unsigned char>> const&, unsigned long, bool, bool, bool, std::__Fuzzer::chrono::duration<long long, std::__Fuzzer::ratio<1l, 1000000l>>, std::__Fuzzer::vector<unsigned int, std::__Fuzzer::allocator<unsigned int>> const&, fuzzer::DataFlowTrace const&, fuzzer::InputInfo const*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerCorpus.h:221:10
#5 0x56f814de60e5 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:539:16
#6 0x56f814de7635 in fuzzer::Fuzzer::MutateAndTestOne() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:760:19
#7 0x56f814de8425 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile>>&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:905:5
#8 0x56f814dd6736 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:914:6
#9 0x56f814e02c62 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#10 0x7fa11e2c3082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/libc-start.c:308:16
```
See: https://oss-fuzz.com/testcase-detail/4717811415449600
See: https://oss-fuzz.com/testcase-detail/6164130982068224
Let's *try* the following workaround: set the parameter `-max-len` to
512K, to force the engine to not genereate inputs (i.e. pcap files...)
larger than 512K. Right now the value used is 1MB, i.e the default,
because we have file larger than 1MB in the initial seeds (i.e.
`/tests/pcaps/*`).
Let's hope than having smaller files lead to smaller corpus...
Update pl7m code (fix a Use-of-uninitialized-value error)
-rw-r--r-- | fuzz/fuzz_ndpi_reader_pl7m.options | 2 | ||||
-rw-r--r-- | fuzz/fuzz_ndpi_reader_pl7m_64k.options | 2 | ||||
-rw-r--r-- | fuzz/fuzz_ndpi_reader_pl7m_internal.options | 2 | ||||
-rw-r--r-- | fuzz/fuzz_ndpi_reader_pl7m_internal_simplest.options | 2 | ||||
-rw-r--r-- | fuzz/fuzz_ndpi_reader_pl7m_simplest.options | 2 | ||||
-rw-r--r-- | src/lib/third_party/src/fuzz/pl7m.c | 35 |
6 files changed, 31 insertions, 14 deletions
diff --git a/fuzz/fuzz_ndpi_reader_pl7m.options b/fuzz/fuzz_ndpi_reader_pl7m.options new file mode 100644 index 000000000..1cc0e03b2 --- /dev/null +++ b/fuzz/fuzz_ndpi_reader_pl7m.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len=524288 diff --git a/fuzz/fuzz_ndpi_reader_pl7m_64k.options b/fuzz/fuzz_ndpi_reader_pl7m_64k.options new file mode 100644 index 000000000..1cc0e03b2 --- /dev/null +++ b/fuzz/fuzz_ndpi_reader_pl7m_64k.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len=524288 diff --git a/fuzz/fuzz_ndpi_reader_pl7m_internal.options b/fuzz/fuzz_ndpi_reader_pl7m_internal.options new file mode 100644 index 000000000..1cc0e03b2 --- /dev/null +++ b/fuzz/fuzz_ndpi_reader_pl7m_internal.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len=524288 diff --git a/fuzz/fuzz_ndpi_reader_pl7m_internal_simplest.options b/fuzz/fuzz_ndpi_reader_pl7m_internal_simplest.options new file mode 100644 index 000000000..1cc0e03b2 --- /dev/null +++ b/fuzz/fuzz_ndpi_reader_pl7m_internal_simplest.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len=524288 diff --git a/fuzz/fuzz_ndpi_reader_pl7m_simplest.options b/fuzz/fuzz_ndpi_reader_pl7m_simplest.options new file mode 100644 index 000000000..1cc0e03b2 --- /dev/null +++ b/fuzz/fuzz_ndpi_reader_pl7m_simplest.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len=524288 diff --git a/src/lib/third_party/src/fuzz/pl7m.c b/src/lib/third_party/src/fuzz/pl7m.c index aa34bd5a5..d3c507283 100644 --- a/src/lib/third_party/src/fuzz/pl7m.c +++ b/src/lib/third_party/src/fuzz/pl7m.c @@ -125,6 +125,13 @@ size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); #endif +/* If you want custom memory allocators, you can simply change these defines */ +#define pl7m_malloc(size) malloc(size) +#define pl7m_calloc(num, size) calloc(num, size) +#define pl7m_free(p) free(p) + + + struct gre_header { #if defined(__LITTLE_ENDIAN_BITFIELD) u_int16_t rec:3, @@ -402,8 +409,8 @@ static int dissect_l3(struct m_pkt *p) switch (p->l3_proto) { case ETH_P_IP: ip4 = (struct ip *)data; - if (ip4->ip_v != 4 || - data_len < 20 /* min */ || + if (data_len < 20 /* min */ || + ip4->ip_v != 4 || ip4->ip_hl < 5 || data_len < ip4->ip_hl * 4 || ntohs(ip4->ip_len) < ip4->ip_hl * 4) { @@ -931,12 +938,12 @@ static struct m_pkt *__dup_pkt(struct m_pkt *p) { struct m_pkt *n; - n = (struct m_pkt *)malloc(sizeof(struct m_pkt)); + n = (struct m_pkt *)pl7m_malloc(sizeof(struct m_pkt)); if (!n) return NULL; - n->raw_data = (unsigned char *)malloc(MAX_PKT_LENGTH); + n->raw_data = (unsigned char *)pl7m_malloc(MAX_PKT_LENGTH); if(!n->raw_data) { - free(n); + pl7m_free(n); return NULL; } memcpy(n->raw_data, p->raw_data, p->header.caplen); @@ -960,8 +967,8 @@ static struct m_pkt *__dup_pkt(struct m_pkt *p) } static void __free_pkt(struct m_pkt *p) { - free(p->raw_data); - free(p); + pl7m_free(p->raw_data); + pl7m_free(p); } static void __add_pkt(struct pl7m_handle *h, struct m_pkt *p, struct m_pkt *prev, struct m_pkt *next) @@ -1023,7 +1030,7 @@ static void __free_m_pkts(struct pl7m_handle *h) __free_pkt(p); p = n; } - free(h); + pl7m_free(h); } static struct m_pkt *do_pkt_actions(struct pl7m_handle *h, struct m_pkt *p, struct m_pkt **prev) @@ -1167,7 +1174,7 @@ static struct pl7m_handle *__deserialize_from_fd(FILE *fd_in) return NULL; } - h = (struct pl7m_handle *)calloc(1, sizeof(struct pl7m_handle)); + h = (struct pl7m_handle *)pl7m_calloc(1, sizeof(struct pl7m_handle)); if (!h) { pcap_close(pcap_h); return NULL; @@ -1183,15 +1190,15 @@ static struct pl7m_handle *__deserialize_from_fd(FILE *fd_in) /* Ignore current pkt, but keep going */ continue; } - p = (struct m_pkt *)calloc(sizeof(struct m_pkt), 1); + p = (struct m_pkt *)pl7m_calloc(sizeof(struct m_pkt), 1); if (!p) { __free_m_pkts(h); pcap_close(pcap_h); return NULL; } - p->raw_data = (unsigned char *)malloc(MAX_PKT_LENGTH); + p->raw_data = (unsigned char *)pl7m_malloc(MAX_PKT_LENGTH); if (!p->raw_data) { - free(p); + pl7m_free(p); __free_m_pkts(h); pcap_close(pcap_h); return NULL; @@ -1205,8 +1212,8 @@ static struct pl7m_handle *__deserialize_from_fd(FILE *fd_in) if (rc != 0) { derr("Error dissect_do\n"); /* Ignore current pkt, but keep going */ - free(p->raw_data); - free(p); + pl7m_free(p->raw_data); + pl7m_free(p); continue; } |