Add a fuzzer for the http used in our directory protocol

(Teor wrote the code, nick extracted it.  It won't compile yet.)
This commit is contained in:
teor 2016-12-13 19:16:03 -05:00 committed by Nick Mathewson
parent b96c70d668
commit a967d568dc

174
src/test/fuzz/fuzz_http.c Normal file
View File

@ -0,0 +1,174 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define BUFFERS_PRIVATE
#include "or.h"
#include "backtrace.h"
#include "buffers.h"
#include "config.h"
#include "connection.h"
#include "directory.h"
#include "torlog.h"
/* Silence compiler warnings about a missing extern */
extern const char tor_git_revision[];
const char tor_git_revision[] = "";
#define MAX_FUZZ_SIZE (2*MAX_HEADERS_SIZE + MAX_DIR_UL_SIZE)
static int mock_get_options_calls = 0;
static or_options_t *mock_options = NULL;
static void
reset_options(or_options_t *options, int *get_options_calls)
{
memset(options, 0, sizeof(or_options_t));
options->TestingTorNetwork = 1;
*get_options_calls = 0;
}
static const or_options_t*
mock_get_options(void)
{
++mock_get_options_calls;
tor_assert(mock_options);
return mock_options;
}
static void
mock_connection_write_to_buf_impl_(const char *string, size_t len,
connection_t *conn, int zlib)
{
log_debug(LD_GENERAL, "%sResponse:\n%zu\nConnection: %p\n%s\n",
zlib ? "Compressed " : "", len, conn, string);
}
/* Read a directory command (including HTTP headers) from stdin, parse it, and
* output what tor parsed */
int
main(int c, char** v)
{
/* Disable logging by default to speed up fuzzing. */
int loglevel = LOG_ERR;
/* Initialise logging first */
init_logging(1);
configure_backtrace_handler(get_version());
for (int i = 1; i < c; ++i) {
if (!strcmp(v[i], "--warn")) {
loglevel = LOG_WARN;
} else if (!strcmp(v[i], "--notice")) {
loglevel = LOG_NOTICE;
} else if (!strcmp(v[i], "--info")) {
loglevel = LOG_INFO;
} else if (!strcmp(v[i], "--debug")) {
loglevel = LOG_DEBUG;
}
}
{
log_severity_list_t s;
memset(&s, 0, sizeof(s));
set_log_severity_config(loglevel, LOG_ERR, &s);
/* ALWAYS log bug warnings. */
s.masks[LOG_WARN-LOG_ERR] |= LD_BUG;
add_stream_log(&s, "", fileno(stdout));
}
/* Make BUG() and nonfatal asserts crash */
tor_set_failed_assertion_callback(abort);
/* Set up fake variables */
dir_connection_t dir_conn;
int rv = -1;
ssize_t data_size = -1;
char *stdin_buf = tor_malloc(MAX_FUZZ_SIZE+1);
/* directory_handle_command checks some tor options
* just make them all 0 */
mock_options = tor_malloc(sizeof(or_options_t));
reset_options(mock_options, &mock_get_options_calls);
MOCK(get_options, mock_get_options);
/* Set up the fake connection */
memset(&dir_conn, 0, sizeof(dir_connection_t));
dir_conn.base_.type = CONN_TYPE_DIR;
/* Set up fake response handler */
MOCK(connection_write_to_buf_impl_, mock_connection_write_to_buf_impl_);
/*
afl extension - loop and reset state after parsing
likely needs to reset the allocation data structures and counts as well
#ifdef __AFL_HAVE_MANUAL_CONTROL
while (__AFL_LOOP(1000)) {
#endif
*/
/* Initialise the data structures */
memset(stdin_buf, 0, MAX_FUZZ_SIZE+1);
/* Apparently tor sets this before directory_handle_command() is called. */
dir_conn.base_.address = tor_strdup("replace-this-address.example.com");
#ifdef __AFL_HAVE_MANUAL_CONTROL
/* Tell AFL to pause and fork here - ignored if not using AFL */
__AFL_INIT();
#endif
/* Read the data */
data_size = read(STDIN_FILENO, stdin_buf, MAX_FUZZ_SIZE);
tor_assert(data_size != -1);
tor_assert(data_size <= MAX_FUZZ_SIZE);
stdin_buf[data_size] = '\0';
tor_assert(strlen(stdin_buf) >= 0);
tor_assert(strlen(stdin_buf) <= MAX_FUZZ_SIZE);
log_debug(LD_GENERAL, "Input-Length:\n%zu\n", data_size);
log_debug(LD_GENERAL, "Input:\n%s\n", stdin_buf);
/* Copy the stdin data into the buffer */
tor_assert(data_size >= 0);
dir_conn.base_.inbuf = buf_new_with_data(stdin_buf, (size_t)data_size);
if (!dir_conn.base_.inbuf) {
log_debug(LD_GENERAL, "Zero-Length-Input\n");
return 0;
}
/* Parse the headers */
rv = directory_handle_command(&dir_conn);
/* TODO: check the output is correctly parsed based on the input */
/* Report the parsed origin address */
if (dir_conn.base_.address) {
log_debug(LD_GENERAL, "Address:\n%s\n", dir_conn.base_.address);
}
log_debug(LD_GENERAL, "Result:\n%d\n", rv);
/* Reset */
tor_free(dir_conn.base_.address);
buf_free(dir_conn.base_.inbuf);
dir_conn.base_.inbuf = NULL;
/*
#ifdef __AFL_HAVE_MANUAL_CONTROL
}
#endif
*/
/* Cleanup */
tor_free(mock_options);
UNMOCK(get_options);
UNMOCK(connection_write_to_buf_impl_);
tor_free(stdin_buf);
}