[tor-commits] [tor/master] Fuzzing module for various string operations, currently focusing on

nickm at torproject.org nickm at torproject.org
Wed Dec 12 16:08:02 UTC 2018


commit 845e8dbe5904b4b2d3eb2db9e2681ea2f4d98008
Author: Nick Mathewson <nickm at torproject.org>
Date:   Mon Dec 10 10:00:26 2018 -0500

    Fuzzing module for various string operations, currently focusing on
    encoding and decoding.
    
    There are bunches of places where we don't want to invest in a full
    fuzzer, but we would like to make sure that some string operation
    can handle all its possible inputs.  This fuzzer uses the first byte
    of its input to decide what to do with the rest of the input.  Right
    now, all the possibilities are decoding a string, and seeing whether
    it is decodeable.  If it is, we try to re-encode it and do the whole
    thing again, to make sure we get the same result.
    
    This turned up a lot of bugs in the key-value parser, and I think it
    will help in other cases too.
    
    Closes ticket 28808.
---
 scripts/codegen/fuzzing_include_am.py |   1 +
 src/test/fuzz/fuzz_strops.c           | 247 ++++++++++++++++++++++++++++++++++
 src/test/fuzz/include.am              |  29 ++++
 3 files changed, 277 insertions(+)

diff --git a/scripts/codegen/fuzzing_include_am.py b/scripts/codegen/fuzzing_include_am.py
index 3c948d87c..5b5115884 100755
--- a/scripts/codegen/fuzzing_include_am.py
+++ b/scripts/codegen/fuzzing_include_am.py
@@ -13,6 +13,7 @@ FUZZERS = """
 	iptsv2
 	microdesc
 	socks
+	strops
 	vrs
 """
 
