Skip to content
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

Fixes for a few fuzzer issues #11975

Merged
merged 2 commits into from
Mar 15, 2019
Merged

Conversation

keszybz
Copy link
Member

@keszybz keszybz commented Mar 12, 2019

No description provided.

This is almost the same as 0e636bf. I looked through the code,
and I don't see any more instances of this pattern, so hopefully this
will be the last one.

https://oss-fuzz.com/issue/5660094128193536/13691.
@keszybz keszybz added the fuzzing Implementation of fuzzers and fixes for stuff found through fuzzing label Mar 12, 2019
@poettering poettering added the good-to-merge/waiting-for-ci 👍 PR is good to merge, but CI hasn't passed at time of review. Please merge if you see CI has passed label Mar 12, 2019
@@ -0,0 +1,2 @@
[libfuzzer]
max_len = 65535
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't going to work when AFL is used as a fuzzing engine so ClusterFuzz will keep opening issues you're trying to avoid. They recommend checking whether the length passed to LLVMFuzzerTestOneInput makes sense in fuzz targets.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@evverx
Copy link
Member

evverx commented Mar 12, 2019

I doubt ClusterFuzz would have been able to find a couple of stack overflows if it hadn't tried to feed too much data to, for example, fuzz-json so I'm wondering why you're trying to sweep issues like that under the rug. You could just comment on issues ClusterFuzz have opened and ignore them if you don't think they should be fixed.

We have a few cases or reported issues which are about a timeout to parse
the input in 25 s. In all cases, the input is a few hundred kb. We don't really
care if the config parsers are super efficent, so let's set a limit on the input
size to avoid triggering such issues. The parsers often contain quadratic
algorithms. This is OK, because the numbers of elements are almost always very
small in real use. Rewriting the code to use more complicated data structures
to speed this up would not only complicate the code, but also pessimize behaviour
for the overwhelmingly common case of small samples. Note that in all those
cases, the input data is trusted. We care about memory correctness, and not
not so much about efficiency.

The size checks are done twice: using options for libfuzzer, and using an
internal check for afl. Those should be changed together. I didn't use a define,
because there is no easy mechanism to share the define between the two files.
@keszybz keszybz removed the good-to-merge/waiting-for-ci 👍 PR is good to merge, but CI hasn't passed at time of review. Please merge if you see CI has passed label Mar 12, 2019
@keszybz
Copy link
Member Author

keszybz commented Mar 12, 2019

Updated to add internal checks on size.

fuzz-json and various other fuzzers are different, because they are supposed to be used for external data. Those three are for data that we either write ourselves or which is configuration data. Marking and ignoring issues on oss-fuzz is not really an option, because the number of such code paths is very very large, so oss-fuzz would keep finding new issues. I think it's more worthwhile to let the fuzzers find issues that are not this type of resource exhaustion. As I wrote in the commit message, complicating the implementation to "solve" this case is not a good solution, because it would make the code more complicated and pessimize the common case of very small inputs.

So... generally, I think we should let the fuzzers use large inputs, iff the input data is external, and has no natural bound (e.g. from packet size).

@evverx
Copy link
Member

evverx commented Mar 12, 2019

I'm wondering where 65535 came from? Could we at least use something that wouldn't look too correct?

