https://sourceware.org/bugzilla/show_bug.cgi?id=34893
Bug ID: 34893
Summary: ld: eval_symbol does not validate the complex-symbol
length ("s-1:x" -> memcpy of SIZE_MAX into a 4096-byte
stack buffer)
Product: binutils
Version: 2.48 (HEAD)
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: ld
Assignee: unassigned at sourceware dot org
Reporter: martin.mirchev at u dot nus.edu
Target Milestone: ---
eval_symbol() (bfd/elflink.c) parses the length of an "s<len>:<name>" term of
an STT_RELC complex-symbol name with strtol() into the size_t symlen. It then
checks only
9390 if (symend < sym || symlen + 1 > sizeof (symbuf))
before
9396 memcpy (symbuf, sym, symlen);
For "s-1:x", symlen is SIZE_MAX and symlen + 1 wraps to 0, so memcpy is called
with SIZE_MAX into the 4096-byte stack buffer symbuf. symlen is also never
compared with the bytes left in the name, so "s4000:x" copies 4000 bytes
starting at a 7-byte name and reads past the string table.
Tested on master 1ec1cee48577c7b1960ddce5a6054b3f9fab6ef5 (GNU ld
2.47.50.20261027). Release: Ubuntu 22.04 gcc 11 default -g -O2 (fortify on).
ASan: -O1 -g -fsanitize=address,undefined.
Attached (all files in ld-complex-symbol-length.tar.gz): complex-symbol.s,
complex-symbol-safe.s, set-symbol-type.c, mk.sh and
the generated objects. gas cannot emit STT_RELC, so set-symbol-type.c sets the
type to 8 after assembling.
ordinary.o "s-1:x" as STT_OBJECT (control)
safe.o "#1" as STT_RELC (control)
bad.o "s-1:x" as STT_RELC
long.o "s4000:x" as STT_RELC
$ ld -o bad bad.o
*** buffer overflow detected ***: terminated (exit 134)
$ ld -o long long.o
ld: undefined symbol reference in complex symbol: x
ld: final link failed: bad value (exit 1)
$ ld -o o ordinary.o; ld -o s safe.o (both exit 0)
ASan, bad.o:
ERROR: AddressSanitizer: unknown-crash on address 0x7fffad58a890
WRITE of size 18446744073709551615 at 0x7fffad58a890 thread T0
#0 memcpy bits/string_fortified.h:29
#1 eval_symbol bfd/elflink.c:9396
#2 elf_link_input_bfd bfd/elflink.c:11916
#3 _bfd_elf_final_link bfd/elflink.c:13247
#4 ldwrite ld/ldwrite.c:548
#5 main ld/ldmain.c:1001
Address ... is located in stack of thread T0 at offset 96 in frame
#0 eval_symbol bfd/elflink.c:9351
[96, 4192) 'symbuf' (line 9356) <== Memory access at offset 96 is inside
this variable
ASan, long.o:
READ of size 4000 at 0x521000025c17 thread T0
#0 memcpy
#1 eval_symbol bfd/elflink.c:9396
0x5210000268e0 is located 0 bytes to the right of 4064-byte region
allocated by: bfd_alloc bfd/libbfd.c:453 <- bfd_section_from_shdr
bfd/elf.c:2896
Both controls link cleanly under ASan. Without _FORTIFY_SOURCE, bad.o is a
plain
stack overwrite. The parsing dates from d93525185ce6 (binutils 2.18) and the
current form of the check from 4b93929bf941 (PR 5160). PR 26469 fixed other
problems in the same function but not this length.
A likely fix is to reject a negative or non-numeric length and require symlen
to be below sizeof (symbuf) and no larger than the text remaining after the
':',
without the wrapping symlen + 1 comparison.
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.