Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use-after-free push_stack in /src/cups/cups/raster-interpret.c #768

Closed
Jminis opened this issue Aug 1, 2023 · 1 comment
Closed

Use-after-free push_stack in /src/cups/cups/raster-interpret.c #768

Jminis opened this issue Aug 1, 2023 · 1 comment
Assignees
Labels
bug Something isn't working priority-low
Milestone

Comments

@Jminis
Copy link

Jminis commented Aug 1, 2023

Description

Hello, while performing fuzzing based on the information registered in OSS-Fuzz, a UAF crash was discovered. I would like to share some basic analysis and crash data related to this. (Additionally, this issue does not have a significantly detrimental effect on the program.)

Crash Log

/out/FuzzCUPS -rss_limit_mb=2560 -timeout=25 FuzzCUPS_poc/cups--FuzzCUPS--crash-ec73921dbc52d3ce45efccb47567ba46-2023-07-27-16:03:10 # /tmp/FuzzCUPS_corpus < /dev/null
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2666470492
INFO: Loaded 1 modules   (10782 inline 8-bit counters): 10782 [0x724ea0, 0x7278be),
INFO: Loaded 1 PC tables (10782 PCs): 10782 [0x7278c0,0x751aa0),
/out/FuzzCUPS: Running 1 inputs 1 time(s) each.
Running: FuzzCUPS_poc/cups--FuzzCUPS--crash-ec73921dbc52d3ce45efccb47567ba46-2023-07-27-16:03:10
=================================================================
==12==ERROR: AddressSanitizer: heap-use-after-free on address 0x61d0000007d0 at pc 0x000000530bd1 bp 0x7ffc688612a0 sp 0x7ffc68860a70
READ of size 72 at 0x61d0000007d0 thread T0
SCARINESS: 54 (multi-byte-read-heap-use-after-free)
    #0 0x530bd0 in __asan_memcpy /src/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3
    #1 0x5778d7 in memcpy /usr/include/x86_64-linux-gnu/bits/string_fortified.h:34:10
    #2 0x5778d7 in push_stack /src/cups/cups/raster-interpret.c:955:3
    #3 0x5778d7 in copy_stack /src/cups/cups/raster-interpret.c:730:10
    #4 0x573196 in _cupsRasterExecPS /src/cups/cups/raster-interpret.c
    #5 0x56ee5c in LLVMFuzzerTestOneInput /src/cups/fuzzer/FuzzCUPS.c:45:5
    #6 0x4406b3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:611:15
    #7 0x42be12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
    #8 0x4316bc in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:860:9
    #9 0x45abf2 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    #10 0x7f677bc91082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
    #11 0x421fdd in _start (/out/FuzzCUPS+0x421fdd)

DEDUP_TOKEN: __asan_memcpy--memcpy--push_stack
0x61d0000007d0 is located 1872 bytes inside of 2304-byte region [0x61d000000080,0x61d000000980)
freed by thread T0 here:
    #0 0x531c4c in __interceptor_realloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:85:3
    #1 0x577844 in push_stack /src/cups/cups/raster-interpret.c:944:17
    #2 0x577844 in copy_stack /src/cups/cups/raster-interpret.c:730:10
    #3 0x573196 in _cupsRasterExecPS /src/cups/cups/raster-interpret.c
    #4 0x56ee5c in LLVMFuzzerTestOneInput /src/cups/fuzzer/FuzzCUPS.c:45:5
    #5 0x4406b3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:611:15
    #6 0x42be12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
    #7 0x4316bc in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:860:9
    #8 0x45abf2 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    #9 0x7f677bc91082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)

DEDUP_TOKEN: __interceptor_realloc--push_stack--copy_stack
previously allocated by thread T0 here:
    #0 0x531a1e in __interceptor_calloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:77:3
    #1 0x570d1b in new_stack /src/cups/cups/raster-interpret.c:899:19
    #2 0x570d1b in _cupsRasterExecPS /src/cups/cups/raster-interpret.c:529:13
    #3 0x56ee5c in LLVMFuzzerTestOneInput /src/cups/fuzzer/FuzzCUPS.c:45:5
    #4 0x4406b3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:611:15
    #5 0x42be12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
    #6 0x4316bc in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:860:9
    #7 0x45abf2 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    #8 0x7f677bc91082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)

DEDUP_TOKEN: __interceptor_calloc--new_stack--_cupsRasterExecPS
SUMMARY: AddressSanitizer: heap-use-after-free /src/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3 in __asan_memcpy
Shadow bytes around the buggy address:
  0x0c3a7fff80a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c3a7fff80b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c3a7fff80c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c3a7fff80d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c3a7fff80e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x0c3a7fff80f0: fd fd fd fd fd fd fd fd fd fd[fd]fd fd fd fd fd
  0x0c3a7fff8100: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c3a7fff8110: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c3a7fff8120: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c3a7fff8130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c3a7fff8140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==12==ABORTING

Analyze

From the debugging results, the obj structure was in a freed state at memcpy(temp, obj, sizeof(_cups_ps_obj_t)); in the push_stack function below.
The point at which it is freed seems to be when temp = realloc(st->objs, (size_t)st->alloc_objs * sizeof(_cups_ps_obj_t))) == NULL, as the memory of the heap area pointed to by obj is freed by realloc.

static _cups_ps_obj_t	*		/* O - New object */
push_stack(_cups_ps_stack_t *st,	/* I - Stack */
           _cups_ps_obj_t   *obj)	/* I - Object */
{
  _cups_ps_obj_t	*temp;		/* New object */


  if (st->num_objs >= st->alloc_objs)
  {


    st->alloc_objs += 32;

    if ((temp = realloc(st->objs, (size_t)st->alloc_objs *
                                  sizeof(_cups_ps_obj_t))) == NULL)
      return (NULL);

    st->objs = temp;
    memset(temp + st->num_objs, 0, 32 * sizeof(_cups_ps_obj_t));
  }

  temp = st->objs + st->num_objs;
  st->num_objs ++;

  memcpy(temp, obj, sizeof(_cups_ps_obj_t));

  return (temp);
}

Here, obj is an argument at the call of push_stack in copy_stack, and it was pointing to the st structure that is freed in realloc.

static int				/* O - 0 on success, -1 on error */
copy_stack(_cups_ps_stack_t *st,	/* I - Stack */
           int              c)		/* I - Number of objects to copy */
{
  int	n;				/* Index */


  if (c < 0)
    return (-1);
  else if (c == 0)
    return (0);

  if ((n = st->num_objs - c) < 0)
    return (-1);

  while (c > 0)
  {
    if (!push_stack(st, st->objs + n))
      return (-1);

    n ++;
    c --;
  }

  return (0);
}
@michaelrsweet michaelrsweet self-assigned this Aug 2, 2023
@michaelrsweet michaelrsweet added bug Something isn't working priority-low labels Aug 2, 2023
@michaelrsweet michaelrsweet added this to the v2.4.x milestone Aug 2, 2023
@michaelrsweet
Copy link
Member

Simple enough fix - just need to make a temporary copy of the stack object before copying...

[master d2edfc6] Fix a bug in the copy stack code (Issue #768)

[2.4.x cd01b4d] Fix a bug in the copy stack code (Issue #768)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working priority-low
Projects
None yet
Development

No branches or pull requests

2 participants