Heap Use After Free in the deletestringbox() function (READ of size 8 )
Hi,
While fuzzing dpic 68ab9432 with AFL++, I found a heap use-after-free in the deletestringbox() function, in dpic.y.
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.2 LTS"
Attaching a reproducer: test03
the issue can be reproduced by running:
dpic test03
With ASAN report
=================================================================
==18==ERROR: AddressSanitizer: heap-use-after-free on address 0x60d000000060 at pc 0x000000528bfe bp 0x7fffffffa5a0 sp 0x7fffffffa598
READ of size 8 at 0x60d000000060 thread T0
#0 0x528bfd in deletestringbox /src/dpic/dpic.y:5716:19
#1 0x4fba03 in yyparse /src/dpic/dpic.y
#2 0x4e67b3 in main /src/dpic/main.c:1795:13
#3 0x7ffff7c570b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16
#4 0x41c48d in _start (/src/dpic/dpic+0x41c48d)
0x60d000000060 is located 32 bytes inside of 136-byte region [0x60d000000040,0x60d0000000c8)
freed by thread T0 here:
#0 0x497482 in free (/src/dpic/dpic+0x497482)
#1 0x51b74d in deletetree /src/dpic/dpic.y
previously allocated by thread T0 here:
#0 0x4976ed in malloc (/src/dpic/dpic+0x4976ed)
#1 0x525e42 in newprim /src/dpic/dpic.y
SUMMARY: AddressSanitizer: heap-use-after-free /src/dpic/dpic.y:5716:19 in deletestringbox
Shadow bytes around the buggy address:
0x0c1a7fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c1a7fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c1a7fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c1a7fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c1a7fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c1a7fff8000: fa fa fa fa fa fa fa fa fd fd fd fd[fd]fd fd fd
0x0c1a7fff8010: fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa
0x0c1a7fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c1a7fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c1a7fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c1a7fff8050: 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
Shadow gap: cc
==18==ABORTING
GDB report:
$ gdb -q ./dpic core
Reading symbols from ./dpic...
[New LWP 3062595]
Core was generated by `./dpic ./test03'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 bval (buf=0x1000000000000 <error: Cannot access memory at address 0x1000000000000>) at dpic.y:4919
4919 if (bval(pn->segmnt) > 1) {
(gdb) bt
#0 bval (buf=0x1000000000000 <error: Cannot access memory at address 0x1000000000000>) at dpic.y:4919
#1 deletename (head=0x4394e8) at dpic.y:4919
#2 0x000000000040778d in deletetree (p=0x7fffffffa728) at dpic.y:3906
#3 0x0000000000409184 in deletestringbox (pr=pr@entry=0x7fffffffa728) at dpic.y:5724
#4 0x000000000041079d in yyparse () at dpic.y:2810
#5 0x0000000000404830 in main (argc=<optimized out>, argv=<optimized out>) at main.c:1795
(gdb)
Valgrind report:
$ valgrind --track-origins=yes ./dpic ./test03
==55== Memcheck, a memory error detector
==55== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==55== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==55== Command: ./dpic ./test03
==55==
Char chr(127)"\177" unknown
*** dpic ERROR: file "./test03" line 1:
>
Character not recognized: ignored
*** dpic ERROR: file "./test03" line 1:
>0dbq
Improper use of logical operator
*** dpic ERROR: file "./test03" line 1:
>0dbq
Improper use of logical operator
==55== Invalid read of size 8
==55== at 0x1139D5: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B4A3: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Address 0x4b9a3e0 is 32 bytes inside a block of size 136 free'd
==55== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x111F92: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B57F: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Block was alloc'd at
==55== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x112078: newprim (in /src/dpic/dpic)
==55== by 0x116888: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55==
==55== Invalid write of size 8
==55== at 0x111F10: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B4A3: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Address 0x4b9a3e0 is 32 bytes inside a block of size 136 free'd
==55== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x111F92: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B57F: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Block was alloc'd at
==55== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x112078: newprim (in /src/dpic/dpic)
==55== by 0x116888: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55==
==55== Invalid read of size 8
==55== at 0x111F3E: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B4A3: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Address 0x4b9a3f0 is 48 bytes inside a block of size 136 free'd
==55== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x111F92: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B57F: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Block was alloc'd at
==55== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x112078: newprim (in /src/dpic/dpic)
==55== by 0x116888: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55==
==55== Invalid read of size 8
==55== at 0x111F20: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B4A3: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Address 0x4b9a3e8 is 40 bytes inside a block of size 136 free'd
==55== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x111F92: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B57F: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Block was alloc'd at
==55== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x112078: newprim (in /src/dpic/dpic)
==55== by 0x116888: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55==
==55== Invalid read of size 8
==55== at 0x111F54: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B4A3: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Address 0x4b9a3e0 is 32 bytes inside a block of size 136 free'd
==55== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x111F92: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B57F: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Block was alloc'd at
==55== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x112078: newprim (in /src/dpic/dpic)
==55== by 0x116888: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55==
==55== Invalid read of size 8
==55== at 0x111DA0: deletename (in /src/dpic/dpic)
==55== by 0x111F60: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B4A3: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Address 0x4b9a3d8 is 24 bytes inside a block of size 136 free'd
==55== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x111F92: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B57F: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Block was alloc'd at
==55== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x112078: newprim (in /src/dpic/dpic)
==55== by 0x116888: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55==
==55== Invalid read of size 8
==55== at 0x111DA0: deletename (in /src/dpic/dpic)
==55== by 0x111F6C: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B4A3: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Address 0x4b9a3d0 is 16 bytes inside a block of size 136 free'd
==55== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x111F92: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B57F: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Block was alloc'd at
==55== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x112078: newprim (in /src/dpic/dpic)
==55== by 0x116888: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55==
==55== Invalid read of size 8
==55== at 0x111DA0: deletename (in /src/dpic/dpic)
==55== by 0x111F78: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B4A3: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Address 0x4b9a3c8 is 8 bytes inside a block of size 136 free'd
==55== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x111F92: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B57F: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Block was alloc'd at
==55== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x112078: newprim (in /src/dpic/dpic)
==55== by 0x116888: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55==
==55== Invalid read of size 8
==55== at 0x111DA0: deletename (in /src/dpic/dpic)
==55== by 0x111F80: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B4A3: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Address 0x4b9a3c0 is 0 bytes inside a block of size 136 free'd
==55== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x111F92: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B57F: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Block was alloc'd at
==55== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x112078: newprim (in /src/dpic/dpic)
==55== by 0x116888: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55==
==55== Invalid read of size 4
==55== at 0x111F84: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B4A3: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Address 0x4b9a420 is 96 bytes inside a block of size 136 free'd
==55== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x111F92: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B57F: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Block was alloc'd at
==55== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x112078: newprim (in /src/dpic/dpic)
==55== by 0x116888: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55==
==55== Invalid free() / delete / delete[] / realloc()
==55== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x111F92: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B4A3: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Address 0x4b9a3c0 is 0 bytes inside a block of size 136 free'd
==55== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x111F92: deletetree (in /src/dpic/dpic)
==55== by 0x113A09: deletestringbox (in /src/dpic/dpic)
==55== by 0x11B57F: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55== Block was alloc'd at
==55== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==55== by 0x112078: newprim (in /src/dpic/dpic)
==55== by 0x116888: yyparse (in /src/dpic/dpic)
==55== by 0x10EDE7: main (in /src/dpic/dpic)
==55==
*** dpic: maximum error count exceeded
==55==
==55== HEAP SUMMARY:
==55== in use at exit: 4,592 bytes in 4 blocks
==55== total heap usage: 9 allocs, 6 frees, 17,048 bytes allocated
==55==
==55== LEAK SUMMARY:
==55== definitely lost: 0 bytes in 0 blocks
==55== indirectly lost: 0 bytes in 0 blocks
==55== possibly lost: 0 bytes in 0 blocks
==55== still reachable: 4,592 bytes in 4 blocks
==55== suppressed: 0 bytes in 0 blocks
==55== Rerun with --leak-check=full to see details of leaked memory
==55==
==55== For lists of detected and suppressed errors, rerun with: -s
==55== ERROR SUMMARY: 11 errors from 11 contexts (suppressed: 0 from 0)