libFuzzer: Add build support and instructions#4433
Conversation
|
PTAL! Note that this depends on merging the following three changes, to avoid crashing wildly:
The OSS-Fuzz support will come next. Stay tuned! |
pks-t
left a comment
There was a problem hiding this comment.
Thanks a lot for this. I have no idea how @carlosmn or @ethomson think about this, but eventually I'd like to have a set of fuzzers included in our code base. It would be even nicer if those fuzzers could be submitted to the Google OSS-fuzz infrastructure such that we have continuous fuzzing of some of our code. I'd deem this especially important for all network-facing code.
So thanks a lot for working on this, this crosses off one item from my todo list!
| ADD_SUBDIRECTORY(examples) | ||
| ENDIF () | ||
|
|
||
| IF (BUILD_FUZZERS) |
There was a problem hiding this comment.
Even though that's not yet documented, we now settled on IF( style, so without spaces in between. We're not being consistent about it right now, but going forward we try to be.
|
|
||
| 1. Create a build directory beneath the libgit2 source directory, and change into it: `mkdir build && cd build` | ||
| 2. Choose which sanitizers to add. For instance, `address,leak`. Note that some sanitizers are mutually incompatible, so you might need several rounds to achieve more coverage. | ||
| 3. Create the cmake build environment and configure the build with the sanitizers chosen: `CC=/usr/bin/clang-6.0 CFLAGS="-fsanitize=fuzzer-no-link,address,leak -g" cmake -DTHREADSAFE=ON -DBUILD_CLAR=OFF -DBUILD_SHARED_LIBS=OFF -DBUILD_FUZZERS=ON -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=fuzzer,address,leak" ..`. Note that `CFLAGS` has `fuzzer-no-link` followed by the chosen sanitizers and `-DCMAKE_EXE_LINKER_FLAGS` has `fuzzer` followed by the chosen sanitizers. |
There was a problem hiding this comment.
I think instead of instructing the user to set CC and CFLAGS for himself, you should do it for him in case the user has enabled fuzzing.
There was a problem hiding this comment.
Tried to automate it as much as possible, but I had trouble getting rid of the CC and linker flags, because OSS-Fuzz require the build system to not assume these things.
I could add an USE_OSS_FUZZ flag to turn off all these things, but I'm not an expert in CMake and couldn't get it to correctly detect a version of clang that was recent enough (especially given that you need to manually install it, and the binary name might change between distros).
There was a problem hiding this comment.
It's a lot better already. Given the clear build instructions I'm fine with this, thanks!
|
|
||
| 1. All the prerequisites for [building libgit2](https://github.com/libgit2/libgit2). | ||
| 2. A recent version of clang. 6.0 is preferred. [pre-build Debian/Ubuntu packages](https://github.com/libgit2/libgit2) | ||
| 3. (Optional) Symlink the `llvm-symbolizer` binary to get nice stack traces: `sudo ln -s llvm-symbolizer-6.0 /usr/bin/llvm-symbolizer` |
There was a problem hiding this comment.
We shouldn't instruct the user to modify his base system, which should only be touched by the package manager.
|
|
||
| **Run the fuzz targets** | ||
|
|
||
| 1. `ASAN_OPTIONS=allocator_may_return_null=1 ./build/fuzz/fuzz_packfile_raw fuzz/corpora/fuzz_packfile_raw/` |
There was a problem hiding this comment.
The plural of "corpus": http://llvm.org/docs/LibFuzzer.html#corpus
| #include <stdint.h> | ||
| #include <stdio.h> | ||
|
|
||
| #include <openssl/sha.h> |
There was a problem hiding this comment.
Instead of using OpenSSL for SHA1, you can just link to libgit2internal, add the include path to the source directory and use for example git_hash_buf to do the hashing.
| static git_odb *odb = NULL; | ||
|
|
||
| int LLVMFuzzerInitialize(__attribute__((unused)) int *argc, | ||
| __attribute__((unused)) char ***argv) |
There was a problem hiding this comment.
Please use the GIT_UNUSED macro instead of __attribute((unused)).
| fprintf(stderr, "Failed to initialize libgit2\n"); | ||
| abort(); | ||
| } | ||
| if (git_repository_init(&repo, REPOSITORY_PATH, true) < 0) { |
There was a problem hiding this comment.
I think instead of having a repository being created in the current directory, you should instead create a temporary path by using e.g. mkdtemp.
There was a problem hiding this comment.
How about I use git_mempack_new instead? No files except the pack_git_... temporaries which will only be leaked if the process crashes. I also added some code to remove the *.pack and *.idx files that are committed.
The problem with the fuzzers is that they are not designed to clean up the process state when they go down. Even using atexit(3) wasn't enough to clean the mess left.
| } | ||
|
|
||
| git_indexer *indexer; | ||
| git_transfer_progress stats = {0, 0}; |
There was a problem hiding this comment.
We are using C90 only, so please no variable declarations after statements.
There was a problem hiding this comment.
Done (switching my brain off of C++ is hard)
| abort(); | ||
| } | ||
| if (git_indexer_append(indexer, hash, sizeof(hash), &stats) < | ||
| 0) { |
There was a problem hiding this comment.
This linebreak is a bit funny. No need to be too strict with breaking lines.
There was a problem hiding this comment.
I admit my kernel-style is weak, so I rely on clang-format. Fixed.
|
|
||
| cleanup: | ||
| git_indexer_free(indexer); | ||
| return 0; |
There was a problem hiding this comment.
How is the return value being interpreted by LLVM?
There was a problem hiding this comment.
It is required to be zero (for now): http://llvm.org/docs/LibFuzzer.html#fuzz-target
|
The trigger is ready to be pulled: https://github.com/lhchavez/oss-fuzz/tree/libgit2/projects/libgit2 LMK who needs to be the owner/maintainer for the project in OSS-Fuzz. |
|
All prerequisites have been merged, so this change is ready to land. |
pks-t
left a comment
There was a problem hiding this comment.
I didn't see anything that immediately catched my eyes, only some few things to clear up for myself. I'd welcome it though if you could rebase this PR to get rid of the merge and also try to squash commits together where it makes sense (not in the sense of having one giant commit, but in the sense of getting rid of fixups to just-introduced commits).
Before merging this I'd like to get the opinions of @ethomson and @carlosmn.
Thanks a lot for your work!
| fprintf(stderr, "Failed to initialize libgit2\n"); | ||
| abort(); | ||
| } | ||
| if (git_repository_init(&repo, REPOSITORY_PATH, true) < 0) { |
| * with this software. If not, see | ||
| * <http://creativecommons.org/publicdomain/zero/1.0/>. | ||
| * This file is part of libgit2, distributed under the GNU GPL v2 with | ||
| * a Linking Exception. For full terms see the included COPYING file. |
There was a problem hiding this comment.
This should definitly be squashed into the commit which created that file ;)
|
|
||
| 1. Create a build directory beneath the libgit2 source directory, and change into it: `mkdir build && cd build` | ||
| 2. Choose which sanitizers to add. For instance, `address,leak`. Note that some sanitizers are mutually incompatible, so you might need several rounds to achieve more coverage. | ||
| 3. Create the cmake build environment and configure the build with the sanitizers chosen: `CC=/usr/bin/clang-6.0 CFLAGS="-fsanitize=fuzzer-no-link,address,leak -g" cmake -DTHREADSAFE=ON -DBUILD_CLAR=OFF -DBUILD_SHARED_LIBS=OFF -DBUILD_FUZZERS=ON -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=fuzzer,address,leak" ..`. Note that `CFLAGS` has `fuzzer-no-link` followed by the chosen sanitizers and `-DCMAKE_EXE_LINKER_FLAGS` has `fuzzer` followed by the chosen sanitizers. |
There was a problem hiding this comment.
It's a lot better already. Given the clear build instructions I'm fine with this, thanks!
| # The actual sanitizer link target will be added when linking the fuzz | ||
| # targets. | ||
| SET(CMAKE_C_FLAGS "-fsanitize=fuzzer-no-link ${CMAKE_C_FLAGS}") | ||
| ENDIF () |
|
|
||
| In order to get full coverage, though, you might want to also enable one of the | ||
| sanitizers. You might need a recent version of clang to get full support. | ||
|
|
There was a problem hiding this comment.
That's definitly nice to have. I'm currently stuck on a system without working fuzzers due to problems with musl libc, so I always have to use a VM. At least I can get some feedback with the standalone mode.
| goto exit; | ||
| } | ||
| git_vector_foreach(&corpus_files, i, corpus_filename) { | ||
| if (run_one_file(corpus_filename) < 0) { |
There was a problem hiding this comment.
This can only happen in case the corpus file could not be read, right? As in the case of a corpus error, we alwasy abort().
There was a problem hiding this comment.
yes, abort() or segfault.
| fuzz_target_name=$(basename "${fuzz_target}") | ||
| # TODO: Make this exit on failures once all fixes are in place. | ||
| "${fuzz_target}" "../fuzz/corpora/${fuzz_target_name}" | ||
| done |
There was a problem hiding this comment.
Cool, that's a good thing to have. I guess making it work on AppVeyor wouldn't make any sense at all, would it?
There was a problem hiding this comment.
maybe, i can give it a try later :)
|
Squashed and ready to go! |
|
I'll tackle this PR after the next release, which should hopefully be done soon |
This change adds support for building a fuzz target for exercising the packfile parser, as well as documentation. It also runs the fuzzers in Travis to avoid regressions.
|
any progress on the release? i've rebased the squashed change to |
|
Sorry @lhchavez for not getting back to this earlier x( I've planned to tackle this issue next week anyway, as we now also have another proposed fuzzer from @nelhage. As both proposed fuzzers test different things (packfiles vs smart protocol), they luckily can both be merged into our code base. This PR has been lurking around for too long, though. I always wanted to get this merged, but somehow I never found the time to finally follow through. |
|
all right, let me know if there's a preferred way to split this change to make reviews easier. |
|
Would you be okay with me adopting this PR? I'd obviously retain your commits and start working from them, but adopting the PR would allow me to push this faster and also merge with the other fuzzing target we have by now. Feel free to say "no" in case you want to push this through, though, I wouldn't mind. |
|
go for it! and thanks for your help. |
|
Correct, fuzzing is implemented now and finding lots of errors, so this can be closed Thanks again, @lhchavez, it has proven to be highly valuable for us! |
This change adds support for building a fuzz target for exercising the
packfile parser, as well as documentation. It also runs the fuzzers in
Travis to avoid regressions.