Add basic fuzzers

To compile:
  * CXX=clang++ meson build
  * ninja -C build fuzzer-xml fuzzer-uri

These fuzzers use libFuzzer and asan support in clang 10 or later to
fuzz the XML parsing and http_uri functions.  They aren't very thorough
(yet), but demonstrate the basic technique.
This commit is contained in:
Benjamin Gordon
2020-10-30 17:01:36 -06:00
parent d59044aee6
commit 4313f0de62
4 changed files with 144 additions and 1 deletions
+16
View File
@@ -0,0 +1,16 @@
The `fuzzer` directory contains several fuzz targets that make use of asan and
[libFuzzer](https://llvm.org/docs/LibFuzzer.html) from clang 10 or later to test
functions that are expected to process untrusted inputs.
To build:
```
CXX=clang++-10 meson build
ninja -C build fuzzer-$name
```
where `$name` can be any of the files in the `fuzzer` directory.
You can then run the fuzzer as `build/fuzzer-$name`. The basic mode will run
indefinitely until a problem is found. Pass `-help=1` to see additional fuzzer
options.
+74
View File
@@ -0,0 +1,74 @@
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// See LICENSE for license terms and conditions.
#include <fuzzer/FuzzedDataProvider.h>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include "airscan.h"
constexpr int kMaxInputSize = 32 * 1024;
namespace {
struct LogWrapper {
LogWrapper() { log_init(); }
~LogWrapper() { log_cleanup(); }
};
} // namespace
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Limit fuzzer input size to 32KB. URLs technically don't have a limit, but
// practical sizes found in real life will be under 4KB. This gives us a
// buffer to test longer URLs without wasting time on huge inputs.
if (size > kMaxInputSize) {
return 0;
}
FuzzedDataProvider data_provider(data, size);
std::string str_input = data_provider.ConsumeRemainingBytesAsString();
LogWrapper log;
http_uri *uri1 = http_uri_new(str_input.c_str(), true);
if (uri1 == NULL) {
return 0;
}
http_uri_free(uri1);
uri1 = http_uri_new(str_input.c_str(), false);
if (uri1 == NULL) {
return 0;
}
http_uri *uri2 = http_uri_clone(uri1);
if (uri2 == NULL) {
http_uri_free(uri1);
return 0;
}
http_uri_free(uri2);
const char *str = http_uri_str(uri1);
uri2 = http_uri_new(str, true);
if (uri2 == NULL) {
http_uri_free(uri1);
return 0;
}
http_uri_free(uri2);
const char *path = http_uri_get_path(uri1);
uri2 = http_uri_new_relative(uri1, path, false, false);
if (uri2 == NULL) {
http_uri_free(uri1);
return 0;
}
http_uri_free(uri2);
http_uri_fix_end_slash(uri1);
http_uri_free(uri1);
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// See LICENSE for license terms and conditions.
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <libxml/xmlerror.h>
#include "airscan.h"
void noerrs(void *ctx, const char*msg, ...) {
// Ignore the libxml error messages.
}
constexpr int kMaxInputSize = 32 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Limit fuzzer input size to 32KB. libxml can take a very long time to
// parse very large inputs, which causes the fuzzer to time out.
if (size > kMaxInputSize) {
return 0;
}
xmlSetGenericErrorFunc(NULL, noerrs);
xml_rd *xml = NULL;
if (xml_rd_begin(&xml, (const char*)data, size, NULL)) {
return 0;
}
if (xml == NULL) {
return 0;
}
while (!xml_rd_end(xml)) {
xml_rd_deep_next(xml, 0);
}
xml_rd_finish(&xml);
return 0;
}
+12 -1
View File
@@ -1,4 +1,4 @@
project('sane-airscan', 'c')
project('sane-airscan', 'c', 'cpp')
sources = [
'airscan-array.c',
@@ -76,6 +76,17 @@ dll_file = configure_file(
copy: true
)
foreach fuzzer : ['uri', 'xml']
executable(
'fuzzer-' + fuzzer,
sources + ['fuzzer/@0@.cc'.format(fuzzer)],
dependencies: shared_deps,
build_by_default: false,
cpp_args: ['-fsanitize=address', '-fsanitize=fuzzer-no-link'],
link_args: ['-fsanitize=address', '-fsanitize=fuzzer']
)
endforeach
install_man('sane-airscan.5')
install_man('airscan-discover.1')
install_data('airscan.conf',