Browse Source

Unit tests for our zlib code to test and reject compression bombs.

Nick Mathewson 8 years ago
parent
commit
f016213f7f
2 changed files with 51 additions and 0 deletions
  1. 3 0
      changes/test_zlib_bombs
  2. 48 0
      src/test/test_util.c

+ 3 - 0
changes/test_zlib_bombs

@@ -0,0 +1,3 @@
+  o Testing:
+    - We now have unit tests for our code to reject zlib "compression bombs".
+      (Fortunately, the code works fine.)

+ 48 - 0
src/test/test_util.c

@@ -1836,6 +1836,53 @@ test_util_gzip(void *arg)
   tor_free(buf1);
 }
 
+static void
+test_util_gzip_compression_bomb(void *arg)
+{
+  /* A 'compression bomb' is a very small object that uncompresses to a huge
+   * one. Most compression formats support them, but they can be a DOS vector.
+   * In Tor we try not to generate them, and we don't accept them.
+   */
+  (void) arg;
+  size_t one_million = 1<<20;
+  char *one_mb = tor_malloc_zero(one_million);
+  char *result = NULL;
+  size_t result_len = 0;
+  tor_zlib_state_t *state = NULL;
+
+  /* Make sure we can't produce a compression bomb */
+  tt_int_op(-1, OP_EQ, tor_gzip_compress(&result, &result_len,
+                                         one_mb, one_million,
+                                         ZLIB_METHOD));
+
+  /* Here's a compression bomb that we made manually. */
+  const char compression_bomb[1039] =
+    { 0x78, 0xDA, 0xED, 0xC1, 0x31, 0x01, 0x00, 0x00, 0x00, 0xC2,
+      0xA0, 0xF5, 0x4F, 0x6D, 0x08, 0x5F, 0xA0 /* .... */ };
+  tt_int_op(-1, OP_EQ, tor_gzip_uncompress(&result, &result_len,
+                                           compression_bomb, 1039,
+                                           ZLIB_METHOD, 0, LOG_WARN));
+
+
+  /* Now try streaming that. */
+  state = tor_zlib_new(0, ZLIB_METHOD, HIGH_COMPRESSION);
+  tor_zlib_output_t r;
+  const char *inp = compression_bomb;
+  size_t inlen = 1039;
+  do {
+    char *outp = one_mb;
+    size_t outleft = 4096; /* small on purpose */
+    r = tor_zlib_process(state, &outp, &outleft, &inp, &inlen, 0);
+    tt_int_op(inlen, OP_NE, 0);
+  } while (r == TOR_ZLIB_BUF_FULL);
+
+  tt_int_op(r, OP_EQ, TOR_ZLIB_ERR);
+
+ done:
+  tor_free(one_mb);
+  tor_zlib_free(state);
+}
+
 /** Run unit tests for mmap() wrapper functionality. */
 static void
 test_util_mmap(void *arg)
@@ -4800,6 +4847,7 @@ struct testcase_t util_tests[] = {
   UTIL_LEGACY(strmisc),
   UTIL_LEGACY(pow2),
   UTIL_LEGACY(gzip),
+  UTIL_LEGACY(gzip_compression_bomb),
   UTIL_LEGACY(datadir),
   UTIL_LEGACY(memarea),
   UTIL_LEGACY(control_formats),