-
Notifications
You must be signed in to change notification settings - Fork 2.5k
libFuzzer: Add build support and instructions #4433
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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!
CMakeLists.txt
Outdated
@@ -328,6 +329,10 @@ IF (BUILD_EXAMPLES) | |||
ADD_SUBDIRECTORY(examples) | |||
ENDIF () | |||
|
|||
IF (BUILD_FUZZERS) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
fuzz/README.md
Outdated
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a lot better already. Given the clear build instructions I'm fine with this, thanks!
fuzz/README.md
Outdated
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't instruct the user to modify his base system, which should only be touched by the package manager.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
fuzz/README.md
Outdated
|
||
**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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's that "corpora" prefix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The plural of "corpus": http://llvm.org/docs/LibFuzzer.html#corpus
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Heh, good to know
fuzz/fuzz_packfile_raw.c
Outdated
#include <stdint.h> | ||
#include <stdio.h> | ||
|
||
#include <openssl/sha.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, done
fuzz/fuzz_packfile_raw.c
Outdated
static git_odb *odb = NULL; | ||
|
||
int LLVMFuzzerInitialize(__attribute__((unused)) int *argc, | ||
__attribute__((unused)) char ***argv) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the GIT_UNUSED
macro instead of __attribute((unused))
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
fuzz/fuzz_packfile_raw.c
Outdated
fprintf(stderr, "Failed to initialize libgit2\n"); | ||
abort(); | ||
} | ||
if (git_repository_init(&repo, REPOSITORY_PATH, true) < 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's even better!
fuzz/fuzz_packfile_raw.c
Outdated
} | ||
|
||
git_indexer *indexer; | ||
git_transfer_progress stats = {0, 0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are using C90 only, so please no variable declarations after statements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done (switching my brain off of C++ is hard)
fuzz/fuzz_packfile_raw.c
Outdated
abort(); | ||
} | ||
if (git_indexer_append(indexer, hash, sizeof(hash), &stats) < | ||
0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This linebreak is a bit funny. No need to be too strict with breaking lines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I admit my kernel-style is weak, so I rely on clang-format. Fixed.
fuzz/fuzz_packfile_raw.c
Outdated
|
||
cleanup: | ||
git_indexer_free(indexer); | ||
return 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is the return value being interpreted by LLVM?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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!
fuzz/fuzz_packfile_raw.c
Outdated
fprintf(stderr, "Failed to initialize libgit2\n"); | ||
abort(); | ||
} | ||
if (git_repository_init(&repo, REPOSITORY_PATH, true) < 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's even better!
fuzz/fuzz_packfile_raw.c
Outdated
* 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should definitly be squashed into the commit which created that file ;)
fuzz/README.md
Outdated
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a lot better already. Given the clear build instructions I'm fine with this, thanks!
CMakeLists.txt
Outdated
# 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 () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice
fuzz/README.md
Outdated
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
fuzz/StandaloneFuzzTargetMain.c
Outdated
goto exit; | ||
} | ||
git_vector_foreach(&corpus_files, i, corpus_filename) { | ||
if (run_one_file(corpus_filename) < 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, abort()
or segfault.
script/cibuild.sh
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.