You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@qpid.apache.org by "Jiri Daněk (Jira)" <ji...@apache.org> on 2021/04/18 06:43:00 UTC
[jira] [Updated] (DISPATCH-2060) use-after free in
qd_alloc_deref_safe_ptr if a pool item has been freed due to
global_free_list size limit
[ https://issues.apache.org/jira/browse/DISPATCH-2060?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Jiri Daněk updated DISPATCH-2060:
---------------------------------
Description:
This is something that is unlikely to occur because the global_free_list size limit is unset by default and as far as I can tell, nobody sets it (except of one small unittest). But if it is set, then it may happen that an item gets freed while there is still a {{safe pointer}} pointing to it. The check in {{qd_alloc_deref_safe_ptr}} to see if safe pointer is still valid involves accessing the item memory. Since that's been freed, the operation is a use-after-free.
{code}
static char *test_safe_references(void *context)
{
object_t *obj = new_object_t();
object_t_sp safe_obj;
set_safe_ptr_object_t(obj, &safe_obj);
object_t *alias = safe_deref_object_t(safe_obj);
if (obj != alias)
return "Safe alias was not equal to the original pointer";
free_object_t(obj);
alias = safe_deref_object_t(safe_obj); // HERE is ../tests/alloc_test.c:90
if (alias != 0)
return "Safe dereference of a freed object was not null";
return 0;
}
{code}
{noformat}
==21009==ERROR: AddressSanitizer: heap-use-after-free on address 0x611000003f48 at pc 0x7fcf829bb060 bp 0x7ffc752e1780 sp 0x7ffc752e1778
READ of size 4 at 0x611000003f48 thread T0
#0 0x7fcf829bb05f in qd_alloc_sequence ../src/alloc_pool.c:523
#1 0x4161f2 in qd_alloc_deref_safe_ptr ../include/qpid/dispatch/alloc_pool.h:102
#2 0x4161f2 in safe_deref_object_t ../tests/alloc_test.c:35
#3 0x41638c in test_safe_references ../tests/alloc_test.c:90
#4 0x4163dc in alloc_tests ../tests/alloc_test.c:105
#5 0x406c30 in main ../tests/run_unit_tests.c:65
#6 0x7fcf81545cbc in __libc_start_main (/nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libc.so.6+0x23cbc)
#7 0x404959 in _start (/home/jdanek/repos/qpid/qpid-dispatch/cmake-build-debug-asan/tests/unit_tests+0x404959)
0x611000003f48 is located 136 bytes inside of 192-byte region [0x611000003ec0,0x611000003f80)
freed by thread T0 here:
#0 0x7fcf8318eb6f in __interceptor_free (/nix/store/g40sl3zh3nv52vj0mrl4iki5iphh5ika-gcc-10.2.0-lib/lib/libasan.so.6+0xacb6f)
#1 0x7fcf829badae in qd_dealloc ../src/alloc_pool.c:503
#2 0x41609d in free_object_t ../tests/alloc_test.c:35
#3 0x41636a in test_safe_references ../tests/alloc_test.c:89
#4 0x4163dc in alloc_tests ../tests/alloc_test.c:105
#5 0x406c30 in main ../tests/run_unit_tests.c:65
#6 0x7fcf81545cbc in __libc_start_main (/nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libc.so.6+0x23cbc)
previously allocated by thread T0 here:
#0 0x7fcf8318fa3c in __interceptor_posix_memalign (/nix/store/g40sl3zh3nv52vj0mrl4iki5iphh5ika-gcc-10.2.0-lib/lib/libasan.so.6+0xada3c)
#1 0x7fcf829b78ea in qd_alloc ../src/alloc_pool.c:398
#2 0x41607a in new_object_t ../tests/alloc_test.c:35
#3 0x4162e8 in test_safe_references ../tests/alloc_test.c:80
#4 0x4163dc in alloc_tests ../tests/alloc_test.c:105
#5 0x406c30 in main ../tests/run_unit_tests.c:65
#6 0x7fcf81545cbc in __libc_start_main (/nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libc.so.6+0x23cbc)
SUMMARY: AddressSanitizer: heap-use-after-free ../src/alloc_pool.c:523 in qd_alloc_sequence
Shadow bytes around the buggy address:
0x0c227fff8790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c227fff87a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff87b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c227fff87c0: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
0x0c227fff87d0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
=>0x0c227fff87e0: fd fd fd fd fd fd fd fd fd[fd]fd fd fd fd fd fd
0x0c227fff87f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff8800: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff8810: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff8820: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff8830: 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
==21009==ABORTING
{noformat}
was:
This is something that is unlikely to occur because the global_free_list size limit is unset by default. But if it is set, then it may happen that an item gets freed while there is still a {{safe pointer}} pointing to it. The check in {{qd_alloc_deref_safe_ptr}} to see if safe pointer is still valid involves accessing the item memory. Since that's been freed, the operation is a use-after-free.
{code}
static char *test_safe_references(void *context)
{
object_t *obj = new_object_t();
object_t_sp safe_obj;
set_safe_ptr_object_t(obj, &safe_obj);
object_t *alias = safe_deref_object_t(safe_obj);
if (obj != alias)
return "Safe alias was not equal to the original pointer";
free_object_t(obj);
alias = safe_deref_object_t(safe_obj); // HERE is ../tests/alloc_test.c:90
if (alias != 0)
return "Safe dereference of a freed object was not null";
return 0;
}
{code}
{noformat}
==21009==ERROR: AddressSanitizer: heap-use-after-free on address 0x611000003f48 at pc 0x7fcf829bb060 bp 0x7ffc752e1780 sp 0x7ffc752e1778
READ of size 4 at 0x611000003f48 thread T0
#0 0x7fcf829bb05f in qd_alloc_sequence ../src/alloc_pool.c:523
#1 0x4161f2 in qd_alloc_deref_safe_ptr ../include/qpid/dispatch/alloc_pool.h:102
#2 0x4161f2 in safe_deref_object_t ../tests/alloc_test.c:35
#3 0x41638c in test_safe_references ../tests/alloc_test.c:90
#4 0x4163dc in alloc_tests ../tests/alloc_test.c:105
#5 0x406c30 in main ../tests/run_unit_tests.c:65
#6 0x7fcf81545cbc in __libc_start_main (/nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libc.so.6+0x23cbc)
#7 0x404959 in _start (/home/jdanek/repos/qpid/qpid-dispatch/cmake-build-debug-asan/tests/unit_tests+0x404959)
0x611000003f48 is located 136 bytes inside of 192-byte region [0x611000003ec0,0x611000003f80)
freed by thread T0 here:
#0 0x7fcf8318eb6f in __interceptor_free (/nix/store/g40sl3zh3nv52vj0mrl4iki5iphh5ika-gcc-10.2.0-lib/lib/libasan.so.6+0xacb6f)
#1 0x7fcf829badae in qd_dealloc ../src/alloc_pool.c:503
#2 0x41609d in free_object_t ../tests/alloc_test.c:35
#3 0x41636a in test_safe_references ../tests/alloc_test.c:89
#4 0x4163dc in alloc_tests ../tests/alloc_test.c:105
#5 0x406c30 in main ../tests/run_unit_tests.c:65
#6 0x7fcf81545cbc in __libc_start_main (/nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libc.so.6+0x23cbc)
previously allocated by thread T0 here:
#0 0x7fcf8318fa3c in __interceptor_posix_memalign (/nix/store/g40sl3zh3nv52vj0mrl4iki5iphh5ika-gcc-10.2.0-lib/lib/libasan.so.6+0xada3c)
#1 0x7fcf829b78ea in qd_alloc ../src/alloc_pool.c:398
#2 0x41607a in new_object_t ../tests/alloc_test.c:35
#3 0x4162e8 in test_safe_references ../tests/alloc_test.c:80
#4 0x4163dc in alloc_tests ../tests/alloc_test.c:105
#5 0x406c30 in main ../tests/run_unit_tests.c:65
#6 0x7fcf81545cbc in __libc_start_main (/nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libc.so.6+0x23cbc)
SUMMARY: AddressSanitizer: heap-use-after-free ../src/alloc_pool.c:523 in qd_alloc_sequence
Shadow bytes around the buggy address:
0x0c227fff8790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c227fff87a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff87b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c227fff87c0: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
0x0c227fff87d0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
=>0x0c227fff87e0: fd fd fd fd fd fd fd fd fd[fd]fd fd fd fd fd fd
0x0c227fff87f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff8800: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff8810: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff8820: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c227fff8830: 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
==21009==ABORTING
{noformat}
> use-after free in qd_alloc_deref_safe_ptr if a pool item has been freed due to global_free_list size limit
> ----------------------------------------------------------------------------------------------------------
>
> Key: DISPATCH-2060
> URL: https://issues.apache.org/jira/browse/DISPATCH-2060
> Project: Qpid Dispatch
> Issue Type: Bug
> Affects Versions: 1.15.0
> Reporter: Jiri Daněk
> Priority: Trivial
>
> This is something that is unlikely to occur because the global_free_list size limit is unset by default and as far as I can tell, nobody sets it (except of one small unittest). But if it is set, then it may happen that an item gets freed while there is still a {{safe pointer}} pointing to it. The check in {{qd_alloc_deref_safe_ptr}} to see if safe pointer is still valid involves accessing the item memory. Since that's been freed, the operation is a use-after-free.
> {code}
> static char *test_safe_references(void *context)
> {
> object_t *obj = new_object_t();
> object_t_sp safe_obj;
> set_safe_ptr_object_t(obj, &safe_obj);
> object_t *alias = safe_deref_object_t(safe_obj);
> if (obj != alias)
> return "Safe alias was not equal to the original pointer";
> free_object_t(obj);
> alias = safe_deref_object_t(safe_obj); // HERE is ../tests/alloc_test.c:90
> if (alias != 0)
> return "Safe dereference of a freed object was not null";
> return 0;
> }
> {code}
> {noformat}
> ==21009==ERROR: AddressSanitizer: heap-use-after-free on address 0x611000003f48 at pc 0x7fcf829bb060 bp 0x7ffc752e1780 sp 0x7ffc752e1778
> READ of size 4 at 0x611000003f48 thread T0
> #0 0x7fcf829bb05f in qd_alloc_sequence ../src/alloc_pool.c:523
> #1 0x4161f2 in qd_alloc_deref_safe_ptr ../include/qpid/dispatch/alloc_pool.h:102
> #2 0x4161f2 in safe_deref_object_t ../tests/alloc_test.c:35
> #3 0x41638c in test_safe_references ../tests/alloc_test.c:90
> #4 0x4163dc in alloc_tests ../tests/alloc_test.c:105
> #5 0x406c30 in main ../tests/run_unit_tests.c:65
> #6 0x7fcf81545cbc in __libc_start_main (/nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libc.so.6+0x23cbc)
> #7 0x404959 in _start (/home/jdanek/repos/qpid/qpid-dispatch/cmake-build-debug-asan/tests/unit_tests+0x404959)
> 0x611000003f48 is located 136 bytes inside of 192-byte region [0x611000003ec0,0x611000003f80)
> freed by thread T0 here:
> #0 0x7fcf8318eb6f in __interceptor_free (/nix/store/g40sl3zh3nv52vj0mrl4iki5iphh5ika-gcc-10.2.0-lib/lib/libasan.so.6+0xacb6f)
> #1 0x7fcf829badae in qd_dealloc ../src/alloc_pool.c:503
> #2 0x41609d in free_object_t ../tests/alloc_test.c:35
> #3 0x41636a in test_safe_references ../tests/alloc_test.c:89
> #4 0x4163dc in alloc_tests ../tests/alloc_test.c:105
> #5 0x406c30 in main ../tests/run_unit_tests.c:65
> #6 0x7fcf81545cbc in __libc_start_main (/nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libc.so.6+0x23cbc)
> previously allocated by thread T0 here:
> #0 0x7fcf8318fa3c in __interceptor_posix_memalign (/nix/store/g40sl3zh3nv52vj0mrl4iki5iphh5ika-gcc-10.2.0-lib/lib/libasan.so.6+0xada3c)
> #1 0x7fcf829b78ea in qd_alloc ../src/alloc_pool.c:398
> #2 0x41607a in new_object_t ../tests/alloc_test.c:35
> #3 0x4162e8 in test_safe_references ../tests/alloc_test.c:80
> #4 0x4163dc in alloc_tests ../tests/alloc_test.c:105
> #5 0x406c30 in main ../tests/run_unit_tests.c:65
> #6 0x7fcf81545cbc in __libc_start_main (/nix/store/q53f5birhik4dxg3q3r2g5f324n7r5mc-glibc-2.31-74/lib/libc.so.6+0x23cbc)
> SUMMARY: AddressSanitizer: heap-use-after-free ../src/alloc_pool.c:523 in qd_alloc_sequence
> Shadow bytes around the buggy address:
> 0x0c227fff8790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> 0x0c227fff87a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
> 0x0c227fff87b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> 0x0c227fff87c0: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
> 0x0c227fff87d0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
> =>0x0c227fff87e0: fd fd fd fd fd fd fd fd fd[fd]fd fd fd fd fd fd
> 0x0c227fff87f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
> 0x0c227fff8800: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
> 0x0c227fff8810: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
> 0x0c227fff8820: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
> 0x0c227fff8830: 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
> ==21009==ABORTING
> {noformat}
--
This message was sent by Atlassian Jira
(v8.3.4#803005)
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@qpid.apache.org
For additional commands, e-mail: dev-help@qpid.apache.org