Hi maintainers,

we have found another issue in objdump's CTF handling and would like to report 
this issue.
Could you confirm if this qualifies as a bug? I am happy to provide any 
additional information needed.


## Summary
We found a bug  where file size verification is not performed, which causes a 
segmentation fault (SEGV) due to out-of-bounds memory access when an invalid 
size is 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\x01\x02\x03\x04\x05\x06\x07\x06\x07\x6C\x2D\x2D\x64\x65\x62\x75\x67\x67\x69\x8D\x67\x20\x2C\x2D\x46\x00\x00\x00\x00\x20\x2D'
 > mini
./binutils/objdump ./mini --target=binary --ctf=.data
```

## Output

```
AddressSanitizer:DEADLYSIGNAL
=================================================================
==222433==ERROR: AddressSanitizer: SEGV on unknown address (pc 0x55e6ee18837e 
bp 0x7ffc7b018db0 sp 0x7ffc7b018b00 T0)
==222433==The signal is caused by a READ memory access.
==222433==Hint: this fault was caused by a dereference of a high value address 
(see register values below).  Disassemble the provided pc to learn which 
register was used.
    #0 0x55e6ee18837e in ctf_bfdopen_ctfsect 
/home/pine/Documents/fuzz/analysis2/binutils-2.45/build/libctf/../../libctf/ctf-open-bfd.c:123:17
    #1 0x55e6ee06bbd8 in dump_ctf 
/home/pine/Documents/fuzz/analysis2/binutils-2.45/build/binutils/../../binutils/objdump.c:4919:15
    #2 0x55e6ee0697f0 in dump_bfd 
/home/pine/Documents/fuzz/analysis2/binutils-2.45/build/binutils/../../binutils/objdump.c:5837:2
    #3 0x55e6ee068b87 in display_object_bfd 
/home/pine/Documents/fuzz/analysis2/binutils-2.45/build/binutils/../../binutils/objdump.c:5911:7
    #4 0x55e6ee068a97 in display_any_bfd 
/home/pine/Documents/fuzz/analysis2/binutils-2.45/build/binutils/../../binutils/objdump.c:5990:5
    #5 0x55e6ee067aa6 in display_file 
/home/pine/Documents/fuzz/analysis2/binutils-2.45/build/binutils/../../binutils/objdump.c:6011:3
    #6 0x55e6ee066a2d in main 
/home/pine/Documents/fuzz/analysis2/binutils-2.45/build/binutils/../../binutils/objdump.c:6438:6
    #7 0x7f78c7e466b4 in __libc_start_call_main 
/usr/src/debug/glibc/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #8 0x7f78c7e46768 in __libc_start_main 
/usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:360:3
    #9 0x55e6edf123d4 in _start 
(/home/pine/Documents/fuzz/analysis2/analysis2/result_zig/objdump/out_objdump_1/default/objdump+0x1663d4)
 (BuildId: 77c0b96fce4c4af073e1b502b33c63b354bcea51)

==222433==Register values:
rax = 0x04000f9318cbc92f  rbx = 0x00007ffc7b018b00  rcx = 0x200000000000462d  
rdx = 0x000000000000000c
rdi = 0x200000000000462d  rsi = 0x000055e6ee5be5c0  rbp = 0x00007ffc7b018db0  
rsp = 0x00007ffc7b018b00
 r8 = 0x00000000ffffffff   r9 = 0x0000000000000000  r10 = 0x0000000000000000  
r11 = 0x00007f78c7e60420
r12 = 0x00007ffc7b019528  r13 = 0x0000000000000004  r14 = 0x00007f78c82ab000  
r15 = 0x000055e6ee680710
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV 
/home/pine/Documents/fuzz/analysis2/binutils-2.45/build/libctf/../../libctf/ctf-open-bfd.c:123:17
 in ctf_bfdopen_ctfsect
```

## Root Cause Analysis

The size of le64toh (arc->ctfa_ctfs) is not validated at 
libctf/ctf-archive.c:402

```
      struct ctf_archive *arc = (struct ctf_archive *) ctfsect->cts_data;
      return (const ctf_preamble_t *) ((char *) arc + le64toh (arc->ctfa_ctfs)
                               + sizeof (uint64_t));
```

Therefore, when an invalid size is input, an out-of-bounds memory reference 
occurs at libctf/ctf-open-bfd.c:121, 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..b5d51a84 100644
--- a/libctf/ctf-archive.c
+++ b/libctf/ctf-archive.c
@@ -399,7 +399,13 @@ 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;
-      return (const ctf_preamble_t *) ((char *) arc + le64toh (arc->ctfa_ctfs)
+      size_t offset = le64toh (arc->ctfa_ctfs);
+
+      if((offset + sizeof(uint64_t)) > ctfsect->cts_size)
+      {
+        return NULL;
+      }
+      return (const ctf_preamble_t *) ((char *) arc + offset
                                       + sizeof (uint64_t));
     }
   else
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)
     {
```

Best wishes,
Momoko Shiraishi

Reply via email to