Merge branch 'glib' into 'master'

Integrate oss-fuzz targets

Closes #1471

See merge request GNOME/glib!371
This commit is contained in:
Philip Withnall 2018-10-11 00:02:03 +00:00
commit 7ec354d1d6
13 changed files with 268 additions and 0 deletions

49
fuzzing/README.md Normal file
View File

@ -0,0 +1,49 @@
Fuzz targets used by [oss-fuzz](https://github.com/google/oss-fuzz/).
## How to add new targets
Add **fuzz_target_name.c** and edit `meson.build` accordingly.
New targets are picked up by oss-fuzz automatically within a day. Targets must not be renamed once added.
Add (optional) **fuzz_target_name.dict** containing keywords and magic bytes.
Add (optional) **fuzz_target_name.corpus** with file names on separate lines. Wildcards `?`, `*` and `**` are supported. Examples below.
```bash
glib/* # all files in directory glib
glib/** # all files in directory glib and sub-directories
**.xbel # all files ending with .xbel in the repository
```
Recommended reading: [Fuzz Target](https://llvm.org/docs/LibFuzzer.html#fuzz-target), [Dictionaries](https://llvm.org/docs/LibFuzzer.html#dictionaries), [Corpus](https://llvm.org/docs/LibFuzzer.html#corpus)
## How to reproduce oss-fuzz bugs locally
Build with at least the following flags, choosing a sanitizer as needed. A somewhat recent version of [clang](http://clang.llvm.org/) is recommended.
```bash
$ CC=clang CXX=clang++ meson DIR -Db_sanitize=<address|undefined> -Db_lundef=false
```
Afterwards run the affected target against the provided test case.
```bash
$ DIR/fuzzing/fuzz_target_name FILE
```
#### FAQs
###### What about Memory Sanitizer (MSAN)?
Correct MSAN instrumentation is [difficult to achieve](https://clang.llvm.org/docs/MemorySanitizer.html#handling-external-code) locally, so false positives are very likely to mask the actual bug.
If need be, [you can still reproduce](https://github.com/google/oss-fuzz/blob/master/docs/reproducing.md#building-using-docker) those bugs with the oss-fuzz provided docker images.
###### There are no file/function names in the stack trace.
`llvm-symbolizer` must be in `PATH`.
###### UndefinedBehavior Sanitizer (UBSAN) doesn't provide a stack trace.
Set environment variable `UBSAN_OPTIONS` to `print_stacktrace=1` prior to running the target.

32
fuzzing/driver.c Normal file
View File

@ -0,0 +1,32 @@
/* Simpler gnu89 version of StandaloneFuzzTargetMain.c from LLVM */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
extern int LLVMFuzzerTestOneInput (const unsigned char *data, size_t size);
int
main (int argc, char **argv)
{
FILE *f;
size_t n_read, len;
unsigned char *buf;
if (argc < 2)
return 1;
f = fopen (argv[1], "r");
assert (f);
fseek (f, 0, SEEK_END);
len = ftell (f);
fseek (f, 0, SEEK_SET);
buf = (unsigned char*) malloc (len);
n_read = fread (buf, 1, len, f);
assert (n_read == len);
LLVMFuzzerTestOneInput (buf, len);
free (buf);
printf ("Done!\n");
return 0;
}

22
fuzzing/fuzz.h Normal file
View File

@ -0,0 +1,22 @@
#include "gio/gio.h"
#include "glib/glib.h"
int LLVMFuzzerTestOneInput (const unsigned char *data, size_t size);
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
static GLogWriterOutput
empty_logging_func (GLogLevelFlags log_level, const GLogField *fields,
gsize n_fields, gpointer user_data)
{
return G_LOG_WRITER_HANDLED;
}
#endif
/* Disables logging for oss-fuzz. Must be used with each target. */
static void
fuzz_set_logging_func (void)
{
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
g_log_set_writer_func (empty_logging_func, NULL, NULL);
#endif
}

15
fuzzing/fuzz_bookmark.c Normal file
View File

@ -0,0 +1,15 @@
#include "fuzz.h"
int
LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
{
GBookmarkFile *bookmark = NULL;
fuzz_set_logging_func ();
bookmark = g_bookmark_file_new ();
g_bookmark_file_load_from_data (bookmark, (const gchar*) data, size, NULL);
g_bookmark_file_free (bookmark);
return 0;
}

View File

@ -0,0 +1 @@
glib/tests/**.xbel

View File

@ -0,0 +1,28 @@
#include "fuzz.h"
const static GDBusCapabilityFlags flags = G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING;
int
LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
{
gssize bytes;
GDBusMessage *msg = NULL;
guchar *blob = NULL;
gsize msg_size;
fuzz_set_logging_func ();
bytes = g_dbus_message_bytes_needed ((guchar*) data, size, NULL);
if (bytes <= 0)
return 0;
msg = g_dbus_message_new_from_blob ((guchar*) data, size, flags, NULL);
if (msg == NULL)
return 0;
blob = g_dbus_message_to_blob (msg, &msg_size, flags, NULL);
g_free (blob);
g_object_unref (msg);
return 0;
}

16
fuzzing/fuzz_key.c Normal file
View File

@ -0,0 +1,16 @@
#include "fuzz.h"
int
LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
{
GKeyFile *key = NULL;
fuzz_set_logging_func ();
key = g_key_file_new ();
g_key_file_load_from_data (key, (const gchar*) data, size, G_KEY_FILE_NONE,
NULL);
g_key_file_free (key);
return 0;
}

2
fuzzing/fuzz_key.corpus Normal file
View File

@ -0,0 +1,2 @@
glib/tests/**.ini
gio/tests/**.desktop

View File

@ -0,0 +1,21 @@
#include "fuzz.h"
int
LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
{
GVariant *variant = NULL, *normal_variant = NULL;
fuzz_set_logging_func ();
variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size, FALSE,
NULL, NULL);
if (variant == NULL)
return 0;
normal_variant = g_variant_take_ref (g_variant_get_normal_form (variant));
g_variant_get_data (variant);
g_variant_unref (normal_variant);
g_variant_unref (variant);
return 0;
}

View File

@ -0,0 +1,21 @@
#include "fuzz.h"
int
LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
{
const gchar *gdata = (const gchar*) data;
GVariant *variant = NULL;
gchar *text = NULL;
fuzz_set_logging_func ();
variant = g_variant_parse (NULL, gdata, gdata + size, NULL, NULL);
if (variant == NULL)
return 0;
text = g_variant_print (variant, TRUE);
g_free (text);
g_variant_unref (variant);
return 0;
}

View File

@ -0,0 +1,32 @@
"'"
"\""
"("
")"
"<"
">"
"["
"]"
"{"
"}"
"*"
"?"
"@"
"b'"
"b\""
"boolean"
"byte"
"double"
"false"
"handle"
"int16"
"int32"
"int64"
"just"
"nothing"
"objectpath"
"signature"
"string"
"true"
"uint16"
"uint32"
"uint64"

28
fuzzing/meson.build Normal file
View File

@ -0,0 +1,28 @@
fuzz_targets = [
'fuzz_bookmark',
'fuzz_dbus_message',
'fuzz_key',
'fuzz_variant_binary',
'fuzz_variant_text',
]
deps = [libgmodule_dep, libgio_dep, libglib_dep, libgobject_dep]
extra_sources = []
extra_c_args = cc.get_supported_arguments('-Werror=unused-function')
# Links in a static library provided by oss-fuzz, else a standalone driver.
# https://github.com/google/oss-fuzz/blob/master/docs/new_project_guide.md#buildsh-script-environment
fuzzing_engine = cxx.find_library('FuzzingEngine', required : false)
if fuzzing_engine.found()
deps += fuzzing_engine
else
extra_sources += 'driver.c'
endif
foreach target_name : fuzz_targets
exe = executable(target_name, [extra_sources, target_name + '.c'],
c_args : extra_c_args,
dependencies : deps,
)
endforeach

View File

@ -1980,6 +1980,7 @@ subdir('gio')
if xgettext.found()
subdir('po')
endif
subdir('fuzzing')
subdir('tests')
# Install glib-gettextize executable, if a UNIX-style shell is found