https://sourceware.org/bugzilla/show_bug.cgi?id=34898
Bug ID: 34898
Summary: libctf: ctf_member_next with CTF_MN_RECURSE writes to
the iterator after freeing it (heap-use-after-free at
ctf-types.c:229)
Product: binutils
Version: 2.48 (HEAD)
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: libctf
Assignee: unassigned at sourceware dot org
Reporter: martin.mirchev at u dot nus.edu
Target Milestone: ---
In ctf_member_next (libctf/ctf-types.c), when CTF_MN_RECURSE is set and the
recursive call for an unnamed sub-struct member fails with an error other than
ECTF_NEXT_END, the error path frees the iterator and then stores into it:
227 ctf_next_destroy (i);
228 *it = NULL;
229 i->ctn_type = 0;
Line 229 is an 8-byte write into the freed 80-byte ctf_next_t.
Tested on binutils-gdb master 1ec1cee48577c7b1960ddce5a6054b3f9fab6ef5
(--enable-targets=all). Release: Ubuntu 22.04 gcc 11 default -g -O2.
ASan: -O1 -g -fsanitize=address,undefined.
Attached (all files in libctf-member-next-uaf.tar.gz):
evil.ctf 121-byte raw CTF v3 dict: struct S { struct T; } where T's own
unnamed member has an out-of-range type id (ECTF_BADID on
resolve)
benign.ctf same dict with a valid member type (control)
craft.c generator for both files
harness.c libctf consumer: ctf_simple_open() on the file, then
ctf_member_next (fp, S, &it, ..., CTF_MN_RECURSE) in a loop, as
libctf-lookup/struct-iteration.c does
gcc -I include -o harness harness.c libctf/.libs/libctf.a bfd/.libs/libbfd.a
\
libsframe/.libs/libsframe.a libiberty/libiberty.a -lzstd -lz -ldl
./harness evil.ctf
ASan:
ERROR: AddressSanitizer: heap-use-after-free on address 0x507000000178
WRITE of size 8 at 0x507000000178 thread T0
#0 ctf_member_next libctf/ctf-types.c:229
#1 main harness.c:89
0x507000000178 is located 8 bytes inside of 80-byte region
[0x507000000170,0x5070000001c0)
freed by thread T0 here:
#1 ctf_next_destroy libctf/ctf-util.c:267
#2 ctf_member_next libctf/ctf-types.c:227
previously allocated by thread T0 here:
#1 ctf_next_create libctf/ctf-util.c:250
#2 ctf_member_next libctf/ctf-types.c:121
Release build: no crash. The second call returns -1 with ECTF_BADID and the
program exits 0. Valgrind on the release build: "Invalid write of size 8 at
ctf_member_next (ctf-types.c:229) ... 8 bytes inside a block of size 80 free'd
... by ctf_member_next (ctf-types.c:227)".
Controls: benign.ctf is clean under ASan and valgrind. evil.ctf iterated with
flags 0 is also clean, because the sub-struct branch needs CTF_MN_RECURSE. I
found no in-tree binutils tool that passes that flag, so this needs a libctf
API consumer.
The store at line 229 should probably be dropped or moved before
ctf_next_destroy, since the iterator no longer exists at that point.
This issue was found by an LLM-Enhanced Static Analysis Engine and verified
manually.
--
You are receiving this mail because:
You are on the CC list for the bug.