libdw: 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.
libdwfl: When rebuilding an ELF from process memory, segments_end used
the last PT_LOAD segment's end rather than the largest, so a later
smaller segment could shrink contents_size below an earlier segment's
start, underflowing end - start into a huge length and overflowing the
heap buffer. Skip any segment that starts past contents_size, matching
the guard already used in dwfl_segment_report_module.
* libdw/dwarf_getmacros.c (get_macinfo_table): Reject opcode 0,
add bounds checks.
* libdwfl/elf-from-memory.c (elf_from_remote_memory): Skip
out-of-range segment.
* 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 <[email protected]>
---
libdw/dwarf_getmacros.c | 12 ++++++++++++
libdwfl/elf-from-memory.c | 8 ++++++++
tests/Makefile.am | 2 +-
tests/run-dwarf-getmacros.sh | 8 ++++++++
tests/testfile-macros-opcode0.bz2 | Bin 0 -> 166 bytes
5 files changed, 29 insertions(+), 1 deletion(-)
create mode 100644 tests/testfile-macros-opcode0.bz2
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/libdwfl/elf-from-memory.c b/libdwfl/elf-from-memory.c
index e9b330fd..14b2f5c8 100644
--- a/libdwfl/elf-from-memory.c
+++ b/libdwfl/elf-from-memory.c
@@ -304,6 +304,14 @@ elf_from_remote_memory (GElf_Addr ehdr_vma,
GElf_Off start = offset & -pagesize;
GElf_Off end = (offset + filesz + pagesize - 1) & -pagesize;
+ /* The final contents_size is the trimmed last segment's end, which
+ may be smaller than an earlier segment's start (segments_end above
+ tracks the last PT_LOAD, not the maximum). Skip any segment that
+ falls entirely past it: otherwise buffer + start would be out of
+ bounds and end - start would underflow into a huge read length.
+ Mirrors the file_trimmed_end check in dwfl_segment_report_module. */
+ if (start >= (GElf_Off) contents_size)
+ continue;
if (end > (GElf_Off) contents_size)
end = contents_size;
nread = (*read_memory) (arg, buffer + start,
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8ae7d126..2881989d 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
0000000000000000000000000000000000000000..5e4cb8684065c20b00b0cbde317cf733c8e7a0e9
GIT binary patch
literal 166
zcmZ>Y%CIzaj8qGbRLPmZ%D_<ie?|Sf2OSKK0?ffI4hs7p&u3V`z|f$;FiBuR1_KD(
zY8IL`tE$<ds^@~T0|QgBe`;^e{*tG&%sXesEOc`gVcW4$Erf$<3&&MnAtp(|yESS1
zV|4@gn65uudF+WtQ?()Ei?+$xjRq_ixOEN1A~kF{KYmWwJ<+}JN!^c@8BCTlt$QYQ
S&xl#X`Cq)q)goX5$Xx(&Fh3Ol
literal 0
HcmV?d00001
--
2.52.0.windows.1