https://sourceware.org/bugzilla/show_bug.cgi?id=33548

            Bug ID: 33548
           Summary: objdump --ctf: Heap buffer overflow
           Product: binutils
           Version: 2.45
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: binutils
          Assignee: unassigned at sourceware dot org
          Reporter: shiraishi at os dot is.s.u-tokyo.ac.jp
  Target Milestone: ---

## Summary
We found a bug in objdump's CTF handling where missing file size validation
leads to out-of-bounds memory access and a segmentation fault (SEGV) when
processing malformed input.

## Reproduction
Tested Environment

```
OS: Manjaro Linux
arch: x86_64
CC: clang 20.1.8
glibc: 2.41
```

## Reproduction Steps

```
wget https://ftp.gnu.org/gnu/binutils/binutils-2.45.tar.xz
tar -xvf binutils-2.45.tar.xz
cd binutils-2.45
export CFLAGS="-g -O0 -fsanitize=address -fno-omit-frame-pointer"
export CXXFLAGS="-g -O0 -fsanitize=address -fno-omit-frame-pointer"
export LDFLAGS="-fsanitize=address"
mkdir build
cd build
../configure --prefix=$PWD/install --disable-nls
make -j$(nproc)
printf '\xEB\x3E\x62\xD7\xA4\xF2\x47\x8B\x00' > mini
./binutils/objdump ./mini --target=binary --ctf=.data
```

## Output
```
==723251==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x7b68d4de00d0 at pc 0x55e15dcf16cb bp 0x7fff4fca9a60 sp 0x7fff4fca9a50
READ of size 8 at 0x7b68d4de00d0 thread T0
    #0 0x55e15dcf16ca in ctf_arc_bufpreamble ../../libctf/ctf-archive.c:402
    #1 0x55e15dd2bbc4 in ctf_bfdopen_ctfsect ../../libctf/ctf-open-bfd.c:121
    #2 0x55e15dc25fdb in dump_ctf ../../binutils/objdump.c:4919
    #3 0x55e15dc2a9c5 in dump_bfd ../../binutils/objdump.c:5837
    #4 0x55e15dc2ad46 in display_object_bfd ../../binutils/objdump.c:5911
    #5 0x55e15dc2b06a in display_any_bfd ../../binutils/objdump.c:5990
    #6 0x55e15dc2b0d6 in display_file ../../binutils/objdump.c:6011
    #7 0x55e15dc2d22e in main ../../binutils/objdump.c:6438
    #8 0x7f48d6c376b4  (/usr/lib/libc.so.6+0x276b4) (BuildId:
468e3585c794491a48ea75fceb9e4d6b1464fc35)
    #9 0x7f48d6c37768 in __libc_start_main (/usr/lib/libc.so.6+0x27768)
(BuildId: 468e3585c794491a48ea75fceb9e4d6b1464fc35)
    #10 0x55e15dc0fa54 in _start
(/home/pine/Documents/fuzz/analysis2/test/binutils-2.45/build/binutils/objdump+0x145a54)
(BuildId: 7cdbf8eb625396e3744720a861ca2f10ac8b8c72)

0x7b68d4de00d0 is located 23 bytes after 9-byte region
[0x7b68d4de00b0,0x7b68d4de00b9)
allocated by thread T0 here:
    #0 0x7f48d6f20e15 in malloc
/usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:67
    #1 0x55e15dd797ed in bfd_malloc ../../bfd/libbfd.c:291
    #2 0x55e15dd6c7ee in bfd_get_full_section_contents ../../bfd/compress.c:742
    #3 0x55e15dd845f7 in bfd_malloc_and_get_section ../../bfd/section.c:1662
    #4 0x55e15dc24408 in read_section ../../binutils/objdump.c:4581
    #5 0x55e15dc25f12 in dump_ctf ../../binutils/objdump.c:4907
    #6 0x55e15dc2a9c5 in dump_bfd ../../binutils/objdump.c:5837
    #7 0x55e15dc2ad46 in display_object_bfd ../../binutils/objdump.c:5911
    #8 0x55e15dc2b06a in display_any_bfd ../../binutils/objdump.c:5990
    #9 0x55e15dc2b0d6 in display_file ../../binutils/objdump.c:6011
    #10 0x55e15dc2d22e in main ../../binutils/objdump.c:6438
    #11 0x7f48d6c376b4  (/usr/lib/libc.so.6+0x276b4) (BuildId:
468e3585c794491a48ea75fceb9e4d6b1464fc35)
    #12 0x7f48d6c37768 in __libc_start_main (/usr/lib/libc.so.6+0x27768)
(BuildId: 468e3585c794491a48ea75fceb9e4d6b1464fc35)
    #13 0x55e15dc0fa54 in _start
(/home/pine/Documents/fuzz/analysis2/test/binutils-2.45/build/binutils/objdump+0x145a54)
(BuildId: 7cdbf8eb625396e3744720a861ca2f10ac8b8c72)

SUMMARY: AddressSanitizer: heap-buffer-overflow ../../libctf/ctf-archive.c:402
in ctf_arc_bufpreamble
Shadow bytes around the buggy address:
  0x7b68d4ddfe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b68d4ddfe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b68d4ddff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b68d4ddff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b68d4de0000: fa fa fd fa fa fa 00 04 fa fa 00 04 fa fa 00 04
=>0x7b68d4de0080: fa fa 06 fa fa fa 00 01 fa fa[fa]fa fa fa fa fa
  0x7b68d4de0100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7b68d4de0180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7b68d4de0200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7b68d4de0280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7b68d4de0300: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==723251==ABORTING

```

