diff options
-rw-r--r-- | changes/bug21439 | 7 | ||||
-rw-r--r-- | configure.ac | 7 | ||||
-rw-r--r-- | src/common/memarea.c | 91 | ||||
-rw-r--r-- | src/or/buffers.c | 10 | ||||
-rw-r--r-- | src/test/test_util.c | 7 |
5 files changed, 121 insertions, 1 deletions
diff --git a/changes/bug21439 b/changes/bug21439 new file mode 100644 index 0000000000..3acc53bfb7 --- /dev/null +++ b/changes/bug21439 @@ -0,0 +1,7 @@ + o Minor features (testing): + - Add a "--disable-memory-sentinels" feature to help with fuzzing. + When Tor is compiled with this option, we disable a number of + redundant memory-safety failsafes that are intended to stop + bugs from becoming security issues. This makes it easier to hunt + for bugs that would be security issues without the failsafes + turned on. Closes ticket 21439. diff --git a/configure.ac b/configure.ac index 59da60c6c4..05ac9fe846 100644 --- a/configure.ac +++ b/configure.ac @@ -53,6 +53,8 @@ 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])) +AC_ARG_ENABLE(memory-sentinels, + AS_HELP_STRING(--disable-memory-sentinels, [disable code that tries to prevent some kinds of memory access bugs. For fuzzing only.])) 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]) @@ -76,6 +78,11 @@ if test "$enable_system_torrc" = "no"; then [Defined if we're not going to look for a torrc in SYSCONF]) fi +if test "$enable_memory_sentinels" = "no"; then + AC_DEFINE(DISABLE_MEMORY_SENTINELS, 1, + [Defined if we're turning off memory safety code to look for bugs]) +fi + AM_CONDITIONAL(USE_OPENBSD_MALLOC, test "x$enable_openbsd_malloc" = "xyes") AC_ARG_ENABLE(asciidoc, diff --git a/src/common/memarea.c b/src/common/memarea.c index 7d16b702e3..12781e76ea 100644 --- a/src/common/memarea.c +++ b/src/common/memarea.c @@ -12,6 +12,9 @@ #include "util.h" #include "compat.h" #include "torlog.h" +#include "container.h" + +#ifndef DISABLE_MEMORY_SENTINELS /** If true, we try to detect any attempts to write beyond the length of a * memarea. */ @@ -304,3 +307,91 @@ memarea_assert_ok(memarea_t *area) } } +#else + +struct memarea_t { + smartlist_t *pieces; +}; + +memarea_t * +memarea_new(void) +{ + memarea_t *ma = tor_malloc_zero(sizeof(memarea_t)); + ma->pieces = smartlist_new(); + return ma; +} +void +memarea_drop_all(memarea_t *area) +{ + memarea_clear(area); + smartlist_free(area->pieces); + tor_free(area); +} +void +memarea_clear(memarea_t *area) +{ + SMARTLIST_FOREACH(area->pieces, void *, p, tor_free_(p)); + smartlist_clear(area->pieces); +} +int +memarea_owns_ptr(const memarea_t *area, const void *ptr) +{ + SMARTLIST_FOREACH(area->pieces, const void *, p, if (ptr == p) return 1;); + return 0; +} + +void * +memarea_alloc(memarea_t *area, size_t sz) +{ + void *result = tor_malloc(sz); + smartlist_add(area->pieces, result); + return result; +} + +void * +memarea_alloc_zero(memarea_t *area, size_t sz) +{ + void *result = tor_malloc_zero(sz); + smartlist_add(area->pieces, result); + return result; +} +void * +memarea_memdup(memarea_t *area, const void *s, size_t n) +{ + void *r = memarea_alloc(area, n); + memcpy(r, s, n); + return r; +} +char * +memarea_strdup(memarea_t *area, const char *s) +{ + size_t n = strlen(s); + char *r = memarea_alloc(area, n+1); + memcpy(r, s, n); + r[n] = 0; + return r; +} +char * +memarea_strndup(memarea_t *area, const char *s, size_t n) +{ + size_t ln = strnlen(s, n); + char *r = memarea_alloc(area, ln+1); + memcpy(r, s, ln); + r[ln] = 0; + return r; +} +void +memarea_get_stats(memarea_t *area, + size_t *allocated_out, size_t *used_out) +{ + (void)area; + *allocated_out = *used_out = 128; +} +void +memarea_assert_ok(memarea_t *area) +{ + (void)area; +} + +#endif + diff --git a/src/or/buffers.c b/src/or/buffers.c index 603da1bb6e..155b1935ed 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -83,7 +83,11 @@ static int parse_socks_client(const uint8_t *data, size_t datalen, #define CHUNK_HEADER_LEN STRUCT_OFFSET(chunk_t, mem[0]) /* We leave this many NUL bytes at the end of the buffer. */ +#ifdef DISABLE_MEMORY_SENTINELS +#define SENTINEL_LEN 0 +#else #define SENTINEL_LEN 4 +#endif /* Header size plus NUL bytes at the end */ #define CHUNK_OVERHEAD (CHUNK_HEADER_LEN + SENTINEL_LEN) @@ -97,18 +101,22 @@ static int parse_socks_client(const uint8_t *data, size_t datalen, #define DEBUG_SENTINEL -#ifdef DEBUG_SENTINEL +#if defined(DEBUG_SENTINEL) && !defined(DISABLE_MEMORY_SENTINELS) #define DBG_S(s) s #else #define DBG_S(s) (void)0 #endif +#ifdef DISABLE_MEMORY_SENTINELS +#define CHUNK_SET_SENTINEL(chunk, alloclen) STMT_NIL +#else #define CHUNK_SET_SENTINEL(chunk, alloclen) do { \ uint8_t *a = (uint8_t*) &(chunk)->mem[(chunk)->memlen]; \ DBG_S(uint8_t *b = &((uint8_t*)(chunk))[(alloclen)-SENTINEL_LEN]); \ DBG_S(tor_assert(a == b)); \ memset(a,0,SENTINEL_LEN); \ } while (0) +#endif /** Return the next character in <b>chunk</b> onto which data can be appended. * If the chunk is full, this might be off the end of chunk->mem. */ diff --git a/src/test/test_util.c b/src/test/test_util.c index e80201737a..5b4d5b7703 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -3340,6 +3340,13 @@ test_util_memarea(void *arg) void *malloced_ptr = NULL; int i; +#ifdef DISABLE_MEMORY_SENTINELS + /* If memory sentinels are disabled, this whole module is just an alias for + malloc(), which is free to lay out memory most any way it wants. */ + if (1) + tt_skip(); +#endif + (void)arg; tt_assert(area); |