mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 05:03:43 +01:00
Merge branch 'combined-fuzzing-v4'
This commit is contained in:
commit
558c04f5b1
4
.gitignore
vendored
4
.gitignore
vendored
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
120
doc/HACKING/Fuzzing.md
Normal 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
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 =
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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"
|
||||
|
52
src/test/fuzz/dict/consensus
Normal file
52
src/test/fuzz/dict/consensus
Normal 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"
|
41
src/test/fuzz/dict/descriptor
Normal file
41
src/test/fuzz/dict/descriptor
Normal 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"
|
32
src/test/fuzz/dict/extrainfo
Normal file
32
src/test/fuzz/dict/extrainfo
Normal 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"
|
8
src/test/fuzz/dict/hsdescv2
Normal file
8
src/test/fuzz/dict/hsdescv2
Normal 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
24
src/test/fuzz/dict/http
Normal 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"
|
6
src/test/fuzz/dict/iptsv2
Normal file
6
src/test/fuzz/dict/iptsv2
Normal file
@ -0,0 +1,6 @@
|
||||
"introduction-point"
|
||||
"ip-address"
|
||||
"onion-port"
|
||||
"onion-key"
|
||||
"service-key"
|
||||
|
7
src/test/fuzz/dict/microdesc
Normal file
7
src/test/fuzz/dict/microdesc
Normal file
@ -0,0 +1,7 @@
|
||||
"onion-key"
|
||||
"ntor-onion-key"
|
||||
"id"
|
||||
"a"
|
||||
"family"
|
||||
"p"
|
||||
"p6"
|
19
src/test/fuzz/fixup_filenames.sh
Executable file
19
src/test/fuzz/fixup_filenames.sh
Executable 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
|
78
src/test/fuzz/fuzz_consensus.c
Normal file
78
src/test/fuzz/fuzz_consensus.c
Normal 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;
|
||||
}
|
||||
|
79
src/test/fuzz/fuzz_descriptor.c
Normal file
79
src/test/fuzz/fuzz_descriptor.c
Normal 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;
|
||||
}
|
||||
|
65
src/test/fuzz/fuzz_extrainfo.c
Normal file
65
src/test/fuzz/fuzz_extrainfo.c
Normal 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;
|
||||
}
|
||||
|
52
src/test/fuzz/fuzz_hsdescv2.c
Normal file
52
src/test/fuzz/fuzz_hsdescv2.c
Normal 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
133
src/test/fuzz/fuzz_http.c
Normal 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;
|
||||
}
|
||||
|
46
src/test/fuzz/fuzz_iptsv2.c
Normal file
46
src/test/fuzz/fuzz_iptsv2.c
Normal 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;
|
||||
}
|
||||
|
47
src/test/fuzz/fuzz_microdesc.c
Normal file
47
src/test/fuzz/fuzz_microdesc.c
Normal 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
34
src/test/fuzz/fuzz_multi.sh
Executable 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
80
src/test/fuzz/fuzz_vrs.c
Normal 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
13
src/test/fuzz/fuzzing.h
Normal 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 */
|
||||
|
190
src/test/fuzz/fuzzing_common.c
Normal file
190
src/test/fuzz/fuzzing_common.c
Normal 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
250
src/test/fuzz/include.am
Normal 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
14
src/test/fuzz/minimize.sh
Executable 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}"
|
||||
|
27
src/test/fuzz_static_testcases.sh
Executable file
27
src/test/fuzz_static_testcases.sh
Executable 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
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user