https://sourceware.org/bugzilla/show_bug.cgi?id=34370
Bug ID: 34370
Summary: objdump: null-pointer dereference in tg_start_block
(binutils/prdbg.c:2774)
Product: binutils
Version: 2.47 (HEAD)
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: binutils
Assignee: unassigned at sourceware dot org
Reporter: lswang1112 at gmail dot com
Target Milestone: ---
Created attachment 16825
--> https://sourceware.org/bugzilla/attachment.cgi?id=16825&action=edit
Minimal 392-byte ELF with .stab N_FUN entry for a non-member function; triggers
SIGSEGV at prdbg.c:2774
Affected version: GNU Binutils 2.46.1 (also confirmed on 2.46.50.20260707 git
HEAD)
Confirmed reproduced on 2.46.1 release.
------------------------------------------------------------------------
ROOT CAUSE
------------------------------------------------------------------------
tg_start_block() (binutils/prdbg.c) is the CTF/tag-file backend's
"start block" callback, invoked for each function body during stab
debug-info output. When a function with no method annotation is
processed, the function pops the type string off the type stack with
pop_type(), then immediately tries to access fields of the now-emptied
stack head:
/* prdbg.c:2733 – tg_start_block */
static bool
tg_start_block (void *p, bfd_vma addr)
{
struct pr_handle *info = (struct pr_handle *) p;
...
if (info->parameter > 0)
{
info->parameter = 0;
...
/* line 2764: pop_type() sets info->stack = info->stack->next */
t = pop_type (info); /* pops the only element; info->stack = NULL
*/
if (t == NULL)
return false;
fprintf (info->f, ";\"\tkind:%c\ttype:%s", kind, t);
free (t);
...
free (info->stack->method); /* line 2774: info->stack is NULL →
SIGSEGV */
info->stack->method = NULL; /* line 2775 */
}
return true;
}
pop_type() (prdbg.c:461):
static char *
pop_type (struct pr_handle *info)
{
struct pr_stack *o;
char *ret;
assert (info->stack != NULL);
o = info->stack;
info->stack = o->next; /* last element: o->next == NULL → info->stack =
NULL */
ret = o->type;
free (o);
return ret;
}
When the function has exactly one entry on the type stack and the
else-branch (non-method, kind='f') is taken at line 2761, pop_type()
is called and removes that last element, setting info->stack to NULL.
Lines 2774–2775 then dereference info->stack unconditionally, crashing
with SIGSEGV (or UBSan "member access within null pointer of type
'struct pr_stack'").
The code assumes that a second stack element (the class/method context)
always remains after popping the type; this assumption is violated when
the stab data describes a top-level (non-member) function.
------------------------------------------------------------------------
CRASH OUTPUT
------------------------------------------------------------------------
gdb backtrace, plain (non-instrumented) build:
Program received signal SIGSEGV, Segmentation fault.
0x00005555555f4b9e in tg_start_block (p=0x7fffffffdba0, addr=16)
at
/home/paul/Desktop/experiment/src/binutils-2.46.1/binutils/prdbg.c:2774
2774 free (info->stack->method);
#0 tg_start_block prdbg.c:2774 <-- null deref
#1 debug_write_block debug.c:2869
#2 debug_write_function debug.c:2845
#3 debug_write_name debug.c:2390
#4 debug_write debug.c:2352
#5 print_debugging_info prdbg.c:296
#6 dump_bfd objdump.c:5849
#7 display_object_bfd objdump.c:5900
#8 display_any_bfd objdump.c:5979
#9 display_file objdump.c:6000
#10 main objdump.c:6427
UBSan / ASan output (instrumented build):
/home/paul/Desktop/experiment/src/binutils-2.46.1/binutils/prdbg.c:2774:26:
runtime error: member access within null pointer of type 'struct pr_stack'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prdbg.c:2774:26
------------------------------------------------------------------------
HOW TO REPRODUCE
------------------------------------------------------------------------
Download the source:
# Release tarball (recommended):
wget https://ftp.gnu.org/gnu/binutils/binutils-2.46.1.tar.xz
# Or from git:
git clone git://sourceware.org/git/binutils-gdb.git
cd binutils-gdb && git checkout binutils-2_46_1
Build from the tarball:
tar xf binutils-2.46.1.tar.xz && cd binutils-2.46.1
mkdir build && cd build
../configure --disable-gdb --disable-gdbserver \
--disable-gdbsupport --disable-sim CFLAGS="-g -O0"
make -j$(nproc) all-binutils
Reproduce (requires a crafted ELF with a malformed .stab section that
describes a non-member function via the stab tag-output path):
./binutils/objdump -G -W -e -g poc_tg_start_block_null_deref.elf
Under gdb:
gdb -q -batch -ex run -ex bt \
--args ./binutils/objdump -G -W -e -g poc_tg_start_block_null_deref.elf
The -g flag instructs objdump to print stab debug information using the
pr_fns / tg_fns callback tables. A crafted .stab section containing an
'N_FUN' stab entry for a non-method function is sufficient to trigger
the bug; the crash occurs during the tag-file output pass
(print_debugging_info with as_tags=true).
------------------------------------------------------------------------
SUGGESTED FIX
------------------------------------------------------------------------
Save the method string before calling pop_type(), or guard lines
2774–2775 with a NULL check:
--- a/binutils/prdbg.c
+++ b/binutils/prdbg.c
@@ -2770,8 +2770,12 @@ tg_start_block (void *p, bfd_vma addr)
if (partof)
fprintf (info->f, "\tclass:%s", partof);
fputc ('\n', info->f);
- free (info->stack->method);
- info->stack->method = NULL;
+ if (info->stack != NULL)
+ {
+ free (info->stack->method);
+ info->stack->method = NULL;
+ }
}
return true;
Alternatively, the method/partof string should be saved to a local
variable before pop_type() is called, so the stack pointer is not
needed afterward.
------------------------------------------------------------------------
IMPACT
------------------------------------------------------------------------
Null-pointer dereference (CWE-476) in binutils/prdbg.c, triggered by
objdump -g on a crafted ELF file containing a malformed .stab section.
Impact is denial of service (SIGSEGV crash). The crash is reproducible
on both instrumented and plain builds and requires no special privileges
or elevated permissions.
--
You are receiving this mail because:
You are on the CC list for the bug.