parent
e029aae1d3
commit
df3f53bd5c
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# I'm not sure how to make maximum use of this invention
|
||||||
|
# Make sure to have llvm-symbolizer installed
|
||||||
|
clang -g -fsanitize=address,undefined,fuzzer -fno-sanitize-recover=all \
|
||||||
|
tests/fuzz.c -o fuzz-executor
|
||||||
|
|
||||||
|
fuzz () {
|
||||||
|
echo "`tput bold`-- Fuzzing $1`tput sgr0`"
|
||||||
|
mkdir -p /tmp/corpus-$1
|
||||||
|
./fuzz-executor -test=$1 -artifact_prefix=$1- \
|
||||||
|
-max_len=32 -max_total_time=600 -timeout=1 /tmp/corpus-$1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
for test in "$@"; do fuzz $test; done
|
||||||
|
else
|
||||||
|
for test in $(./fuzz-executor); do fuzz $test; done
|
||||||
|
fi
|
|
@ -0,0 +1,210 @@
|
||||||
|
/*
|
||||||
|
* tests/fuzz.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020, Přemysl Eric Janouch <p@janouch.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PROGRAM_NAME "fuzz"
|
||||||
|
#define PROGRAM_VERSION "0"
|
||||||
|
|
||||||
|
#define LIBERTY_WANT_SSL
|
||||||
|
// The MPD client is a full wrapper and needs the network
|
||||||
|
#define LIBERTY_WANT_POLLER
|
||||||
|
#define LIBERTY_WANT_ASYNC
|
||||||
|
|
||||||
|
#define LIBERTY_WANT_PROTO_IRC
|
||||||
|
#define LIBERTY_WANT_PROTO_HTTP
|
||||||
|
#define LIBERTY_WANT_PROTO_SCGI
|
||||||
|
#define LIBERTY_WANT_PROTO_FASTCGI
|
||||||
|
#define LIBERTY_WANT_PROTO_WS
|
||||||
|
#define LIBERTY_WANT_PROTO_MPD
|
||||||
|
|
||||||
|
#include "../liberty.c"
|
||||||
|
|
||||||
|
// --- UTF-8 -------------------------------------------------------------------
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_utf8_validate (const uint8_t *data, size_t size)
|
||||||
|
{
|
||||||
|
utf8_validate ((const char *) data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Base 64 -----------------------------------------------------------------
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_base64_decode (const uint8_t *data, size_t size)
|
||||||
|
{
|
||||||
|
struct str out = str_make ();
|
||||||
|
base64_decode ((const char *) data, size, &out);
|
||||||
|
str_free (&out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- IRC ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_irc_parse_message (const uint8_t *data, size_t size)
|
||||||
|
{
|
||||||
|
struct str wrap = str_make ();
|
||||||
|
str_append_data (&wrap, data, size);
|
||||||
|
|
||||||
|
struct irc_message msg;
|
||||||
|
irc_parse_message (&msg, wrap.str);
|
||||||
|
irc_free_message (&msg);
|
||||||
|
|
||||||
|
str_free (&wrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- HTTP --------------------------------------------------------------------
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_http_parse_media_type (const uint8_t *data, size_t size)
|
||||||
|
{
|
||||||
|
struct str wrap = str_make ();
|
||||||
|
str_append_data (&wrap, data, size);
|
||||||
|
|
||||||
|
char *type = NULL;
|
||||||
|
char *subtype = NULL;
|
||||||
|
struct str_map parameters = str_map_make (free);
|
||||||
|
http_parse_media_type (wrap.str, &type, &subtype, ¶meters);
|
||||||
|
free (type);
|
||||||
|
free (subtype);
|
||||||
|
str_map_free (¶meters);
|
||||||
|
|
||||||
|
str_free (&wrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_http_parse_upgrade (const uint8_t *data, size_t size)
|
||||||
|
{
|
||||||
|
struct str wrap = str_make ();
|
||||||
|
str_append_data (&wrap, data, size);
|
||||||
|
|
||||||
|
struct http_protocol *protocols = NULL;
|
||||||
|
http_parse_upgrade (wrap.str, &protocols);
|
||||||
|
LIST_FOR_EACH (struct http_protocol, iter, protocols)
|
||||||
|
http_protocol_destroy (iter);
|
||||||
|
|
||||||
|
str_free (&wrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- SCGI --------------------------------------------------------------------
|
||||||
|
|
||||||
|
static bool
|
||||||
|
test_scgi_parser_on_headers_read (void *user_data)
|
||||||
|
{
|
||||||
|
(void) user_data;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
test_scgi_parser_on_content (void *user_data, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
(void) user_data;
|
||||||
|
(void) data;
|
||||||
|
(void) len;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_scgi_parser_push (const uint8_t *data, size_t size)
|
||||||
|
{
|
||||||
|
struct scgi_parser parser = scgi_parser_make ();
|
||||||
|
parser.on_headers_read = test_scgi_parser_on_headers_read;
|
||||||
|
parser.on_content = test_scgi_parser_on_content;
|
||||||
|
|
||||||
|
scgi_parser_push (&parser, data, size, NULL);
|
||||||
|
scgi_parser_free (&parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- WebSockets --------------------------------------------------------------
|
||||||
|
|
||||||
|
static bool
|
||||||
|
test_websockets_on_frame_header (void *user_data, const struct ws_parser *self)
|
||||||
|
{
|
||||||
|
(void) user_data;
|
||||||
|
(void) self;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
test_websockets_on_frame (void *user_data, const struct ws_parser *self)
|
||||||
|
{
|
||||||
|
(void) user_data;
|
||||||
|
(void) self;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_ws_parser_push (const uint8_t *data, size_t size)
|
||||||
|
{
|
||||||
|
struct ws_parser parser = ws_parser_make ();
|
||||||
|
parser.on_frame_header = test_websockets_on_frame_header;
|
||||||
|
parser.on_frame = test_websockets_on_frame;
|
||||||
|
|
||||||
|
ws_parser_push (&parser, data, size);
|
||||||
|
ws_parser_free (&parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Main --------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef void (*fuzz_test_fn) (const uint8_t *data, size_t size);
|
||||||
|
static fuzz_test_fn generator = NULL;
|
||||||
|
|
||||||
|
void
|
||||||
|
LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
|
||||||
|
{
|
||||||
|
generator (data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LLVMFuzzerInitialize (int *argcp, char ***argvp)
|
||||||
|
{
|
||||||
|
struct str_map targets = str_map_make (NULL);
|
||||||
|
#define REGISTER(name) str_map_set (&targets, #name, test_ ## name);
|
||||||
|
REGISTER (utf8_validate)
|
||||||
|
REGISTER (base64_decode)
|
||||||
|
REGISTER (irc_parse_message)
|
||||||
|
REGISTER (http_parse_media_type)
|
||||||
|
REGISTER (http_parse_upgrade)
|
||||||
|
REGISTER (scgi_parser_push)
|
||||||
|
REGISTER (ws_parser_push)
|
||||||
|
// TODO: add more parsers/processors
|
||||||
|
|
||||||
|
char **argv = *argvp, *option = "-test=", *name = NULL;
|
||||||
|
for (int i = 1; i < *argcp; i++)
|
||||||
|
if (!strncmp (argv[i], option, strlen (option)))
|
||||||
|
{
|
||||||
|
name = argv[i] + strlen (option);
|
||||||
|
memmove (argv + i, argv + i + 1, (*argcp - i) * sizeof *argv);
|
||||||
|
(*argcp)--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
struct str_map_iter iter = str_map_iter_make (&targets);
|
||||||
|
while (str_map_iter_next (&iter))
|
||||||
|
printf ("%s\n", iter.link->key);
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(generator = str_map_find (&targets, name)))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Unknown test: %s\n", name);
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
str_map_free (&targets);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -77,7 +77,7 @@ test_irc (void)
|
||||||
static void
|
static void
|
||||||
test_http_parser (void)
|
test_http_parser (void)
|
||||||
{
|
{
|
||||||
struct str_map parameters = str_map_make (NULL);
|
struct str_map parameters = str_map_make (free);
|
||||||
parameters.key_xfrm = tolower_ascii_strxfrm;
|
parameters.key_xfrm = tolower_ascii_strxfrm;
|
||||||
|
|
||||||
char *type = NULL;
|
char *type = NULL;
|
||||||
|
@ -88,9 +88,11 @@ test_http_parser (void)
|
||||||
soft_assert (!strcasecmp_ascii (subtype, "html"));
|
soft_assert (!strcasecmp_ascii (subtype, "html"));
|
||||||
soft_assert (parameters.len == 1);
|
soft_assert (parameters.len == 1);
|
||||||
soft_assert (!strcmp (str_map_find (¶meters, "charset"), "utf-8"));
|
soft_assert (!strcmp (str_map_find (¶meters, "charset"), "utf-8"));
|
||||||
|
free (type);
|
||||||
|
free (subtype);
|
||||||
str_map_free (¶meters);
|
str_map_free (¶meters);
|
||||||
|
|
||||||
struct http_protocol *protocols;
|
struct http_protocol *protocols = NULL;
|
||||||
soft_assert (http_parse_upgrade ("websocket, HTTP/2.0, , ", &protocols));
|
soft_assert (http_parse_upgrade ("websocket, HTTP/2.0, , ", &protocols));
|
||||||
|
|
||||||
soft_assert (!strcmp (protocols->name, "websocket"));
|
soft_assert (!strcmp (protocols->name, "websocket"));
|
||||||
|
|
Loading…
Reference in New Issue