diff --git a/src/test/fuzz/fuzz_strops.c b/src/test/fuzz/fuzz_strops.c
new file mode 100644
index 000000000..5da590acf
--- /dev/null
+++ b/src/test/fuzz/fuzz_strops.c
@@ -0,0 +1,247 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file fuzz_strops.c
+ * \brief Fuzzers for various string encoding/decoding operations
+ **/
+
+#include "orconfig.h"
+
+#include "lib/cc/torint.h"
+#include "lib/ctime/di_ops.h"
+#include "lib/encoding/binascii.h"
+#include "lib/encoding/cstring.h"
+#include "lib/encoding/kvline.h"
+#include "lib/encoding/confline.h"
+#include "lib/malloc/malloc.h"
+#include "lib/log/escape.h"
+#include "lib/log/util_bug.h"
+#include "lib/intmath/muldiv.h"
+
+#include "test/fuzz/fuzzing.h"
+
+#include <stdio.h>
+#include <string.h>
+
+int
+fuzz_init(void)
+{
+  return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+  return 0;
+}
+
+typedef struct chunk_t {
+  uint8_t *buf;
+  size_t len;
+} chunk_t;
+
+#define chunk_free(ch)                          \
+  FREE_AND_NULL(chunk_t, chunk_free_, (ch))
+
+static chunk_t *
+chunk_new(size_t len)
+{
+  chunk_t *ch = tor_malloc(sizeof(chunk_t));
+  ch->buf = tor_malloc(len);
+  ch->len = len;
+  return ch;
+}
+static void
+chunk_free_(chunk_t *ch)
+{
+  if (!ch)
+    return;
+  tor_free(ch->buf);
+  tor_free(ch);
+}
+static bool
+chunk_eq(const chunk_t *a, const chunk_t *b)
+{
+  return a->len == b->len && fast_memeq(a->buf, b->buf, a->len);
+}
+
+static chunk_t *
+b16_dec(const chunk_t *inp)
+{
+  chunk_t *ch = chunk_new(CEIL_DIV(inp->len, 2));
+  int r = base16_decode((char *)ch->buf, ch->len, (char *)inp->buf, inp->len);
+  if (r >= 0) {
+    ch->len = r;
+  } else {
+    chunk_free(ch);
+  }
+  return ch;
+}
+static chunk_t *
+b16_enc(const chunk_t *inp)
+{
+  chunk_t *ch = chunk_new(inp->len * 2 + 1);
+  base16_encode((char *)ch->buf, ch->len, (char*)inp->buf, inp->len);
+  return ch;
+}
+
+#if 0
+static chunk_t *
+b32_dec(const chunk_t *inp)
+{
+  chunk_t *ch = chunk_new(inp->len);//XXXX
+  int r = base32_decode((char *)ch->buf, ch->len, (char *)inp->buf, inp->len);
+  if (r >= 0) {
+    ch->len = r; // XXXX we need some way to get the actual length of
+                 // XXXX the output here.
+  } else {
+    chunk_free(ch);
+  }
+  return ch;
+}
+static chunk_t *
+b32_enc(const chunk_t *inp)
+{
+  chunk_t *ch = chunk_new(base32_encoded_size(inp->len));
+  base32_encode((char *)ch->buf, ch->len, (char*)inp->buf, inp->len);
+  ch->len = strlen((char *) ch->buf);
+  return ch;
+}
+#endif
+
+static chunk_t *
+b64_dec(const chunk_t *inp)
+{
+  chunk_t *ch = chunk_new(inp->len);//XXXX This could be shorter.
+  int r = base64_decode((char *)ch->buf, ch->len, (char *)inp->buf, inp->len);
+  if (r >= 0) {
+    ch->len = r;
+  } else {
+    chunk_free(ch);
+  }
+  return ch;
+}
+static chunk_t *
+b64_enc(const chunk_t *inp)
+{
+  chunk_t *ch = chunk_new(BASE64_BUFSIZE(inp->len));
+  base64_encode((char *)ch->buf, ch->len, (char *)inp->buf, inp->len, 0);
+  ch->len = strlen((char *) ch->buf);
+  return ch;
+}
+
+static chunk_t *
+c_dec(const chunk_t *inp)
+{
+  char *s = tor_memdup_nulterm(inp->buf, inp->len);
+  chunk_t *ch = tor_malloc(sizeof(chunk_t));
+  char *r = NULL;
+  (void) unescape_string(s, &r, &ch->len);
+  tor_free(s);
+  ch->buf = (uint8_t*) r;
+  if (!ch->buf) {
+    tor_free(ch);
+  }
+  return ch;
+}
+static chunk_t *
+c_enc(const chunk_t *inp)
+{
+  char *s = tor_memdup_nulterm(inp->buf, inp->len);
+  chunk_t *ch = tor_malloc(sizeof(chunk_t));
+  ch->buf = (uint8_t*)esc_for_log(s);
+  tor_free(s);
+  ch->len = strlen((char*)ch->buf);
+  return ch;
+}
+
+static int kv_flags = 0;
+static config_line_t *
+kv_dec(const chunk_t *inp)
+{
+  char *s = tor_memdup_nulterm(inp->buf, inp->len);
+  config_line_t *res = kvline_parse(s, kv_flags);
+  tor_free(s);
+  return res;
+}
+static chunk_t *
+kv_enc(const config_line_t *inp)
+{
+  char *s = kvline_encode(inp, kv_flags);
+  if (!s)
+    return NULL;
+  chunk_t *res = tor_malloc(sizeof(chunk_t));
+  res->buf = (uint8_t*)s;
+  res->len = strlen(s);
+  return res;
+}
+
+/* Given an encoder function, a decoder function, and a function to free
+ * the decoded object, check whether any string that successfully decoded
+ * will then survive an encode-decode-encode round-trip unchanged.
+ */
+#define ENCODE_ROUNDTRIP(E,D,FREE)              \
+  STMT_BEGIN {                                  \
+    bool err = false;                           \
+    a = D(&inp);                                \
+    if (!a)                                     \
+      return 0;                                 \
+    b = E(a);                                   \
+    tor_assert(b);                              \
+    c = D(b);                                   \
+    tor_assert(c);                              \
+    d = E(c);                                   \
+    tor_assert(d);                              \
+    if (!chunk_eq(b,d)) {                       \
+      printf("Unequal chunks: %s\n",            \
+             hex_str((char*)b->buf, b->len));   \
+      printf("             vs %s\n",            \
+             hex_str((char*)d->buf, d->len));   \
+      err = true;                               \
+    }                                           \
+    FREE(a);                                    \
+    chunk_free(b);                              \
+    FREE(c);                                    \
+    chunk_free(d);                              \
+    tor_assert(!err);                           \
+  } STMT_END
+
+int
+fuzz_main(const uint8_t *stdin_buf, size_t data_size)
+{
+  if (!data_size)
+    return 0;
+
+  chunk_t inp = { (uint8_t*)stdin_buf, data_size };
+  chunk_t *b=NULL,*d=NULL;
+  void *a=NULL,*c=NULL;
+
+  switch (stdin_buf[0]) {
+    case 0:
+      ENCODE_ROUNDTRIP(b16_enc, b16_dec, chunk_free_);
+      break;
+    case 1:
+      /*
+        XXXX see notes above about our base-32 functions.
+      ENCODE_ROUNDTRIP(b32_enc, b32_dec, chunk_free_);
+      */
+      break;
+    case 2:
+      ENCODE_ROUNDTRIP(b64_enc, b64_dec, chunk_free_);
+      break;
+    case 3:
+      ENCODE_ROUNDTRIP(c_enc, c_dec, chunk_free_);
+      break;
+    case 5:
+      kv_flags = KV_QUOTED|KV_OMIT_KEYS;
+      ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_);
+      break;
+    case 6:
+      kv_flags = 0;
+      ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_);
+      break;
+    }
+
+  return 0;
+}
diff --git a/src/test/fuzz/include.am b/src/test/fuzz/include.am
index 27eeced8c..d0711f05d 100644
--- a/src/test/fuzz/include.am
+++ b/src/test/fuzz/include.am
@@ -153,6 +153,16 @@ src_test_fuzz_fuzz_socks_LDADD = $(FUZZING_LIBS)
 endif
 
 if UNITTESTS_ENABLED
