The qcheck tool exposes an out of bounds heap read access when recompiling it with address sanitizer (-fsanitize=address in CFLAGS). This can be tested with the testsuite (make check). Manually test it: ./configure CFLAGS="-fsanitize=address -g" LDFLAGS="-fsanitize=address -g" make ROOT=tests/qcheck/root/ Q_VDB=/ ./qcheck a-b/pkg -s ^/missing-dir/.* This is the trace from address sanitizer, seems something in the regexp checking: ================================================================= ==22916==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000e718 at pc 0x41c8e1 bp 0x7ffe92883770 sp 0x7ffe92883760 READ of size 8 at 0x60200000e718 thread T0 #0 0x41c8e0 in qcheck_process_contents /mnt/ram/portage-utils-0.56/qcheck.c:116 #1 0x41f00c in qcheck_cb /mnt/ram/portage-utils-0.56/qcheck.c:354 #2 0x410a85 in q_vdb_foreach_pkg_sorted libq/vdb.c:337 #3 0x41f45f in qcheck_main /mnt/ram/portage-utils-0.56/qcheck.c:402 #4 0x41b2dc in q_main /mnt/ram/portage-utils-0.56/q.c:79 #5 0x41ad2f in main /mnt/ram/portage-utils-0.56/main.c:1374 #6 0x7f0b5709ef9f in __libc_start_main (/lib64/libc.so.6+0x1ff9f) #7 0x403df8 (/mnt/ram/portage-utils-0.56/q+0x403df8) 0x60200000e718 is located 0 bytes to the right of 8-byte region [0x60200000e710,0x60200000e718) allocated by thread T0 here: #0 0x7f0b57678a66 in __interceptor_realloc (/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/libasan.so.1+0x57a66) #1 0x404a48 in xrealloc libq/xmalloc.c:57 #2 0x40a5a7 in xarraypush libq/xarray.c:24 #3 0x41f355 in qcheck_main /mnt/ram/portage-utils-0.56/qcheck.c:387 #4 0x41b2dc in q_main /mnt/ram/portage-utils-0.56/q.c:79 #5 0x41ad2f in main /mnt/ram/portage-utils-0.56/main.c:1374 #6 0x7f0b5709ef9f in __libc_start_main (/lib64/libc.so.6+0x1ff9f) SUMMARY: AddressSanitizer: heap-buffer-overflow /mnt/ram/portage-utils-0.56/qcheck.c:116 qcheck_process_contents Shadow bytes around the buggy address: 0x0c047fff9c90: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x0c047fff9ca0: fa fa fd fd fa fa fd fa fa fa fd fa fa fa fd fa 0x0c047fff9cb0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x0c047fff9cc0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x0c047fff9cd0: fa fa fd fa fa fa fd fd fa fa fd fd fa fa 00 00 =>0x0c047fff9ce0: fa fa 00[fa]fa fa 00 00 fa fa 00 fa fa fa 00 fa 0x0c047fff9cf0: fa fa 00 00 fa fa 00 fa fa fa 00 00 fa fa 00 fa 0x0c047fff9d00: fa fa 00 fa fa fa 00 00 fa fa 00 fa fa fa 00 00 0x0c047fff9d10: fa fa 01 fa fa fa 00 fa fa fa 00 00 fa fa 00 fa 0x0c047fff9d20: fa fa 00 00 fa fa 01 fa fa fa 00 fa fa fa 00 00 0x0c047fff9d30: fa fa 00 fa fa fa fd fa fa fa 04 fa fa fa 00 04 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 Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Contiguous container OOB:fc ASan internal: fe ==22916==ABORTING
Turning it in a security issue
not a security issue. ASAN throws a false positive because we assign a pointer that is invalid memory even though we don't use it -- the next statement checks the bounds and kicks out of the loop. and no, it's not a case where the compiler might optimize the check (akin to -fdelete-null-pointer-checks). it's code like: len = strlen(s); foo = s[0]; for (n = 0; n < len; ++n) { ... do stuff with foo ... foo = s[n + 1]; <- asan throws a fit }
fixed in pax-utils: http://gitweb.gentoo.org/proj/pax-utils.git/commit/?id=335e3c30ebd98959a53c22b12b17f907d7def48c and pulled into portage-utils: http://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=66090491b033778785f12ccd3f20cdf54e89c87a