[Bug 277635] ldd (ld-elf.so.1) integer wrap when computing mmap() argument

From: <bugzilla-noreply_at_freebsd.org>
Date: Mon, 11 Mar 2024 16:55:59 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=277635

            Bug ID: 277635
           Summary: ldd (ld-elf.so.1) integer wrap when computing mmap()
                    argument
           Product: Base System
           Version: CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: bin
          Assignee: bugs@FreeBSD.org
          Reporter: rtm@lcs.mit.edu

Created attachment 249097
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=249097&action=edit
elf with huge vaddr that causes ldd / ld.so integer wrap

The attached elf file has a LOAD segment with a p_vaddr big enough
that p_vaddr + p_filesz wraps. This causes rtld-elf's map_object.c to
compute a huge size argument for a call to mmap() to map in the
segment, which causes the segment to be mapped over something
critical. This causes ld-elf.so.1 to crash when called by ldd.

Specifically, data_vaddr ends up larger than data_vlimit in this
map_object() code, so data_vlimit - data_vaddr wraps:

    for (i = 0; i <= nsegs; i++) {
        /* Overlay the segment onto the proper region. */
        data_offset = rtld_trunc_page(segs[i]->p_offset);
        data_vaddr = rtld_trunc_page(segs[i]->p_vaddr);
        data_vlimit = rtld_round_page(segs[i]->p_vaddr + segs[i]->p_filesz);
        data_addr = mapbase + (data_vaddr - base_vaddr);
        ...;
        if (data_vlimit != data_vaddr &&
            mmap(data_addr, data_vlimit - data_vaddr, data_prot,
            data_flags | MAP_PREFAULT_READ, fd, data_offset) == MAP_FAILED) {

Similarly, clever choices of p_vaddr and p_filesz can cause the later

            clear_vaddr = segs[i]->p_vaddr + segs[i]->p_filesz;
            clear_addr = mapbase + (clear_vaddr - base_vaddr);
            ...;
                memset(clear_addr, 0, nclear);

to write memory outside of mapbase..(mapbase+mapsize).

The attached elf file demonstrates the first problem, though only on riscv.

# objdump -x ldd1c.exe
...
    LOAD off    0x0000000000000700 vaddr 0xffffffffffec5701 paddr
0x0000000000001700 align 2**12
         filesz 0x0000003fbffff0b2 memsz 0x00000000000001b0 flags --x
# ldd ldd1c.exe
ldd1c.exe:
pid 35 (ld-elf.so.1), jid 0, uid 0: exited on signal 11 (core dumped)
/ldd1c.exe: signal 11

-- 
You are receiving this mail because:
You are the assignee for the bug.