From: Sayed Kaif Date: Sat, 20 Jun 2026 17:56:16 +0000 (+0530) Subject: libdw: Fix out-of-bounds write parsing .debug_macro opcode table X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=22046fea9ad58919ee3c53371d2725dceb0abfe2;p=thirdparty%2Felfutils.git libdw: Fix out-of-bounds write parsing .debug_macro opcode table A crafted .debug_macro section with opcode 0 makes (opcode - 1) wrap to 0xFFFFFFFF in the unsigned array index, writing a 16-byte struct past the 255-element op_protos array. Reject opcode == 0 and add the missing readp >= endp checks before reading the count and opcode bytes. * libdw/dwarf_getmacros.c (get_macinfo_table): Reject opcode 0, add bounds checks. * tests/testfile-macros-opcode0.bz2: New test input. * tests/run-dwarf-getmacros.sh: Test it. * tests/Makefile.am (EXTRA_DIST): Add new test file. Signed-off-by: Sayed Kaif --- diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c index d7ed7b58..bb2272ea 100644 --- a/libdw/dwarf_getmacros.c +++ b/libdw/dwarf_getmacros.c @@ -255,11 +255,23 @@ get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff, if ((flags & 0x4) != 0) { + if (readp >= endp) + goto invalid_dwarf; unsigned count = *readp++; for (unsigned i = 0; i < count; ++i) { + if (readp >= endp) + goto invalid; unsigned opcode = *readp++; + /* Opcode 0 is not allocated (and 0xff means "not stored"). + Reject it here: without this check the unsigned expression + opcode - 1 wraps to UINT_MAX for opcode == 0, and the + assignment below would write a Dwarf_Macro_Op_Proto far out + of the bounds of the op_protos[255] stack array. */ + if (opcode == 0) + goto invalid; + Dwarf_Macro_Op_Proto e; if (readp >= endp) goto invalid; diff --git a/tests/Makefile.am b/tests/Makefile.am index fb0690ed..d966207a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -411,7 +411,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ testfile45.S.bz2 testfile45.expect.bz2 run-disasm-x86-64.sh \ testfile46.bz2 testfile47.bz2 testfile48.bz2 testfile48.debug.bz2 \ testfile49.bz2 testfile50.bz2 testfile51.bz2 \ - testfile-macros-0xff.bz2 \ + testfile-macros-0xff.bz2 testfile-macros-opcode0.bz2 \ run-readelf-macro.sh testfilemacro.bz2 testfileclangmacro.bz2 \ run-readelf-loc.sh testfileloc.bz2 \ splitdwarf4-not-split4.dwo.bz2 \ diff --git a/tests/run-dwarf-getmacros.sh b/tests/run-dwarf-getmacros.sh index 220c2426..bda6690d 100755 --- a/tests/run-dwarf-getmacros.sh +++ b/tests/run-dwarf-getmacros.sh @@ -707,6 +707,14 @@ file /home/petr/proj/elfutils/master/elfutils/x.c /file EOF +# A .debug_macro opcode_operands_table that defines opcode 0 used to make +# get_table_for_offset() compute op_protos[(unsigned)0 - 1] and write far +# out of bounds. It must now be rejected as invalid DWARF. +testfiles testfile-macros-opcode0 +testrun_compare ${abs_builddir}/dwarf-getmacros testfile-macros-opcode0 0xb <<\EOF +invalid DWARF +EOF + # See testfile-dwp.source. testfiles testfile-dwp-5 testfile-dwp-5.dwp testfiles testfile-dwp-4-strict testfile-dwp-4-strict.dwp diff --git a/tests/testfile-macros-opcode0.bz2 b/tests/testfile-macros-opcode0.bz2 new file mode 100644 index 00000000..cd396158 Binary files /dev/null and b/tests/testfile-macros-opcode0.bz2 differ