Merge branch 'combined-fuzzing-v4'

This commit is contained in:
Nick Mathewson 2017-01-30 08:40:46 -05:00
commit 558c04f5b1
42 changed files with 1588 additions and 63 deletions

4
.gitignore vendored
View File

@ -192,6 +192,10 @@ uptime-*.json
/src/test/test-timers.exe
/src/test/test_workqueue.exe
# /src/test/fuzz
/src/test/fuzz/fuzz-*
/src/test/fuzz/lf-fuzz-*
# /src/tools/
/src/tools/tor-checkkey
/src/tools/tor-resolve

View File

@ -9,6 +9,7 @@ noinst_LIBRARIES=
EXTRA_DIST=
noinst_HEADERS=
bin_PROGRAMS=
EXTRA_PROGRAMS=
CLEANFILES=
TESTS=
noinst_PROGRAMS=
@ -54,6 +55,11 @@ TEST_CPPFLAGS=-DTOR_UNIT_TESTS
TEST_NETWORK_FLAGS=--hs-multi-client 1
endif
if LIBFUZZER_ENABLED
TEST_CFLAGS += -fsanitize-coverage=trace-pc-guard,trace-cmp,trace-div
# not "edge"
endif
TEST_NETWORK_ALL_LOG_DIR=$(top_builddir)/test_network_log
TEST_NETWORK_ALL_DRIVER_FLAGS=--color-tests yes
@ -189,6 +195,7 @@ if USE_PERL
$(top_srcdir)/src/common/*.[ch] \
$(top_srcdir)/src/or/*.[ch] \
$(top_srcdir)/src/test/*.[ch] \
$(top_srcdir)/src/test/*/*.[ch] \
$(top_srcdir)/src/tools/*.[ch]
endif

View File

@ -49,6 +49,10 @@ AC_ARG_ENABLE(asserts-in-tests,
AS_HELP_STRING(--disable-asserts-in-tests, [disable tor_assert() calls in the unit tests, for branch coverage]))
AC_ARG_ENABLE(system-torrc,
AS_HELP_STRING(--disable-system-torrc, [don't look for a system-wide torrc file]))
AC_ARG_ENABLE(libfuzzer,
AS_HELP_STRING(--enable-libfuzzer, [build extra fuzzers based on 'libfuzzer']))
AC_ARG_ENABLE(oss-fuzz,
AS_HELP_STRING(--enable-oss-fuzz, [build extra fuzzers based on 'oss-fuzz' environment]))
if test "x$enable_coverage" != "xyes" -a "x$enable_asserts_in_tests" = "xno" ; then
AC_MSG_ERROR([Can't disable assertions outside of coverage build])
@ -57,6 +61,8 @@ fi
AM_CONDITIONAL(UNITTESTS_ENABLED, test "x$enable_unittests" != "xno")
AM_CONDITIONAL(COVERAGE_ENABLED, test "x$enable_coverage" = "xyes")
AM_CONDITIONAL(DISABLE_ASSERTS_IN_UNIT_TESTS, test "x$enable_asserts_in_tests" = "xno")
AM_CONDITIONAL(LIBFUZZER_ENABLED, test "x$enable_libfuzzer" = "xyes")
AM_CONDITIONAL(OSS_FUZZ_ENABLED, test "x$enable_oss_fuzz" = "xyes")
if test "$enable_static_tor" = "yes"; then
enable_static_libevent="yes";
@ -735,6 +741,7 @@ CFLAGS_FWRAPV=
CFLAGS_ASAN=
CFLAGS_UBSAN=
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
#if !defined(__clang__)
#error
@ -758,7 +765,7 @@ m4_ifdef([AS_VAR_IF],[
AS_VAR_POPDEF([can_compile])
TOR_CHECK_CFLAGS(-Wstack-protector)
TOR_CHECK_CFLAGS(--param ssp-buffer-size=1)
if test "$bwin32" = "false"; then
if test "$bwin32" = "false" && test "$enable_libfuzzer" != "yes" && test "$enable_oss_fuzz" != "yes"; then
TOR_CHECK_CFLAGS(-fPIE)
TOR_CHECK_LDFLAGS(-pie, "$all_ldflags_for_check", "$all_libs_for_check")
fi

120
doc/HACKING/Fuzzing.md Normal file
View File

@ -0,0 +1,120 @@
= Fuzzing Tor
== The simple version (no fuzzing, only tests)
Check out fuzzing-corpora, and set TOR_FUZZ_CORPORA to point to the place
where you checked it out.
To run the fuzzing test cases in a deterministic fashion, use:
make fuzz
== Different kinds of fuzzing
Right now we support three different kinds of fuzzer.
First, there's American Fuzzy Lop (AFL), a fuzzer that works by forking
a target binary and passing it lots of different inputs on stdin. It's the
trickiest one to set up, so I'll be describing it more below.
Second, there's libFuzzer, a llvm-based fuzzer that you link in as a library,
and it runs a target function over and over. To use this one, you'll need to
have a reasonably recent clang and libfuzzer installed. At that point, you
just build with --enable-expensive-hardening and --enable-libfuzzer. That
will produce a set of binaries in src/test/fuzz/lf-fuzz-* . These programs
take as input a series of directories full of fuzzing examples. For more
information on libfuzzer, see http://llvm.org/docs/LibFuzzer.html
Third, there's Google's OSS-Fuzz infrastructure, which expects to get all of
its. For more on this, see https://github.com/google/oss-fuzz and the
projects/tor subdirectory. You'll need to mess around with Docker a bit to
test this one out; it's meant to run on Google's infrastructure.
In all cases, you'll need some starting examples to give the fuzzer when it
starts out. There's a set in the "fuzzing-corpora" git repository. Try
setting TOR_FUZZ_CORPORA to point to a checkout of that repository
== Writing Tor fuzzers
A tor fuzzing harness should have:
* a fuzz_init() function to set up any necessary global state.
* a fuzz_main() function to receive input and pass it to a parser.
* a fuzz_cleanup() function to clear global state.
Most fuzzing frameworks will produce many invalid inputs - a tor fuzzing
harness should rejecting invalid inputs without crashing or behaving badly.
But the fuzzing harness should crash if tor fails an assertion, triggers a
bug, or accesses memory it shouldn't. This helps fuzzing frameworks detect
"interesting" cases.
== Guided Fuzzing with AFL
There is no HTTPS, hash, or signature for American Fuzzy Lop's source code, so
its integrity can't be verified. That said, you really shouldn't fuzz on a
machine you care about, anyway.
To Build:
Get AFL from http://lcamtuf.coredump.cx/afl/ and unpack it
cd afl
make
cd ../tor
PATH=$PATH:../afl/ CC="../afl/afl-gcc" ./configure --enable-expensive-hardening
AFL_HARDEN=1 make clean fuzz
To Find The ASAN Memory Limit: (64-bit only)
On 64-bit platforms, afl needs to know how much memory ASAN uses.
Or, you can configure tor without --enable-expensive-hardening, then use
make fuzz
to run the generated test cases through an ASAN-enabled fuzz-http.
Read afl/docs/notes_for_asan.txt for more details.
Download recidivm from http://jwilk.net/software/recidivm
Download the signature
Check the signature
tar xvzf recidivm*.tar.gz
cd recidivm*
make
/path/to/recidivm -v src/test/fuzz_dir
Use the final "ok" figure as the input to -m when calling afl-fuzz
(Normally, recidivm would output a figure automatically, but in some cases,
the fuzzing harness will hang when the memory limit is too small.)
You could also just say "none" instead of the memory limit below, if you
don't care about memory limits.
To Run:
mkdir -p src/test/fuzz/fuzz_http_findings
../afl/afl-fuzz -i ${TOR_FUZZ_CORPORA}/http -o src/test/fuzz/fuzz_http_findings -m <asan-memory-limit> -- src/test/fuzz_dir
AFL has a multi-core mode, check the documentation for details.
You might find the included fuzz-multi.sh script useful for this.
macOS (OS X) requires slightly more preparation, including:
* using afl-clang (or afl-clang-fast from the llvm directory)
* disabling external crash reporting (AFL will guide you through this step)
== Triaging Issues
Crashes are usually interesting, particularly if using AFL_HARDEN=1 and --enable-expensive-hardening. Sometimes crashes are due to bugs in the harness code.
Hangs might be interesting, but they might also be spurious machine slowdowns.
Check if a hang is reproducible before reporting it. Sometimes, processing
valid inputs may take a second or so, particularly with the fuzzer and
sanitizers enabled.
To see what fuzz-http is doing with a test case, call it like this:
src/test/fuzz/fuzz-http --debug < /path/to/test.case
(Logging is disabled while fuzzing to increase fuzzing speed.)
== Reporting Issues
Please report any issues discovered using the process in Tor's security issue
policy:
https://trac.torproject.org/projects/tor/wiki/org/meetings/2016SummerDevMeeting/Notes/SecurityIssuePolicy

View File

@ -1107,10 +1107,10 @@ crypto_pk_private_decrypt(crypto_pk_t *env, char *to,
* <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be
* at least the length of the modulus of <b>env</b>.
*/
int
crypto_pk_public_checksig(const crypto_pk_t *env, char *to,
size_t tolen,
const char *from, size_t fromlen)
MOCK_IMPL(int,
crypto_pk_public_checksig,(const crypto_pk_t *env, char *to,
size_t tolen,
const char *from, size_t fromlen))
{
int r;
tor_assert(env);
@ -1134,9 +1134,10 @@ crypto_pk_public_checksig(const crypto_pk_t *env, char *to,
* in <b>env</b>. Return 0 if <b>sig</b> is a correct signature for
* SHA1(data). Else return -1.
*/
int
crypto_pk_public_checksig_digest(crypto_pk_t *env, const char *data,
size_t datalen, const char *sig, size_t siglen)
MOCK_IMPL(int,
crypto_pk_public_checksig_digest,(crypto_pk_t *env, const char *data,
size_t datalen, const char *sig,
size_t siglen))
{
char digest[DIGEST_LEN];
char *buf;

View File

@ -180,10 +180,12 @@ int crypto_pk_public_encrypt(crypto_pk_t *env, char *to, size_t tolen,
int crypto_pk_private_decrypt(crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen,
int padding, int warnOnFailure);
int crypto_pk_public_checksig(const crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen);
int crypto_pk_public_checksig_digest(crypto_pk_t *env, const char *data,
size_t datalen, const char *sig, size_t siglen);
MOCK_DECL(int, crypto_pk_public_checksig,(const crypto_pk_t *env,
char *to, size_t tolen,
const char *from, size_t fromlen));
MOCK_DECL(int, crypto_pk_public_checksig_digest,(crypto_pk_t *env,
const char *data, size_t datalen,
const char *sig, size_t siglen));
int crypto_pk_private_sign(const crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen);
int crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen,

View File

@ -15,6 +15,7 @@
* keys to and from the corresponding Curve25519 keys.
*/
#define CRYPTO_ED25519_PRIVATE
#include "orconfig.h"
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
@ -34,7 +35,6 @@
#include <openssl/sha.h>
static void pick_ed25519_impl(void);
static int ed25519_impl_spot_check(void);
/** An Ed25519 implementation, as a set of function pointers. */
typedef struct {
@ -308,10 +308,10 @@ ed25519_sign_prefixed,(ed25519_signature_t *signature_out,
*
* Return 0 if the signature is valid; -1 if it isn't.
*/
int
ed25519_checksig(const ed25519_signature_t *signature,
const uint8_t *msg, size_t len,
const ed25519_public_key_t *pubkey)
MOCK_IMPL(int,
ed25519_checksig,(const ed25519_signature_t *signature,
const uint8_t *msg, size_t len,
const ed25519_public_key_t *pubkey))
{
return
get_ed_impl()->open(signature->sig, msg, len, pubkey->pubkey) < 0 ? -1 : 0;
@ -354,10 +354,10 @@ ed25519_checksig_prefixed(const ed25519_signature_t *signature,
* was valid. Otherwise return -N, where N is the number of invalid
* signatures.
*/
int
ed25519_checksig_batch(int *okay_out,
const ed25519_checkable_t *checkable,
int n_checkable)
MOCK_IMPL(int,
ed25519_checksig_batch,(int *okay_out,
const ed25519_checkable_t *checkable,
int n_checkable))
{
int i, res;
const ed25519_impl_t *impl = get_ed_impl();
@ -642,8 +642,8 @@ ed25519_pubkey_copy(ed25519_public_key_t *dest,
/** Check whether the given Ed25519 implementation seems to be working.
* If so, return 0; otherwise return -1. */
static int
ed25519_impl_spot_check(void)
MOCK_IMPL(STATIC int,
ed25519_impl_spot_check,(void))
{
static const uint8_t alicesk[32] = {
0xc5,0xaa,0x8d,0xf4,0x3f,0x9f,0x83,0x7b,

View File

@ -51,9 +51,9 @@ int ed25519_keypair_generate(ed25519_keypair_t *keypair_out, int extra_strong);
int ed25519_sign(ed25519_signature_t *signature_out,
const uint8_t *msg, size_t len,
const ed25519_keypair_t *key);
int ed25519_checksig(const ed25519_signature_t *signature,
const uint8_t *msg, size_t len,
const ed25519_public_key_t *pubkey);
MOCK_DECL(int,ed25519_checksig,(const ed25519_signature_t *signature,
const uint8_t *msg, size_t len,
const ed25519_public_key_t *pubkey));
MOCK_DECL(int,
ed25519_sign_prefixed,(ed25519_signature_t *signature_out,
@ -84,9 +84,9 @@ typedef struct {
size_t len;
} ed25519_checkable_t;
int ed25519_checksig_batch(int *okay_out,
const ed25519_checkable_t *checkable,
int n_checkable);
MOCK_DECL(int, ed25519_checksig_batch,(int *okay_out,
const ed25519_checkable_t *checkable,
int n_checkable));
int ed25519_keypair_from_curve25519_keypair(ed25519_keypair_t *out,
int *signbit_out,
@ -132,5 +132,9 @@ void crypto_ed25519_testing_force_impl(const char *name);
void crypto_ed25519_testing_restore_impl(void);
#endif
#ifdef CRYPTO_ED25519_PRIVATE
MOCK_DECL(STATIC int, ed25519_impl_spot_check, (void));
#endif
#endif

View File

@ -6,4 +6,4 @@ include src/test/include.am
include src/tools/include.am
include src/win32/include.am
include src/config/include.am
include src/test/fuzz/include.am

View File

@ -281,6 +281,7 @@ buf_pullup(buf_t *buf, size_t bytes)
}
#ifdef TOR_UNIT_TESTS
/* Return the data from the first chunk of buf in cp, and its length in sz. */
void
buf_get_first_chunk_data(const buf_t *buf, const char **cp, size_t *sz)
{
@ -292,6 +293,53 @@ buf_get_first_chunk_data(const buf_t *buf, const char **cp, size_t *sz)
*sz = buf->head->datalen;
}
}
/* Write sz bytes from cp into a newly allocated buffer buf.
* Returns NULL when passed a NULL cp or zero sz.
* Asserts on failure: only for use in unit tests.
* buf must be freed using buf_free(). */
buf_t *
buf_new_with_data(const char *cp, size_t sz)
{
/* Validate arguments */
if (!cp || sz <= 0) {
return NULL;
}
tor_assert(sz < SSIZE_T_CEILING);
/* Allocate a buffer */
buf_t *buf = buf_new_with_capacity(sz);
tor_assert(buf);
assert_buf_ok(buf);
tor_assert(!buf->head);
/* Allocate a chunk that is sz bytes long */
buf->head = chunk_new_with_alloc_size(CHUNK_ALLOC_SIZE(sz));
buf->tail = buf->head;
tor_assert(buf->head);
assert_buf_ok(buf);
tor_assert(buf_allocation(buf) >= sz);
/* Copy the data and size the buffers */
tor_assert(sz <= buf_slack(buf));
tor_assert(sz <= CHUNK_REMAINING_CAPACITY(buf->head));
memcpy(&buf->head->mem[0], cp, sz);
buf->datalen = sz;
buf->head->datalen = sz;
buf->head->data = &buf->head->mem[0];
assert_buf_ok(buf);
/* Make sure everything is large enough */
tor_assert(buf_allocation(buf) >= sz);
tor_assert(buf_allocation(buf) >= buf_datalen(buf) + buf_slack(buf));
/* Does the buffer implementation allocate more than the requested size?
* (for example, by rounding up). If so, these checks will fail. */
tor_assert(buf_datalen(buf) == sz);
tor_assert(buf_slack(buf) == 0);
return buf;
}
#endif
/** Remove the first <b>n</b> bytes from buf. */

View File

@ -64,7 +64,10 @@ void assert_buf_ok(buf_t *buf);
#ifdef BUFFERS_PRIVATE
STATIC int buf_find_string_offset(const buf_t *buf, const char *s, size_t n);
STATIC void buf_pullup(buf_t *buf, size_t bytes);
#ifdef TOR_UNIT_TESTS
void buf_get_first_chunk_data(const buf_t *buf, const char **cp, size_t *sz);
buf_t *buf_new_with_data(const char *cp, size_t sz);
#endif
STATIC size_t preferred_chunk_size(size_t target);
#define DEBUG_CHUNK_ALLOC

View File

@ -14,6 +14,7 @@
#include "connection.h"
#include "connection_edge.h"
#include "control.h"
#define DIRECTORY_PRIVATE
#include "directory.h"
#include "dirserv.h"
#include "dirvote.h"
@ -99,7 +100,6 @@ static void directory_send_command(dir_connection_t *conn,
int purpose, int direct, const char *resource,
const char *payload, size_t payload_len,
time_t if_modified_since);
static int directory_handle_command(dir_connection_t *conn);
static int body_is_plausible(const char *body, size_t body_len, int purpose);
static char *http_get_header(const char *headers, const char *which);
static void http_set_address_origin(const char *headers, connection_t *conn);
@ -2894,9 +2894,9 @@ static const url_table_ent_t url_table[] = {
* conn-\>outbuf. If the request is unrecognized, send a 404.
* Return 0 if we handled this successfully, or -1 if we need to close
* the connection. */
STATIC int
directory_handle_command_get(dir_connection_t *conn, const char *headers,
const char *req_body, size_t req_body_len)
MOCK_IMPL(STATIC int,
directory_handle_command_get,(dir_connection_t *conn, const char *headers,
const char *req_body, size_t req_body_len))
{
char *url, *url_mem, *header;
time_t if_modified_since = 0;
@ -3693,9 +3693,9 @@ handle_post_hs_descriptor(const char *url, const char *body)
* service descriptor. On finding one, process it and write a
* response into conn-\>outbuf. If the request is unrecognized, send a
* 400. Always return 0. */
static int
directory_handle_command_post(dir_connection_t *conn, const char *headers,
const char *body, size_t body_len)
MOCK_IMPL(STATIC int,
directory_handle_command_post,(dir_connection_t *conn, const char *headers,
const char *body, size_t body_len))
{
char *url = NULL;
const or_options_t *options = get_options();
@ -3827,7 +3827,7 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
* from the inbuf, try to process it; otherwise, leave it on the
* buffer. Return a 0 on success, or -1 on error.
*/
static int
STATIC int
directory_handle_command(dir_connection_t *conn)
{
char *headers=NULL, *body=NULL;

View File

@ -148,6 +148,7 @@ int purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose,
struct get_handler_args_t;
STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn,
const struct get_handler_args_t *args);
STATIC int directory_handle_command(dir_connection_t *conn);
#endif
@ -157,10 +158,14 @@ STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn,
STATIC int parse_http_url(const char *headers, char **url);
STATIC dirinfo_type_t dir_fetch_type(int dir_purpose, int router_purpose,
const char *resource);
STATIC int directory_handle_command_get(dir_connection_t *conn,
const char *headers,
const char *req_body,
size_t req_body_len);
MOCK_DECL(STATIC int, directory_handle_command_get,(dir_connection_t *conn,
const char *headers,
const char *req_body,
size_t req_body_len));
MOCK_DECL(STATIC int, directory_handle_command_post,(dir_connection_t *conn,
const char *headers,
const char *body,
size_t body_len));
STATIC int download_status_schedule_get_delay(download_status_t *dls,
const smartlist_t *schedule,
int min_delay, int max_delay,

View File

@ -243,7 +243,7 @@ router_reload_consensus_networkstatus(void)
}
/** Free all storage held by the vote_routerstatus object <b>rs</b>. */
STATIC void
void
vote_routerstatus_free(vote_routerstatus_t *rs)
{
vote_microdesc_hash_t *h, *next;

View File

@ -132,8 +132,9 @@ document_signature_t *document_signature_dup(const document_signature_t *sig);
void networkstatus_free_all(void);
int networkstatus_get_weight_scale_param(networkstatus_t *ns);
void vote_routerstatus_free(vote_routerstatus_t *rs);
#ifdef NETWORKSTATUS_PRIVATE
STATIC void vote_routerstatus_free(vote_routerstatus_t *rs);
#ifdef TOR_UNIT_TESTS
STATIC int networkstatus_set_current_consensus_from_ns(networkstatus_t *c,
const char *flavor);

View File

@ -1210,12 +1210,12 @@ make_tap_onion_key_crosscert(const crypto_pk_t *onion_key,
/** Check whether an RSA-TAP cross-certification is correct. Return 0 if it
* is, -1 if it isn't. */
int
check_tap_onion_key_crosscert(const uint8_t *crosscert,
int crosscert_len,
const crypto_pk_t *onion_pkey,
const ed25519_public_key_t *master_id_pkey,
const uint8_t *rsa_id_digest)
MOCK_IMPL(int,
check_tap_onion_key_crosscert,(const uint8_t *crosscert,
int crosscert_len,
const crypto_pk_t *onion_pkey,
const ed25519_public_key_t *master_id_pkey,
const uint8_t *rsa_id_digest))
{
uint8_t *cc = tor_malloc(crypto_pk_keysize(onion_pkey));
int cc_len =

View File

@ -57,11 +57,11 @@ uint8_t *make_tap_onion_key_crosscert(const crypto_pk_t *onion_key,
const crypto_pk_t *rsa_id_key,
int *len_out);
int check_tap_onion_key_crosscert(const uint8_t *crosscert,
MOCK_DECL(int, check_tap_onion_key_crosscert,(const uint8_t *crosscert,
int crosscert_len,
const crypto_pk_t *onion_pkey,
const ed25519_public_key_t *master_id_pkey,
const uint8_t *rsa_id_digest);
const uint8_t *rsa_id_digest));
int load_ed_keys(const or_options_t *options, time_t now);
int should_make_new_ed_keys(const or_options_t *options, const time_t now);

View File

@ -863,8 +863,8 @@ dump_desc_populate_fifo_from_directory(const char *dirname)
* type *<b>type</b> to file $DATADIR/unparseable-desc. Do not write more
* than one descriptor to disk per minute. If there is already such a
* file in the data directory, overwrite it. */
STATIC void
dump_desc(const char *desc, const char *type)
MOCK_IMPL(STATIC void,
dump_desc,(const char *desc, const char *type))
{
tor_assert(desc);
tor_assert(type);
@ -1172,6 +1172,12 @@ tor_version_is_obsolete(const char *myversion, const char *versionlist)
return ret;
}
MOCK_IMPL(STATIC int,
signed_digest_equals, (const uint8_t *d1, const uint8_t *d2, size_t len))
{
return tor_memeq(d1, d2, len);
}
/** Check whether the object body of the token in <b>tok</b> has a good
* signature for <b>digest</b> using key <b>pkey</b>.
* If <b>CST_NO_CHECK_OBJTYPE</b> is set, do not check
@ -1214,7 +1220,8 @@ check_signature_token(const char *digest,
}
// log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
// hex_str(signed_digest,4));
if (tor_memneq(digest, signed_digest, digest_len)) {
if (! signed_digest_equals((const uint8_t *)digest,
(const uint8_t *)signed_digest, digest_len)) {
log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
tor_free(signed_digest);
return -1;
@ -3704,11 +3711,10 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
if (ns->type != NS_TYPE_CONSENSUS) {
vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
if (routerstatus_parse_entry_from_string(rs_area, &s, rs_tokens, ns,
rs, 0, 0))
rs, 0, 0)) {
smartlist_add(ns->routerstatus_list, rs);
else {
tor_free(rs->version);
tor_free(rs);
} else {
vote_routerstatus_free(rs);
}
} else {
routerstatus_t *rs;
@ -4508,13 +4514,24 @@ router_get_hash_impl(const char *s, size_t s_len, char *digest,
&start,&end)<0)
return -1;
return router_compute_hash_final(digest, start, end-start, alg);
}
/** Compute the digest of the <b>len</b>-byte directory object at
* <b>start</b>, using <b>alg</b>. Store the result in <b>digest</b>, which
* must be long enough to hold it. */
MOCK_IMPL(STATIC int,
router_compute_hash_final,(char *digest,
const char *start, size_t len,
digest_algorithm_t alg))
{
if (alg == DIGEST_SHA1) {
if (crypto_digest(digest, start, end-start) < 0) {
if (crypto_digest(digest, start, len) < 0) {
log_warn(LD_BUG,"couldn't compute digest");
return -1;
}
} else {
if (crypto_digest256(digest, start, end-start, alg) < 0) {
if (crypto_digest256(digest, start, len, alg) < 0) {
log_warn(LD_BUG,"couldn't compute digest");
return -1;
}
@ -4700,11 +4717,13 @@ microdescs_parse_from_string(const char *s, const char *eos,
if (!strcmp(t->args[0], "ed25519")) {
if (md->ed25519_identity_pkey) {
log_warn(LD_DIR, "Extra ed25519 key in microdesc");
smartlist_free(id_lines);
goto next;
}
ed25519_public_key_t k;
if (ed25519_public_from_base64(&k, t->args[1])<0) {
log_warn(LD_DIR, "Bogus ed25519 key in microdesc");
smartlist_free(id_lines);
goto next;
}
md->ed25519_identity_pkey = tor_memdup(&k, sizeof(k));

View File

@ -110,7 +110,6 @@ STATIC int routerstatus_parse_guardfraction(const char *guardfraction_str,
MOCK_DECL(STATIC dumped_desc_t *, dump_desc_populate_one_file,
(const char *dirname, const char *f));
STATIC void dump_desc_populate_fifo_from_directory(const char *dirname);
STATIC void dump_desc(const char *desc, const char *type);
STATIC void dump_desc_fifo_cleanup(void);
struct memarea_t;
STATIC routerstatus_t *routerstatus_parse_entry_from_string(
@ -120,6 +119,12 @@ STATIC routerstatus_t *routerstatus_parse_entry_from_string(
vote_routerstatus_t *vote_rs,
int consensus_method,
consensus_flavor_t flav);
MOCK_DECL(STATIC void,dump_desc,(const char *desc, const char *type));
MOCK_DECL(STATIC int, router_compute_hash_final,(char *digest,
const char *start, size_t len,
digest_algorithm_t alg));
MOCK_DECL(STATIC int, signed_digest_equals,
(const uint8_t *d1, const uint8_t *d2, size_t len));
#endif
#define ED_DESC_SIGNATURE_PREFIX "Tor router descriptor signature v1"

View File

@ -0,0 +1,52 @@
"a"
"additional-digest"
"additional-signature"
"bandwidth-weights"
"client-versions"
"consensus-digest"
"consensus-method"
"consensus-methods"
"contact"
"dir-address"
"directory-footer"
"directory-signature"
"dir-identity-key"
"dir-key-certificate-version"
"dir-key-certification"
"dir-key-crosscert"
"dir-key-expires"
"dir-key-published"
"dir-signing-key"
"dir-source"
"fingerprint"
"fresh-until"
"id"
"known-flags"
"legacy-dir-key"
"m"
"network-status-version"
"opt"
"p"
"package"
"params"
"pr"
"published"
"r"
"recommended-client-protocols"
"recommended-relay-protocols"
"required-client-protocols"
"required-relay-protocols"
"s"
"server-versions"
"shared-rand-commit"
"shared-rand-current-value"
"shared-rand-participate"
"shared-rand-previous-value"
"signing-ed25519"
"v"
"valid-after"
"valid-until"
"vote-digest"
"vote-status"
"voting-delay"
"w"

View File

@ -0,0 +1,41 @@
"reject"
"accept"
"reject6"
"accept6"
"router"
"ipv6-policy"
"signing-key"
"onion-key"
"ntor-onion-key"
"router-signature"
"published"
"uptime"
"fingerprint"
"hibernating"
"platform"
"proto"
"contact"
"read-history"
"write-history"
"extra-info-digest"
"hidden-service-dir"
"identity-ed25519"
"master-key-ed25519"
"router-sig-ed25519"
"onion-key-crosscert"
"ntor-onion-key-crosscert"
"allow-single-hop-exits"
"family"
"caches-extra-info"
"or-address"
"opt"
"bandwidth"
"@purpose"
"tunnelled-dir-server"
"-----BEGIN"
"-----END"
"-----"
"ED25519 CERT"
"RSA PUBLIC KEY"
"CROSSCERT"
"SIGNATURE"

View File

@ -0,0 +1,32 @@
"cell-circuits-per-decile"
"cell-processed-cells"
"cell-queued-cells"
"cell-stats-end"
"cell-time-in-queue"
"dirreq-stats-end"
"dirreq-v2-direct-dl"
"dirreq-v2-ips"
"dirreq-v2-reqs"
"dirreq-v2-resp"
"dirreq-v2-share"
"dirreq-v2-tunneled-dl"
"dirreq-v3-direct-dl"
"dirreq-v3-ips"
"dirreq-v3-reqs"
"dirreq-v3-resp"
"dirreq-v3-share"
"dirreq-v3-tunneled-dl"
"entry-ips"
"entry-stats-end"
"exit-kibibytes-read"
"exit-kibibytes-written"
"exit-stats-end"
"exit-streams-opened"
"extra-info"
"identity-ed25519"
"opt"
"published"
"read-history"
"router-sig-ed25519"
"router-signature"
"write-history"

View File

@ -0,0 +1,8 @@
"introduction-points"
"permanent-key"
"protocol-versions"
"publication-time"
"rendezvous-service-descriptor"
"secret-id-part"
"signature"
"version"

24
src/test/fuzz/dict/http Normal file
View File

@ -0,0 +1,24 @@
#
# AFL dictionary for the Tor Directory protocol's HTTP headers
# ------------------------------------------------------------
#
# Extracted from directory_handle_command() in the tor source code
#
# Copyright (c) 2016, The Tor Project, Inc.
# See LICENSE for licensing information
#
# Usage:
# Select the dictionaries relevant to the part of the directory protocol you
# are fuzzing, and feed them to your fuzzer (if it supports dictionaries).
http_header_body_delimiter = "\x0d\x0a\x0d\x0a"
http_header_header_delimiter = "\x0d\x0a"
# multi-character tokens only
#http_header_value_delimiter = " "
content_length_header = "Content-Length:"
forwarded_for_header = "Forwarded-For:"
x_forwarded_for_header = "X-Forwarded-For:"
get_command = "GET"
post_command = "POST"

View File

@ -0,0 +1,6 @@
"introduction-point"
"ip-address"
"onion-port"
"onion-key"
"service-key"

View File

@ -0,0 +1,7 @@
"onion-key"
"ntor-onion-key"
"id"
"a"
"family"
"p"
"p6"

View File

@ -0,0 +1,19 @@
#!/bin/sh
set -e
if [ ! -d "$1" ] ; then
echo "I need a directory"
exit 1
fi
for fn in "$1"/* ; do
prev=`basename "$fn"`
post=`sha256sum "$fn" | sed -e 's/ .*//;'`
if [ "$prev" == "$post" ] ; then
echo "OK $prev"
else
echo "mv $prev $post"
mv "$fn" "$1/$post"
fi
done

View File

@ -0,0 +1,78 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#include "or.h"
#include "routerparse.h"
#include "networkstatus.h"
#include "fuzzing.h"
static void
mock_dump_desc__nodump(const char *desc, const char *type)
{
(void)desc;
(void)type;
}
static int
mock_router_produce_hash_final__nohash(char *digest,
const char *start, size_t len,
digest_algorithm_t alg)
{
(void)start;
(void)len;
/* we could look at start[..] */
if (alg == DIGEST_SHA1)
memset(digest, 0x01, 20);
else
memset(digest, 0x02, 32);
return 0;
}
static int
mock_signed_digest_equals__yes(const uint8_t *d1, const uint8_t *d2,
size_t len)
{
(void) tor_memeq(d1, d2, len);
return 1;
}
int
fuzz_init(void)
{
disable_signature_checking();
MOCK(dump_desc, mock_dump_desc__nodump);
MOCK(router_compute_hash_final, mock_router_produce_hash_final__nohash);
MOCK(signed_digest_equals, mock_signed_digest_equals__yes);
ed25519_init();
return 0;
}
int
fuzz_cleanup(void)
{
return 0;
}
int
fuzz_main(const uint8_t *data, size_t sz)
{
networkstatus_t *ns;
char *str = tor_memdup_nulterm(data, sz);
const char *eos = NULL;
networkstatus_type_t tp = NS_TYPE_CONSENSUS;
if (tor_memstr(data, MIN(sz, 1024), "tus vote"))
tp = NS_TYPE_VOTE;
const char *what = (tp == NS_TYPE_CONSENSUS) ? "consensus" : "vote";
ns = networkstatus_parse_vote_from_string(str,
&eos,
tp);
if (ns) {
log_debug(LD_GENERAL, "Parsing as %s okay", what);
networkstatus_vote_free(ns);
} else {
log_debug(LD_GENERAL, "Parsing as %s failed", what);
}
tor_free(str);
return 0;
}

View File

@ -0,0 +1,79 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#include "or.h"
#include "routerparse.h"
#include "routerlist.h"
#include "routerkeys.h"
#include "fuzzing.h"
static int
mock_check_tap_onion_key_crosscert__nocheck(const uint8_t *crosscert,
int crosscert_len,
const crypto_pk_t *onion_pkey,
const ed25519_public_key_t *master_id_pkey,
const uint8_t *rsa_id_digest)
{
tor_assert(crosscert && onion_pkey && master_id_pkey && rsa_id_digest);
/* we could look at crosscert[..] */
(void) crosscert_len;
return 0;
}
static void
mock_dump_desc__nodump(const char *desc, const char *type)
{
(void)desc;
(void)type;
}
static int
mock_router_produce_hash_final__nohash(char *digest,
const char *start, size_t len,
digest_algorithm_t alg)
{
(void)start;
(void)len;
/* we could look at start[..] */
if (alg == DIGEST_SHA1)
memset(digest, 0x01, 20);
else
memset(digest, 0x02, 32);
return 0;
}
int
fuzz_init(void)
{
disable_signature_checking();
MOCK(check_tap_onion_key_crosscert,
mock_check_tap_onion_key_crosscert__nocheck);
MOCK(dump_desc, mock_dump_desc__nodump);
MOCK(router_compute_hash_final, mock_router_produce_hash_final__nohash);
ed25519_init();
return 0;
}
int
fuzz_cleanup(void)
{
return 0;
}
int
fuzz_main(const uint8_t *data, size_t sz)
{
routerinfo_t *ri;
const char *str = (const char*) data;
ri = router_parse_entry_from_string((const char *)str,
str+sz,
0, 0, 0, NULL);
if (ri) {
log_debug(LD_GENERAL, "Parsing okay");
routerinfo_free(ri);
} else {
log_debug(LD_GENERAL, "Parsing failed");
}
return 0;
}

View File

@ -0,0 +1,65 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#include "or.h"
#include "routerparse.h"
#include "routerlist.h"
#include "routerkeys.h"
#include "fuzzing.h"
static void
mock_dump_desc__nodump(const char *desc, const char *type)
{
(void)desc;
(void)type;
}
static int
mock_router_produce_hash_final__nohash(char *digest,
const char *start, size_t len,
digest_algorithm_t alg)
{
(void)start;
(void)len;
/* we could look at start[..] */
if (alg == DIGEST_SHA1)
memset(digest, 0x01, 20);
else
memset(digest, 0x02, 32);
return 0;
}
int
fuzz_init(void)
{
disable_signature_checking();
MOCK(dump_desc, mock_dump_desc__nodump);
MOCK(router_compute_hash_final, mock_router_produce_hash_final__nohash);
ed25519_init();
return 0;
}
int
fuzz_cleanup(void)
{
return 0;
}
int
fuzz_main(const uint8_t *data, size_t sz)
{
extrainfo_t *ei;
const char *str = (const char*) data;
int again = 0;
ei = extrainfo_parse_entry_from_string((const char *)str,
str+sz,
0, NULL, &again);
if (ei) {
log_debug(LD_GENERAL, "Parsing okay");
extrainfo_free(ei);
} else {
log_debug(LD_GENERAL, "Parsing failed");
}
return 0;
}

View File

@ -0,0 +1,52 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#include "or.h"
#include "routerparse.h"
#include "rendcommon.h"
#include "fuzzing.h"
static void
mock_dump_desc__nodump(const char *desc, const char *type)
{
(void)desc;
(void)type;
}
int
fuzz_init(void)
{
disable_signature_checking();
MOCK(dump_desc, mock_dump_desc__nodump);
ed25519_init();
return 0;
}
int
fuzz_cleanup(void)
{
return 0;
}
int
fuzz_main(const uint8_t *data, size_t sz)
{
rend_service_descriptor_t *desc = NULL;
char desc_id[64];
char *ipts = NULL;
size_t ipts_size, esize;
const char *next;
char *str = tor_memdup_nulterm(data, sz);
(void) rend_parse_v2_service_descriptor(&desc, desc_id, &ipts, &ipts_size,
&esize, &next, str, 1);
if (desc) {
log_debug(LD_GENERAL, "Parsing okay");
rend_service_descriptor_free(desc);
} else {
log_debug(LD_GENERAL, "Parsing failed");
}
tor_free(ipts);
tor_free(str);
return 0;
}

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

@ -0,0 +1,133 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define BUFFERS_PRIVATE
#define DIRECTORY_PRIVATE
#include "or.h"
#include "backtrace.h"
#include "buffers.h"
#include "config.h"
#include "connection.h"
#include "directory.h"
#include "torlog.h"
#include "fuzzing.h"
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);
}
static int
mock_directory_handle_command_get(dir_connection_t *conn,
const char *headers,
const char *body,
size_t body_len)
{
(void)conn;
log_debug(LD_GENERAL, "Method:\nGET\n");
if (headers) {
log_debug(LD_GENERAL, "Header-Length:\n%zu\n", strlen(headers));
log_debug(LD_GENERAL, "Headers:\n%s\n", headers);
}
log_debug(LD_GENERAL, "Body-Length:\n%zu\n", body_len);
if (body) {
log_debug(LD_GENERAL, "Body:\n%s\n", body);
}
/* Always tell the caller we succeeded */
return 0;
}
static int
mock_directory_handle_command_post(dir_connection_t *conn,
const char *headers,
const char *body,
size_t body_len)
{
(void)conn;
log_debug(LD_GENERAL, "Method:\nPOST\n");
if (headers) {
log_debug(LD_GENERAL, "Header-Length:\n%zu\n", strlen(headers));
log_debug(LD_GENERAL, "Headers:\n%s\n", headers);
}
log_debug(LD_GENERAL, "Body-Length:\n%zu\n", body_len);
if (body) {
log_debug(LD_GENERAL, "Body:\n%s\n", body);
}
/* Always tell the caller we succeeded */
return 0;
}
int
fuzz_init(void)
{
/* Set up fake response handler */
MOCK(connection_write_to_buf_impl_, mock_connection_write_to_buf_impl_);
/* Set up the fake handler functions */
MOCK(directory_handle_command_get, mock_directory_handle_command_get);
MOCK(directory_handle_command_post, mock_directory_handle_command_post);
return 0;
}
int
fuzz_cleanup(void)
{
UNMOCK(connection_write_to_buf_impl_);
UNMOCK(directory_handle_command_get);
UNMOCK(directory_handle_command_post);
return 0;
}
int
fuzz_main(const uint8_t *stdin_buf, size_t data_size)
{
dir_connection_t dir_conn;
/* Set up the fake connection */
memset(&dir_conn, 0, sizeof(dir_connection_t));
dir_conn.base_.type = CONN_TYPE_DIR;
/* Apparently tor sets this before directory_handle_command() is called. */
dir_conn.base_.address = tor_strdup("replace-this-address.example.com");
dir_conn.base_.inbuf = buf_new_with_data((char*)stdin_buf, data_size);
if (!dir_conn.base_.inbuf) {
log_debug(LD_GENERAL, "Zero-Length-Input\n");
goto done;
}
/* Parse the headers */
int 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);
done:
/* Reset. */
tor_free(dir_conn.base_.address);
buf_free(dir_conn.base_.inbuf);
dir_conn.base_.inbuf = NULL;
return 0;
}

View File

@ -0,0 +1,46 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#include "or.h"
#include "routerparse.h"
#include "rendcommon.h"
#include "fuzzing.h"
static void
mock_dump_desc__nodump(const char *desc, const char *type)
{
(void)desc;
(void)type;
}
int
fuzz_init(void)
{
disable_signature_checking();
MOCK(dump_desc, mock_dump_desc__nodump);
ed25519_init();
return 0;
}
int
fuzz_cleanup(void)
{
return 0;
}
int
fuzz_main(const uint8_t *data, size_t sz)
{
rend_service_descriptor_t *desc =
tor_malloc_zero(sizeof(rend_service_descriptor_t));
const char *str = (const char*) data;
int r = rend_parse_introduction_points(desc, str, sz);
if (r >= 0) {
log_debug(LD_GENERAL, "Parsing okay: %d", r);
} else {
log_debug(LD_GENERAL, "Parsing failed");
}
rend_service_descriptor_free(desc);
return 0;
}

View File

@ -0,0 +1,47 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#include "or.h"
#include "routerparse.h"
#include "microdesc.h"
#include "fuzzing.h"
static void
mock_dump_desc__nodump(const char *desc, const char *type)
{
(void)desc;
(void)type;
}
int
fuzz_init(void)
{
disable_signature_checking();
MOCK(dump_desc, mock_dump_desc__nodump);
ed25519_init();
return 0;
}
int
fuzz_cleanup(void)
{
return 0;
}
int
fuzz_main(const uint8_t *data, size_t sz)
{
const char *str = (const char*) data;
smartlist_t *result = microdescs_parse_from_string((const char *)str,
str+sz,
0, SAVED_NOWHERE, NULL);
if (result) {
log_debug(LD_GENERAL, "Parsing okay: %d", smartlist_len(result));
SMARTLIST_FOREACH(result, microdesc_t *, md, microdesc_free(md));
smartlist_free(result);
} else {
log_debug(LD_GENERAL, "Parsing failed");
}
return 0;
}

34
src/test/fuzz/fuzz_multi.sh Executable file
View File

@ -0,0 +1,34 @@
MEMLIMIT_BYTES=21990500990976
N_CPUS=1
if [ $# -ge 1 ]; then
N_CPUS="$1"
shift
fi
FILTER=echo
for i in `seq -w "$N_CPUS"`; do
if [ "$i" -eq 1 ]; then
if [ "$N_CPUS" -eq 1 ]; then
INSTANCE=""
NUMBER=""
else
INSTANCE="-M"
NUMBER="$i"
fi
else
INSTANCE="-S"
NUMBER="$i"
fi
# use whatever remains on the command-line to prefix the fuzzer command
# you have to copy and paste and run these commands yourself
"$FILTER" "$@" \
../afl/afl-fuzz \
-i src/test/fuzz/fuzz_dir_testcase \
-o src/test/fuzz/fuzz_dir_findings \
-x src/test/fuzz/fuzz_dir_dictionary/fuzz_dir_http_header.dct \
-m "$MEMLIMIT_BYTES" \
"$INSTANCE" "$NUMBER" \
-- src/test/fuzz_dir
done

80
src/test/fuzz/fuzz_vrs.c Normal file
View File

@ -0,0 +1,80 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#define NETWORKSTATUS_PRIVATE
#include "or.h"
#include "routerparse.h"
#include "memarea.h"
#include "microdesc.h"
#include "networkstatus.h"
#include "fuzzing.h"
static void
mock_dump_desc__nodump(const char *desc, const char *type)
{
(void)desc;
(void)type;
}
static networkstatus_t *dummy_vote = NULL;
static memarea_t *area = NULL;
int
fuzz_init(void)
{
disable_signature_checking();
MOCK(dump_desc, mock_dump_desc__nodump);
ed25519_init();
area = memarea_new();
dummy_vote = tor_malloc_zero(sizeof(*dummy_vote));
dummy_vote->known_flags = smartlist_new();
smartlist_split_string(dummy_vote->known_flags,
"Authority BadExit Exit Fast Guard HSDir "
"NoEdConsensus Running Stable V2Dir Valid",
" ", 0, 0);
return 0;
}
int
fuzz_cleanup(void)
{
tor_free(dummy_vote);
return 0;
}
int
fuzz_main(const uint8_t *data, size_t sz)
{
char *str = tor_memdup_nulterm(data, sz);
const char *s;
routerstatus_t *rs_ns = NULL, *rs_md = NULL, *rs_vote = NULL;
vote_routerstatus_t *vrs = tor_malloc_zero(sizeof(*vrs));
smartlist_t *tokens = smartlist_new();
s = str;
rs_ns = routerstatus_parse_entry_from_string(area, &s, tokens,
NULL, NULL, 26, FLAV_NS);
tor_assert(smartlist_len(tokens) == 0);
s = str;
rs_md = routerstatus_parse_entry_from_string(area, &s, tokens,
NULL, NULL, 26, FLAV_MICRODESC);
tor_assert(smartlist_len(tokens) == 0);
s = str;
rs_vote = routerstatus_parse_entry_from_string(area, &s, tokens,
dummy_vote, vrs, 26, FLAV_NS);
tor_assert(smartlist_len(tokens) == 0);
log_debug(LD_GENERAL,
"ns=%p, md=%p, vote=%p", rs_ns, rs_md, rs_vote);
routerstatus_free(rs_md);
routerstatus_free(rs_ns);
vote_routerstatus_free(vrs);
memarea_clear(area);
smartlist_free(tokens);
tor_free(str);
return 0;
}

13
src/test/fuzz/fuzzing.h Normal file
View File

@ -0,0 +1,13 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef FUZZING_H
#define FUZZING_H
int fuzz_init(void);
int fuzz_cleanup(void);
int fuzz_main(const uint8_t *data, size_t sz);
void disable_signature_checking(void);
#endif /* FUZZING_H */

View File

@ -0,0 +1,190 @@
/* Copyright (c) 2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CRYPTO_ED25519_PRIVATE
#include "orconfig.h"
#include "or.h"
#include "backtrace.h"
#include "config.h"
#include "fuzzing.h"
#include "crypto.h"
#include "crypto_ed25519.h"
extern const char tor_git_revision[];
const char tor_git_revision[] = "";
static or_options_t *mock_options = NULL;
static const or_options_t *
mock_get_options(void)
{
return mock_options;
}
static int
mock_crypto_pk_public_checksig__nocheck(const crypto_pk_t *env, char *to,
size_t tolen,
const char *from, size_t fromlen)
{
tor_assert(env && to && from);
(void)fromlen;
/* We could look at from[0..fromlen-1] ... */
tor_assert(tolen >= crypto_pk_keysize(env));
memset(to, 0x01, 20);
return 20;
}
static int
mock_crypto_pk_public_checksig_digest__nocheck(crypto_pk_t *env,
const char *data,
size_t datalen,
const char *sig,
size_t siglen)
{
tor_assert(env && data && sig);
(void)datalen;
(void)siglen;
/* We could look at data[..] and sig[..] */
return 0;
}
static int
mock_ed25519_checksig__nocheck(const ed25519_signature_t *signature,
const uint8_t *msg, size_t len,
const ed25519_public_key_t *pubkey)
{
tor_assert(signature && msg && pubkey);
/* We could look at msg[0..len-1] ... */
(void)len;
return 0;
}
static int
mock_ed25519_checksig_batch__nocheck(int *okay_out,
const ed25519_checkable_t *checkable,
int n_checkable)
{
tor_assert(checkable);
int i;
for (i = 0; i < n_checkable; ++i) {
/* We could look at messages and signatures XXX */
tor_assert(checkable[i].pubkey);
tor_assert(checkable[i].msg);
if (okay_out)
okay_out[i] = 1;
}
return 0;
}
static int
mock_ed25519_impl_spot_check__nocheck(void)
{
return 0;
}
void
disable_signature_checking(void)
{
MOCK(crypto_pk_public_checksig,
mock_crypto_pk_public_checksig__nocheck);
MOCK(crypto_pk_public_checksig_digest,
mock_crypto_pk_public_checksig_digest__nocheck);
MOCK(ed25519_checksig, mock_ed25519_checksig__nocheck);
MOCK(ed25519_checksig_batch, mock_ed25519_checksig_batch__nocheck);
MOCK(ed25519_impl_spot_check, mock_ed25519_impl_spot_check__nocheck);
}
static void
global_init(void)
{
tor_threads_init();
{
struct sipkey sipkey = { 1337, 7331 };
siphash_set_global_key(&sipkey);
}
/* Initialise logging first */
init_logging(1);
configure_backtrace_handler(get_version());
/* set up the options. */
mock_options = tor_malloc(sizeof(or_options_t));
MOCK(get_options, mock_get_options);
/* Make BUG() and nonfatal asserts crash */
tor_set_failed_assertion_callback(abort);
}
#ifdef LLVM_FUZZ
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
int
LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
static int initialized = 0;
if (!initialized) {
global_init();
if (fuzz_init() < 0)
abort();
initialized = 1;
}
return fuzz_main(Data, Size);
}
#else /* Not LLVM_FUZZ, so AFL. */
int
main(int argc, char **argv)
{
size_t size;
global_init();
/* Disable logging by default to speed up fuzzing. */
int loglevel = LOG_ERR;
for (int i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "--warn")) {
loglevel = LOG_WARN;
} else if (!strcmp(argv[i], "--notice")) {
loglevel = LOG_NOTICE;
} else if (!strcmp(argv[i], "--info")) {
loglevel = LOG_INFO;
} else if (!strcmp(argv[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));
}
if (fuzz_init() < 0)
abort();
#ifdef __AFL_HAVE_MANUAL_CONTROL
/* Tell AFL to pause and fork here - ignored if not using AFL */
__AFL_INIT();
#endif
#define MAX_FUZZ_SIZE (128*1024)
char *input = read_file_to_str_until_eof(0, MAX_FUZZ_SIZE, &size);
tor_assert(input);
char *raw = tor_memdup(input, size); /* Because input is nul-terminated */
tor_free(input);
fuzz_main((const uint8_t*)raw, size);
tor_free(raw);
if (fuzz_cleanup() < 0)
abort();
tor_free(mock_options);
UNMOCK(get_options);
return 0;
}
#endif

250
src/test/fuzz/include.am Normal file
View File

@ -0,0 +1,250 @@
FUZZING_CPPFLAGS = \
$(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS)
FUZZING_CFLAGS = \
$(AM_CFLAGS) $(TEST_CFLAGS)
FUZZING_LDFLAG = \
@TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
FUZZING_LIBS = \
src/or/libtor-testing.a \
src/common/libor-crypto-testing.a \
$(LIBKECCAK_TINY) \
$(LIBDONNA) \
src/common/libor-testing.a \
src/common/libor-ctime-testing.a \
src/common/libor-event-testing.a \
src/trunnel/libor-trunnel-testing.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@
oss-fuzz-prereqs: \
src/or/libtor-testing.a \
src/common/libor-crypto-testing.a \
$(LIBKECCAK_TINY) \
$(LIBDONNA) \
src/common/libor-testing.a \
src/common/libor-ctime-testing.a \
src/common/libor-event-testing.a \
src/trunnel/libor-trunnel-testing.a
noinst_HEADERS += \
src/test/fuzz/fuzzing.h
src_test_fuzz_fuzz_consensus_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_consensus.c
src_test_fuzz_fuzz_consensus_CPPFLAGS = $(FUZZING_CPPFLAGS)
src_test_fuzz_fuzz_consensus_CFLAGS = $(FUZZING_CFLAGS)
src_test_fuzz_fuzz_consensus_LDFLAGS = $(FUZZING_LDFLAG)
src_test_fuzz_fuzz_consensus_LDADD = $(FUZZING_LIBS)
src_test_fuzz_fuzz_descriptor_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_descriptor.c
src_test_fuzz_fuzz_descriptor_CPPFLAGS = $(FUZZING_CPPFLAGS)
src_test_fuzz_fuzz_descriptor_CFLAGS = $(FUZZING_CFLAGS)
src_test_fuzz_fuzz_descriptor_LDFLAGS = $(FUZZING_LDFLAG)
src_test_fuzz_fuzz_descriptor_LDADD = $(FUZZING_LIBS)
src_test_fuzz_fuzz_http_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_http.c
src_test_fuzz_fuzz_http_CPPFLAGS = $(FUZZING_CPPFLAGS)
src_test_fuzz_fuzz_http_CFLAGS = $(FUZZING_CFLAGS)
src_test_fuzz_fuzz_http_LDFLAGS = $(FUZZING_LDFLAG)
src_test_fuzz_fuzz_http_LDADD = $(FUZZING_LIBS)
src_test_fuzz_fuzz_hsdescv2_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_hsdescv2.c
src_test_fuzz_fuzz_hsdescv2_CPPFLAGS = $(FUZZING_CPPFLAGS)
src_test_fuzz_fuzz_hsdescv2_CFLAGS = $(FUZZING_CFLAGS)
src_test_fuzz_fuzz_hsdescv2_LDFLAGS = $(FUZZING_LDFLAG)
src_test_fuzz_fuzz_hsdescv2_LDADD = $(FUZZING_LIBS)
src_test_fuzz_fuzz_iptsv2_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_iptsv2.c
src_test_fuzz_fuzz_iptsv2_CPPFLAGS = $(FUZZING_CPPFLAGS)
src_test_fuzz_fuzz_iptsv2_CFLAGS = $(FUZZING_CFLAGS)
src_test_fuzz_fuzz_iptsv2_LDFLAGS = $(FUZZING_LDFLAG)
src_test_fuzz_fuzz_iptsv2_LDADD = $(FUZZING_LIBS)
src_test_fuzz_fuzz_extrainfo_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_extrainfo.c
src_test_fuzz_fuzz_extrainfo_CPPFLAGS = $(FUZZING_CPPFLAGS)
src_test_fuzz_fuzz_extrainfo_CFLAGS = $(FUZZING_CFLAGS)
src_test_fuzz_fuzz_extrainfo_LDFLAGS = $(FUZZING_LDFLAG)
src_test_fuzz_fuzz_extrainfo_LDADD = $(FUZZING_LIBS)
src_test_fuzz_fuzz_microdesc_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_microdesc.c
src_test_fuzz_fuzz_microdesc_CPPFLAGS = $(FUZZING_CPPFLAGS)
src_test_fuzz_fuzz_microdesc_CFLAGS = $(FUZZING_CFLAGS)
src_test_fuzz_fuzz_microdesc_LDFLAGS = $(FUZZING_LDFLAG)
src_test_fuzz_fuzz_microdesc_LDADD = $(FUZZING_LIBS)
src_test_fuzz_fuzz_vrs_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_vrs.c
src_test_fuzz_fuzz_vrs_CPPFLAGS = $(FUZZING_CPPFLAGS)
src_test_fuzz_fuzz_vrs_CFLAGS = $(FUZZING_CFLAGS)
src_test_fuzz_fuzz_vrs_LDFLAGS = $(FUZZING_LDFLAG)
src_test_fuzz_fuzz_vrs_LDADD = $(FUZZING_LIBS)
FUZZERS = \
src/test/fuzz/fuzz-consensus \
src/test/fuzz/fuzz-descriptor \
src/test/fuzz/fuzz-extrainfo \
src/test/fuzz/fuzz-http \
src/test/fuzz/fuzz-hsdescv2 \
src/test/fuzz/fuzz-iptsv2 \
src/test/fuzz/fuzz-microdesc \
src/test/fuzz/fuzz-vrs
LIBFUZZER = /home/nickm/build/libfuzz/libFuzzer.a
LIBFUZZER_CPPFLAGS = $(FUZZING_CPPFLAGS) -DLLVM_FUZZ
LIBFUZZER_CFLAGS = $(FUZZING_CFLAGS)
LIBFUZZER_LDFLAG = $(FUZZING_LDFLAG)
LIBFUZZER_LIBS = $(FUZZING_LIBS) $(LIBFUZZER) -lstdc++
if LIBFUZZER_ENABLED
src_test_fuzz_lf_fuzz_consensus_SOURCES = \
$(src_test_fuzz_fuzz_consensus_SOURCES)
src_test_fuzz_lf_fuzz_consensus_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
src_test_fuzz_lf_fuzz_consensus_CFLAGS = $(LIBFUZZER_CFLAGS)
src_test_fuzz_lf_fuzz_consensus_LDFLAGS = $(LIBFUZZER_LDFLAG)
src_test_fuzz_lf_fuzz_consensus_LDADD = $(LIBFUZZER_LIBS)
src_test_fuzz_lf_fuzz_descriptor_SOURCES = \
$(src_test_fuzz_fuzz_descriptor_SOURCES)
src_test_fuzz_lf_fuzz_descriptor_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
src_test_fuzz_lf_fuzz_descriptor_CFLAGS = $(LIBFUZZER_CFLAGS)
src_test_fuzz_lf_fuzz_descriptor_LDFLAGS = $(LIBFUZZER_LDFLAG)
src_test_fuzz_lf_fuzz_descriptor_LDADD = $(LIBFUZZER_LIBS)
src_test_fuzz_lf_fuzz_extrainfo_SOURCES = \
$(src_test_fuzz_fuzz_extrainfo_SOURCES)
src_test_fuzz_lf_fuzz_extrainfo_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
src_test_fuzz_lf_fuzz_extrainfo_CFLAGS = $(LIBFUZZER_CFLAGS)
src_test_fuzz_lf_fuzz_extrainfo_LDFLAGS = $(LIBFUZZER_LDFLAG)
src_test_fuzz_lf_fuzz_extrainfo_LDADD = $(LIBFUZZER_LIBS)
src_test_fuzz_lf_fuzz_http_SOURCES = \
$(src_test_fuzz_fuzz_http_SOURCES)
src_test_fuzz_lf_fuzz_http_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
src_test_fuzz_lf_fuzz_http_CFLAGS = $(LIBFUZZER_CFLAGS)
src_test_fuzz_lf_fuzz_http_LDFLAGS = $(LIBFUZZER_LDFLAG)
src_test_fuzz_lf_fuzz_http_LDADD = $(LIBFUZZER_LIBS)
src_test_fuzz_lf_fuzz_hsdescv2_SOURCES = \
$(src_test_fuzz_fuzz_hsdescv2_SOURCES)
src_test_fuzz_lf_fuzz_hsdescv2_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
src_test_fuzz_lf_fuzz_hsdescv2_CFLAGS = $(LIBFUZZER_CFLAGS)
src_test_fuzz_lf_fuzz_hsdescv2_LDFLAGS = $(LIBFUZZER_LDFLAG)
src_test_fuzz_lf_fuzz_hsdescv2_LDADD = $(LIBFUZZER_LIBS)
src_test_fuzz_lf_fuzz_iptsv2_SOURCES = \
$(src_test_fuzz_fuzz_iptsv2_SOURCES)
src_test_fuzz_lf_fuzz_iptsv2_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
src_test_fuzz_lf_fuzz_iptsv2_CFLAGS = $(LIBFUZZER_CFLAGS)
src_test_fuzz_lf_fuzz_iptsv2_LDFLAGS = $(LIBFUZZER_LDFLAG)
src_test_fuzz_lf_fuzz_iptsv2_LDADD = $(LIBFUZZER_LIBS)
src_test_fuzz_lf_fuzz_microdesc_SOURCES = \
$(src_test_fuzz_fuzz_microdesc_SOURCES)
src_test_fuzz_lf_fuzz_microdesc_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
src_test_fuzz_lf_fuzz_microdesc_CFLAGS = $(LIBFUZZER_CFLAGS)
src_test_fuzz_lf_fuzz_microdesc_LDFLAGS = $(LIBFUZZER_LDFLAG)
src_test_fuzz_lf_fuzz_microdesc_LDADD = $(LIBFUZZER_LIBS)
src_test_fuzz_lf_fuzz_vrs_SOURCES = \
$(src_test_fuzz_fuzz_vrs_SOURCES)
src_test_fuzz_lf_fuzz_vrs_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
src_test_fuzz_lf_fuzz_vrs_CFLAGS = $(LIBFUZZER_CFLAGS)
src_test_fuzz_lf_fuzz_vrs_LDFLAGS = $(LIBFUZZER_LDFLAG)
src_test_fuzz_lf_fuzz_vrs_LDADD = $(LIBFUZZER_LIBS)
LIBFUZZER_FUZZERS = \
src/test/fuzz/lf-fuzz-consensus \
src/test/fuzz/lf-fuzz-descriptor \
src/test/fuzz/lf-fuzz-extrainfo \
src/test/fuzz/lf-fuzz-http \
src/test/fuzz/lf-fuzz-hsdescv2 \
src/test/fuzz/lf-fuzz-iptsv2 \
src/test/fuzz/lf-fuzz-microdesc \
src/test/fuzz/lf-fuzz-vrs
else
LIBFUZZER_FUZZERS =
endif
if OSS_FUZZ_ENABLED
LIBOSS_FUZZ_CPPFLAGS = $(FUZZING_CPPFLAGS) -DLLVM_FUZZ
LIBOSS_FUZZ_CFLAGS = $(FUZZING_CFLAGS)
src_test_fuzz_liboss_fuzz_consensus_a_SOURCES = \
$(src_test_fuzz_fuzz_consensus_SOURCES)
src_test_fuzz_liboss_fuzz_consensus_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
src_test_fuzz_liboss_fuzz_consensus_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
src_test_fuzz_liboss_fuzz_descriptor_a_SOURCES = \
$(src_test_fuzz_fuzz_descriptor_SOURCES)
src_test_fuzz_liboss_fuzz_descriptor_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
src_test_fuzz_liboss_fuzz_descriptor_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
src_test_fuzz_liboss_fuzz_extrainfo_a_SOURCES = \
$(src_test_fuzz_fuzz_extrainfo_SOURCES)
src_test_fuzz_liboss_fuzz_extrainfo_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
src_test_fuzz_liboss_fuzz_extrainfo_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
src_test_fuzz_liboss_fuzz_http_a_SOURCES = \
$(src_test_fuzz_fuzz_http_SOURCES)
src_test_fuzz_liboss_fuzz_http_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
src_test_fuzz_liboss_fuzz_http_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
src_test_fuzz_liboss_fuzz_hsdescv2_a_SOURCES = \
$(src_test_fuzz_fuzz_hsdescv2_SOURCES)
src_test_fuzz_liboss_fuzz_hsdescv2_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
src_test_fuzz_liboss_fuzz_hsdescv2_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
src_test_fuzz_liboss_fuzz_iptsv2_a_SOURCES = \
$(src_test_fuzz_fuzz_iptsv2_SOURCES)
src_test_fuzz_liboss_fuzz_iptsv2_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
src_test_fuzz_liboss_fuzz_iptsv2_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
src_test_fuzz_liboss_fuzz_microdesc_a_SOURCES = \
$(src_test_fuzz_fuzz_microdesc_SOURCES)
src_test_fuzz_liboss_fuzz_microdesc_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
src_test_fuzz_liboss_fuzz_microdesc_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
src_test_fuzz_liboss_fuzz_vrs_a_SOURCES = \
$(src_test_fuzz_fuzz_vrs_SOURCES)
src_test_fuzz_liboss_fuzz_vrs_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
src_test_fuzz_liboss_fuzz_vrs_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
OSS_FUZZ_FUZZERS = \
src/test/fuzz/liboss-fuzz-consensus.a \
src/test/fuzz/liboss-fuzz-descriptor.a \
src/test/fuzz/liboss-fuzz-extrainfo.a \
src/test/fuzz/liboss-fuzz-http.a \
src/test/fuzz/liboss-fuzz-hsdescv2.a \
src/test/fuzz/liboss-fuzz-iptsv2.a \
src/test/fuzz/liboss-fuzz-microdesc.a \
src/test/fuzz/liboss-fuzz-vrs.a
else
OSS_FUZZ_FUZZERS =
endif
noinst_PROGRAMS += $(FUZZERS) $(LIBFUZZER_FUZZERS)
noinst_LIBRARIES += $(OSS_FUZZ_FUZZERS)
oss-fuzz-fuzzers: oss-fuzz-prereqs $(OSS_FUZZ_FUZZERS)
fuzzers: $(FUZZERS) $(LIBFUZZER_FUZZERS)
fuzz: $(FUZZERS)
$(top_srcdir)/src/test/fuzz_static_testcases.sh

14
src/test/fuzz/minimize.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
set -e
if [ ! -d "$1" ] ; then
echo "I need a directory"
exit 1
fi
which=`basename "$1"`
mkdir "$1.out"
afl-cmin -i "$1" -o "$1.out" -m none "./src/test/fuzz/fuzz-${which}"

View File

@ -0,0 +1,27 @@
#!/bin/sh
# Copyright (c) 2016, The Tor Project, Inc.
# See LICENSE for licensing information
set -e
if [ -z "${TOR_FUZZ_CORPORA}" ] || [ ! -d "${TOR_FUZZ_CORPORA}" ] ; then
echo "You need to set TOR_FUZZ_CORPORA to point to a checkout of "
echo "the 'fuzzing-corpora' repository."
exit 77
fi
for fuzzer in "${builddir:-.}"/src/test/fuzz/fuzz-* ; do
f=`basename $fuzzer`
case="${f#fuzz-}"
if [ -d "${TOR_FUZZ_CORPORA}/${case}" ]; then
echo "Running tests for ${case}"
for entry in "${TOR_FUZZ_CORPORA}/${case}/"*; do
"${fuzzer}" "--err" < "$entry"
done
else
echo "No tests found for ${case}"
fi
done

View File

@ -8,7 +8,9 @@ TESTS_ENVIRONMENT = \
export builddir="$(builddir)"; \
export TESTING_TOR_BINARY="$(TESTING_TOR_BINARY)";
TESTSCRIPTS = src/test/test_zero_length_keys.sh \
TESTSCRIPTS = \
src/test/fuzz_static_testcases.sh \
src/test/test_zero_length_keys.sh \
src/test/test_workqueue_cancel.sh \
src/test/test_workqueue_efd.sh \
src/test/test_workqueue_efd2.sh \