]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdw: Fix out-of-bounds write parsing .debug_macro opcode table
authorSayed Kaif <skaif@digiscrypt.com>
Sat, 20 Jun 2026 17:56:16 +0000 (23:26 +0530)
committerMark Wielaard <mark@klomp.org>
Sat, 20 Jun 2026 23:55:00 +0000 (01:55 +0200)
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 <skaif@digiscrypt.com>
libdw/dwarf_getmacros.c
tests/Makefile.am
tests/run-dwarf-getmacros.sh
tests/testfile-macros-opcode0.bz2 [new file with mode: 0644]

index d7ed7b58137e3f7e65f4e987b97e76583ad6dcd4..bb2272ea13b099e57aae06b1e8244e599fc6dc69 100644 (file)
@@ -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;
index fb0690edaf5748e0a880c178615608739888a8fd..d966207a1e5e5bb701112d5c864ca0fd0644846f 100644 (file)
@@ -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 \
index 220c24260e3a9f88210fc3f163678bca62e2d33c..bda6690d4c3a6598d7415f6a5b336b7f2433b271 100755 (executable)
@@ -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 (file)
index 0000000..cd39615
Binary files /dev/null and b/tests/testfile-macros-opcode0.bz2 differ