From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtpng2.m.smailru.net (smtpng2.m.smailru.net [94.100.179.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 8638245C304 for ; Sun, 20 Dec 2020 16:31:14 +0300 (MSK) Date: Sun, 20 Dec 2020 16:31:09 +0300 From: Igor Munkin Message-ID: <20201220133109.GN5396@tarantool.org> References: <20201207172444.GE5396@tarantool.org> <51ad8f7a-c804-7e06-ceb9-0c8adcc56d16@tarantool.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <51ad8f7a-c804-7e06-ceb9-0c8adcc56d16@tarantool.org> Subject: Re: [Tarantool-patches] [PATCH 1/4] test: add infrastructure for fuzzing testing and fuzzers List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Sergey Bronnikov Cc: tarantool-patches@dev.tarantool.org Sergey, Thanks for the changes! On 13.12.20, Sergey Bronnikov wrote: > Igor, many thanks for review! > > I've fixed patches and pushed to the branch (but left them as a separate > commits with prefix [TO SQUASH]). Everything is fixed in scope of the other patches in the series, but I have more questions for your answers and updates for this one, please consider them below. > > On 07.12.2020 20:24, Igor Munkin wrote: > > Sergey, > > > > Thanks for the patch! Please consider the remaining comments below. > > > > On 30.11.20, sergeyb@tarantool.org wrote: > >> and add fuzzers based on LibFuzzer [1] to csv, http_parser and uri modules. Typo: Still exceeds 72 chars... > >> NOTE: LibFuzzer requires Clang compiler. > > Message with assert is definitely not ok. LibFuzzer documentation says > that all fuzzers must return 0 only [1]. > Neat, now everything works fine. However, considering your comment, I have a newbie question (since I'm not an expert in fuzzing testing): how do we need to check whether parsing finishes right or not? Anyway, you can simply add asserts to check rc is 0, can't you? Otherwise these tests look kinda smoke ones to me. > > --- a/test/fuzz/csv_fuzzer.c > +++ b/test/fuzz/csv_fuzzer.c > @@ -9,15 +9,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t > size) { >          csv_create(&csv); >          char *buf = calloc(size, sizeof(char*)); Typo: s/sizeof(char*)/sizeof(char)/. This is why I failed to prove the out of boundary access below for a while. Surprisingly, everything is fine in HTTP parser test. >          if (buf == NULL) > -                return -1; > +                return 0; I believe the testing is not OK if yields NULL, but the code returns 0. This is odd, IMHO. What about adding either assert or abort to handle this branch? To make asserts work all time simply undefine NDEBUG at the beginning of the test. Same for other cases. >          memcpy(buf, data, size); >          buf[size] = '\0'; This write is out of boundaries. In fact it's not, since you overallocate a chunk above (consider typo: sizeof(char *) instead of sizeof(char)). You want to allocate the bytes via and accessing byte, but the "last slot" is addressed by ( - 1). Moreover, these manipulations are excessive: if data passed as the first argument is NUL-terminated, then this assignment is not necessary (everything is done by ). Otherwise, you strips the last byte of the first argument and you need to allocate ( + 1) bytes. Same for URI parser. >          char *end = buf + size; >          csv_parse_chunk(&csv, buf, end); >          csv_finish_parsing(&csv); > -        int rc = csv_get_error_status(&csv) == CSV_ER_INVALID ? 1 : 0; >          csv_destroy(&csv); >          free(buf); > > -        return rc; > +        return 0; >  } > diff --git a/test/fuzz/http_parser_fuzzer.c b/test/fuzz/http_parser_fuzzer.c > index a0aaf6786..f2dd7d09a 100644 > --- a/test/fuzz/http_parser_fuzzer.c > +++ b/test/fuzz/http_parser_fuzzer.c > @@ -9,10 +9,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { > http_parser_create(&parser); > parser.hdr_name = (char *)calloc((int)size, sizeof(char)); Minor: why do you explicitly cast argument here, but omit such cast in other tests? > if (parser.hdr_name == NULL) > - return -1; > + return 0; > char *end_buf = buf + size; > - int rc = http_parse_header_line(&parser, &buf, end_buf, size); > + http_parse_header_line(&parser, &buf, end_buf, size); > free(parser.hdr_name); > > - return rc; > + return 0; > } > > For the rest I believe the reason is > > | NOTE: libFuzzer has rudimentary signal handlers. > | Combine libFuzzer with AddressSanitizer or similar for better crash reports. As I mentioned in the previous reply, I tried exactly your recipe, so ASAN was enabled. > > > > > >> Part of #1809 > >> --- > >> CMakeLists.txt | 2 +- > >> cmake/profile.cmake | 13 ++++++++++ > >> test/CMakeLists.txt | 3 +++ > >> test/fuzz/CMakeLists.txt | 45 ++++++++++++++++++++++++++++++++++ > >> test/fuzz/csv_fuzzer.c | 23 +++++++++++++++++ > >> test/fuzz/http_parser_fuzzer.c | 18 ++++++++++++++ > >> test/fuzz/uri_fuzzer.c | 19 ++++++++++++++ > >> 7 files changed, 122 insertions(+), 1 deletion(-) > >> create mode 100644 test/fuzz/CMakeLists.txt > >> create mode 100644 test/fuzz/csv_fuzzer.c > >> create mode 100644 test/fuzz/http_parser_fuzzer.c > >> create mode 100644 test/fuzz/uri_fuzzer.c > >> diff --git a/test/fuzz/CMakeLists.txt b/test/fuzz/CMakeLists.txt > >> new file mode 100644 > >> index 000000000..142d38f67 > >> --- /dev/null > >> +++ b/test/fuzz/CMakeLists.txt > >> @@ -0,0 +1,45 @@ > > > > 1. I'm totally not an expert, but quite confused with the fact the > > libcsv is build w/o flag, but csv_fuzzer is build with it. > > You are right. Project source code should be instrumented too and I > enable it: > > diff --git a/cmake/profile.cmake b/cmake/profile.cmake > index 45e3d112c..308d1b0fb 100644 > --- a/cmake/profile.cmake > +++ b/cmake/profile.cmake > @@ -53,6 +53,9 @@ if(ENABLE_FUZZER) >              " $ CC=clang CXX=clang++ cmake . <...> -DENABLE_FUZZER=ON > && make -j\n" >              "\n") >      endif() > +    if (NOT OSS_FUZZ) > +        add_compile_flags("C;CXX" -fsanitize=fuzzer-no-link) > +    endif() Why these compile flags are added under this particular condition? >  endif() > >  option(ENABLE_ASAN "Enable AddressSanitizer, a fast memory error > detector based on compiler instrumentation" OFF) > > You may not understand why options with "-fsanitize=fuzzer" two times > (in cmake/profile.cmake and test/fuzz/CMakeLists.txt). I'll clarify it > in advance: > > - cmake/profile.cmake is for project source files, > -fsanitize=fuzzer-no-link option allows to instrument project source > files for fuzzing, but LibFuzzer will not replace main() in these files. > > - test/fuzz/CMakeLists.txt uses -fsanitize=fuzzer and not > -fsanitize=fuzzer-no-link because we want to add automatically generated > main() for each fuzzer. This is a nice wording to comment the corresponding changes. > > > 2. Do you need to specify
flag once more, when ASAN is > > enabled? If not the hunk above looks excess, doesn't it? > > Agree, it was a bad idea to manage UBSan and ASAN flags in yet another > place. Side note: You can oblige one to enable ASAN/UBSAN the same way, you restrict building via clang. Of course if it makes sense :) > > > Code style also recommend to use goto(), but I believe that LibFuzzer > someday will start to accept different exit codes > > and probably it is better to keep code as is without using goto(). Agree here. By the way, there is one nit left: please remove the space between * and the parameter name in the function signatures. > > Also added a warning that triggered when someone use ENABLE_FUZZER and > OSS_FUZZ without > > environment variable LIB_FUZZING_ENGINE: Nice. > > --- a/cmake/profile.cmake > +++ b/cmake/profile.cmake > @@ -53,6 +53,13 @@ if(ENABLE_FUZZER) >              " $ CC=clang CXX=clang++ cmake . <...> -DENABLE_FUZZER=ON > && make -j\n" >              "\n") >      endif() > +    if(OSS_FUZZ AND NOT DEFINED ENV{LIB_FUZZING_ENGINE}) > +        message(SEND_ERROR Minor: Why do you use SEND_ERROR here? I guess one can't proceed with the desired testing in this case, so FATAL_ERROR prevents one from the further misuse. > +            "OSS-Fuzz builds require the environment variable " > +            "LIB_FUZZING_ENGINE to be set. If you are seeing this " > +            "warning, it points to a deeper problem in the ossfuzz " > +            "build setup.") > +    endif() Side note: the mess with whitespace is only in this patch. Everything is OK on the branch in the corresponding commit. >      if (NOT OSS_FUZZ) >          add_compile_flags("C;CXX" -fsanitize=fuzzer-no-link) >      endif() > > > 1. http://llvm.org/docs/LibFuzzer.html#id22 > > 2. > https://github.com/tarantool/tarantool/blob/master/cmake/compiler.cmake#L290-L320 > -- Best regards, IM