Ticket #30041: 0001-POC-out-of-boundary-access-with-large-buffers.patch

File 0001-POC-out-of-boundary-access-with-large-buffers.patch, 3.0 KB (added by asn, 5 months ago)
  • src/test/test_buffers.c

    From 79aee60fe095061d7010101078c78deb49bb14b6 Mon Sep 17 00:00:00 2001
    From: Tobias Stoeckmann <tobias@stoeckmann.org>
    Date: Sun, 31 Mar 2019 17:31:49 +0200
    Subject: [PATCH 1/3] POC: out of boundary access with large buffers
    
    This test case is a proof of concept that it is possible to trigger out
    of boundary accesses with large buffers. This will most likely only
    work on 64 bit systems with at least 5 GB of RAM.
    
    Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
    ---
     src/test/test_buffers.c | 57 +++++++++++++++++++++++++++++++++++++++++
     1 file changed, 57 insertions(+)
    
    diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c
    index 97311c85c..416dd8d19 100644
    a b test_buffers_basic(void *arg) 
    201201    buf_free(buf2);
    202202}
    203203
     204static void
     205test_buffer_overflow(void *arg)
     206{
     207  const size_t chunklen = 0x1FFFFFFF; /* 512 MB - 1 byte */
     208  size_t len_out;
     209  char *chunk;
     210  const char *head_out;
     211  buf_t *buf, *huge;
     212  int i;
     213
     214  /* Create long string that can be added to a buffer. */
     215  chunk = tor_malloc(chunklen + 1);
     216  memset(chunk, 'A', chunklen);
     217  chunk[chunklen] = '\0';
     218
     219  /*
     220   * Prepare buffer "huge" by adding 5 chunks each containing a
     221   * string of almost 512 MB in size, which means that datalen
     222   * of buffer will exceed INT_MAX (2 GB).
     223   */
     224  huge = buf_new();
     225  buf = buf_new();
     226  for (i = 0; i < 5; i++) {
     227    buf_add_string(buf, chunk);
     228    buf_move_all(huge, buf);
     229  }
     230  tor_free(chunk);
     231
     232  /* Perform pullup to get all bytes into one huge chunk. */
     233  buf_pullup(huge, SIZE_T_CEILING, &head_out, &len_out);
     234
     235  /*
     236   * Create a small chunk and add huge one in buffer "buf".
     237   *
     238   * This is needed because otherwise buf_find_pos_of_char would trigger
     239   * an assertion because it verifies pos against datalen.
     240   *
     241   * We want to get past that assertion for this proof of concept, so we
     242   * add a small innocent chunk at the start.
     243   *
     244   * When buf_matches_at_pos is called afterwards, only buf_pos_inc is
     245   * used which is not protected against integer overflow.
     246   */
     247  buf_add(buf, chunk, 1);
     248  buf_move_all(buf, huge);
     249
     250  /*
     251   * Now try to find offset of a string that is longer than INT_MAX.
     252   *
     253   * NOTE: Using head_out like this is fortunately "safe" in this
     254   * situation because buf_move_all does not adjust memory addresses
     255   * of chunks. This dirty trick saves us quite some RAM.
     256   */
     257  buf_find_string_offset(buf, head_out, len_out);
     258}
     259
    204260static void
    205261test_buffer_pullup(void *arg)
    206262{
    test_buffer_peek_startswith(void *arg) 
    798854struct testcase_t buffer_tests[] = {
    799855  { "basic", test_buffers_basic, TT_FORK, NULL, NULL },
    800856  { "copy", test_buffer_copy, TT_FORK, NULL, NULL },
     857  { "overflow", test_buffer_overflow, TT_FORK, NULL, NULL },
    801858  { "pullup", test_buffer_pullup, TT_FORK, NULL, NULL },
    802859  { "startswith", test_buffer_peek_startswith, 0, NULL, NULL },
    803860  { "allocation_tracking", test_buffer_allocation_tracking, TT_FORK,