## Root Cause Analysis

At libctf/ctf-archive.c:402, the code only verifies that ctfsect->cts_size is
at least 8 bytes, but then accesses struct members assuming 16 bytes are
available, resulting in out-of-bounds heap memory access.

```
  if (ctfsect->cts_data != NULL
      && ctfsect->cts_size > sizeof (uint64_t)
      && (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC))
    {
      struct ctf_archive *arc = (struct ctf_archive *) ctfsect->cts_data;
      return (const ctf_preamble_t *) ((char *) arc + le64toh (arc->ctfa_ctfs)
                               + sizeof (uint64_t));
```

Additionally, this eventually leads to an out-of-bounds memory reference at
libctf/ctf-open-bfd.c:123, resulting in a SEGV.

```
  if (ctfsect->cts_data == NULL)
    {
      bfderrstr = N_("CTF section is NULL");
      goto err;
    }
  preamble = ctf_arc_bufpreamble (ctfsect);

  if (preamble->ctp_flags & CTF_F_DYNSTR)
    {
      symhdr = &elf_tdata (abfd)->dynsymtab_hdr;
      strtab_name = ".dynstr";
      symtab_name = ".dynsym";

```

## Proposed Fix

```
diff --git a/libctf/ctf-archive.c b/libctf/ctf-archive.c
index 6c4595fc..d4cd5642 100644
--- a/libctf/ctf-archive.c
+++ b/libctf/ctf-archive.c
@@ -399,6 +399,10 @@ ctf_arc_bufpreamble (const ctf_sect_t *ctfsect)
       && (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC))
     {
       struct ctf_archive *arc = (struct ctf_archive *) ctfsect->cts_data;
+      if(ctfsect->cts_size < sizeof(uint64_t) * 2)
+      {
+        return NULL;
+      }
       return (const ctf_preamble_t *) ((char *) arc + le64toh (arc->ctfa_ctfs)
                                       + sizeof (uint64_t));
     }
diff --git a/libctf/ctf-open-bfd.c b/libctf/ctf-open-bfd.c
index 7241de70..def9cf6d 100644
--- a/libctf/ctf-open-bfd.c
+++ b/libctf/ctf-open-bfd.c
@@ -119,6 +119,10 @@ ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_,
       goto err;
     }
   preamble = ctf_arc_bufpreamble (ctfsect);
+  if(preamble == NULL)
+  {
+    goto err;
+  }

   if (preamble->ctp_flags & CTF_F_DYNSTR)
     {
```

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Reply via email to