+src_test_fuzz_fuzz_strops_SOURCES = \
+	src/test/fuzz/fuzzing_common.c \
+	src/test/fuzz/fuzz_strops.c
+src_test_fuzz_fuzz_strops_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_strops_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_strops_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_strops_LDADD = $(FUZZING_LIBS)
+endif
+
+if UNITTESTS_ENABLED
 src_test_fuzz_fuzz_vrs_SOURCES = \
 	src/test/fuzz/fuzzing_common.c \
 	src/test/fuzz/fuzz_vrs.c
@@ -176,6 +186,7 @@ FUZZERS = \
 	src/test/fuzz/fuzz-iptsv2 \
 	src/test/fuzz/fuzz-microdesc \
 	src/test/fuzz/fuzz-socks \
+	src/test/fuzz/fuzz-strops \
 	src/test/fuzz/fuzz-vrs
 endif
 
@@ -291,6 +302,15 @@ src_test_fuzz_lf_fuzz_socks_LDADD = $(LIBFUZZER_LIBS)
 endif
 
 if UNITTESTS_ENABLED
+src_test_fuzz_lf_fuzz_strops_SOURCES = \
+	$(src_test_fuzz_fuzz_strops_SOURCES)
+src_test_fuzz_lf_fuzz_strops_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_strops_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_strops_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_strops_LDADD = $(LIBFUZZER_LIBS)
+endif
+
+if UNITTESTS_ENABLED
 src_test_fuzz_lf_fuzz_vrs_SOURCES = \
 	$(src_test_fuzz_fuzz_vrs_SOURCES)
 src_test_fuzz_lf_fuzz_vrs_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
@@ -312,6 +332,7 @@ LIBFUZZER_FUZZERS = \
 	src/test/fuzz/lf-fuzz-iptsv2 \
 	src/test/fuzz/lf-fuzz-microdesc \
 	src/test/fuzz/lf-fuzz-socks \
+	src/test/fuzz/lf-fuzz-strops \
 	src/test/fuzz/lf-fuzz-vrs
 
 else
@@ -406,6 +427,13 @@ src_test_fuzz_liboss_fuzz_socks_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
 endif
 
 if UNITTESTS_ENABLED
+src_test_fuzz_liboss_fuzz_strops_a_SOURCES = \
+	$(src_test_fuzz_fuzz_strops_SOURCES)
+src_test_fuzz_liboss_fuzz_strops_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
+src_test_fuzz_liboss_fuzz_strops_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+endif
+
+if UNITTESTS_ENABLED
 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)
@@ -425,6 +453,7 @@ OSS_FUZZ_FUZZERS = \
 	src/test/fuzz/liboss-fuzz-iptsv2.a \
 	src/test/fuzz/liboss-fuzz-microdesc.a \
 	src/test/fuzz/liboss-fuzz-socks.a \
+	src/test/fuzz/liboss-fuzz-strops.a \
 	src/test/fuzz/liboss-fuzz-vrs.a
 
 else





More information about the tor-commits mailing list