(This reminds me that 65535 shouldn't be used in fuzz-dns-packet either as discussed in #8423 (comment))

@evverx
Copy link
Member

evverx commented Mar 12, 2019

fuzz-json and various other fuzzers are different, because they are supposed to be used for external data.

As far as I can tell, fuzz-journald-stream, which is supposed to get external data, was changed relatively recently so that it could reject input that is larger than 65535 bytes, so it looks like the difference between fuzz targets handling "internal" and "external" data isn't clear-cut. To be honest, I'd revert eafadd0 because it'd make it clear that the fuzzer needs improving (instead of hiding the assertion).

@keszybz
Copy link
Member Author

keszybz commented Mar 13, 2019

@evverx sure, if you feel it worth the trouble, please rewrite the fuzzer to do reads and writes in loops. Using an event loop, this probably will not even be too much code. I just didn't think it worth the trouble, but I'd be happy to review a patch.

@evverx
Copy link
Member

evverx commented Mar 13, 2019

@keszybz I hope I'll get round to it, but in the meantime, what I'm trying to say is that it isn't clear to me why issues like that can't be just left open. It's not that we need to "close" as many issues as possible.

@evverx
Copy link
Member

evverx commented Mar 13, 2019

What's more interesting is that some fuzzers like fuzz-env-file are skipped when size is 0. That certainly doesn't feel right from a fuzzing perspective (and is probably another temporary solution to get around something else). I'm wondering if anyone can remember why it's done that way.

@keszybz
Copy link
Member Author

keszybz commented Mar 14, 2019

I added another commit to allow empty inputs.

@evverx
Copy link
Member

evverx commented Mar 14, 2019

check_build is complaining that 5 fuzz targets are broken:

Broken fuzz targets (5):
fuzz-env-file:
BAD BUILD: /out/fuzz-env-file seems to have either startup crash or exit:
INFO: Seed: 3157224537
INFO: Loaded 2 modules   (40415 inline 8-bit counters): 40406 [0x7fe9c030fa00, 0x7fe9c03197d6), 9 [0x8c1f10, 0x8c1f19),
INFO: Loaded 2 PC tables (40415 PCs): 40406 [0x7fe9c03197d8,0x7fe9c03b7538), 9 [0x6694f0,0x669580),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
Assertion 'f' failed at ../../src/systemd/src/fuzz/fuzz-env-file.c:19, function int LLVMFuzzerTestOneInput(const uint8_t *, size_t)(). Aborting.
AddressSanitizer:DEADLYSIGNAL
=================================================================
==79==ERROR: AddressSanitizer: ABRT on unknown address 0x00000000004f (pc 0x7fe9be99a428 bp 0x7fff9de2fab0 sp 0x7fff9de2f948 T0)
SCARINESS: 10 (signal)
    #0 0x7fe9be99a427 in gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x35427)
    #1 0x7fe9be99c029 in abort (/lib/x86_64-linux-gnu/libc.so.6+0x37029)
    #2 0x7fe9bfc5dbaa in log_assert_failed_realm /work/build/../../src/systemd/src/basic/log.c:795:9
    #3 0x5359ce in LLVMFuzzerTestOneInput /work/build/../../src/systemd/src/fuzz/fuzz-env-file.c:19:9
    #4 0x5761b6 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/libfuzzer/FuzzerLoop.cpp:529:15
    #5 0x578eaa in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, fuzzer::fuzzer_allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, fuzzer::fuzzer_allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&) /src/libfuzzer/FuzzerLoop.cpp:729:3
    #6 0x57a7c8 in fuzzer::Fuzzer::Loop(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, fuzzer::fuzzer_allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, fuzzer::fuzzer_allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&) /src/libfuzzer/FuzzerLoop.cpp:779:3
    #7 0x542faf in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/libfuzzer/FuzzerDriver.cpp:776:6
    #8 0x535b7c in main /src/libfuzzer/FuzzerMain.cpp:19:10
    #9 0x7fe9be98582f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #10 0x41d208 in _start (/out/fuzz-env-file+0x41d208)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: ABRT (/lib/x86_64-linux-gnu/libc.so.6+0x35427) in gsignal
==79==ABORTING
MS: 0 ; base unit: 0000000000000000000000000000000000000000


artifact_prefix='./'; Test unit written to ./crash-da39a3ee5e6b4b0d3255bfef95601890afd80709
...
Base64:
ERROR: 17% of fuzz targets seem to be broken. See the list above for a detailed information.
Check build failed.

which seems to explain why the fuzzers have always been skipped when size is 0.

@poettering
Copy link
Member

hmm, what's the state of this one? from my side this looks good, do you, @evverx have objections?

@keszybz
Copy link
Member Author

keszybz commented Mar 15, 2019

The last commit (to allow size==0) was causing problems. I backed it out now. I think this should be good to merge.

@keszybz
Copy link
Member Author

keszybz commented Mar 15, 2019

I'll return to the size==0 issue later.

@poettering poettering merged commit d449d63 into systemd:master Mar 15, 2019
@evverx
Copy link
Member

evverx commented Mar 15, 2019

do you, @evverx have objections?

@poettering it's not that I have any objections. It's just that I'm a little concerned that the fuzzers are slowly drifting into the point where they're starting to be less useful than they can be. It's not the first time issues that nobody supposedly is interested in have been swept under the rug by changing the fuzzers. If I recall correctly, the first one was about journal-remote allocating memory (4GB) in one fell swoop by receiving a 10 byte malformed message (which was fixed later because it was kind of related to a bug a CVE was assigned to). I just hope that (at least) someone looks at https://oss-fuzz.com/v2/coverage-report/job/libfuzzer_asan_systemd/latest from time to time to make sure that "fuzzing works best if the sample is not too huge anyway".

@evverx
Copy link
Member

evverx commented Mar 15, 2019

Speaking of the coverage report (and how useful it is), judging by https://storage.googleapis.com/oss-fuzz-coverage/systemd/reports/20190315/linux/src/systemd/src/fuzz/fuzz-calendarspec.c.html#L17, fuzz-calendarspec has never got past calendar_spec_from_string. Looks like >= should be used there instead of >.

@keszybz
Copy link
Member Author

keszybz commented Mar 16, 2019

> 0 was a bug, but not related to issue size. PR submitted.

I'm not sure what you're trying to say. I'm quite sure that having fuzzers which produce known-bogus results regularly, and having somebody just click through them and mark them as bogus is not the solution. We have a similar situation with CI — and wasted a lot of human time and it quickly leads to the situation where everybody is ignoring the results. Once again: the problem is that any place which does strv appends in the parsing stack is going to be "vulnerable" to timeouts if the sample size is large enough. If you have a better idea how to avoid this other than limiting the sample size, I'm all ears.

@evverx
Copy link
Member

evverx commented Mar 16, 2019

I'm not saying that limiting the sample size is necessarily a bad thing. It's just unclear to me why you decided to use 65535 when, for example, ENTRY_SIZE_MAX in journald is 1024*1024*13 (if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION is set). As I see it, fuzzing isn't exactly about tailoring input so that it can fit into a buffer of some kind without triggering edge cases.

@evverx
Copy link
Member

evverx commented Mar 16, 2019

We have a similar situation with CI — and wasted a lot of human time and it quickly leads to the situation where everybody is ignoring the results.

As far as I cat tell, the situation is getting better. Fedora CI, which was never actively maintained properly, was turned off and doesn't bother anybody any more. CentOS CI is taken care of by @mrc0mmand, Semaphore was turned into something useful by @martinpitt recenlty and Ubuntu CI, well, it's more or less fine as long as it isn't ignored and the maintainers are notified of any weirdness happening there so I don't know why anybody would ignore the CI now.

@keszybz keszybz deleted the fuzzer-fixes-n branch March 20, 2019 12:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fuzzing Implementation of fuzzers and fixes for stuff found through fuzzing
Development

Successfully merging this pull request may close these issues.

None yet

3 participants