Page MenuHomeFreeBSD

Extend ELF coredump to support more than 65535 segments
ClosedPublic

Authored by cem on Jul 20 2016, 3:18 AM.
Tags
None
Referenced Files
Unknown Object (File)
Sat, Jun 22, 1:32 AM
Unknown Object (File)
Sun, Jun 2, 6:16 AM
Unknown Object (File)
Sat, Jun 1, 7:08 PM
Unknown Object (File)
Apr 30 2024, 5:43 AM
Unknown Object (File)
Apr 22 2024, 9:31 PM
Unknown Object (File)
Apr 20 2024, 2:16 AM
Unknown Object (File)
Apr 17 2024, 6:31 PM
Unknown Object (File)
Apr 14 2024, 5:20 AM
Subscribers

Details

Summary

The ELF e_phnum field is only 16 bits wide. To support more than 65535
segments (program headers), Sun's "Linker and Libraries Guide" table 7-7
prescribes a special first section header where sh_info represents the real
number of program headers.

See: http://docs.oracle.com/cd/E18752_01/pdf/817-1984.pdf

Test Plan
#include <sys/param.h>
#include <sys/mman.h>
#include <err.h>
#include <stdint.h>
#include <stdlib.h>

int
main(int argc __unused, char **argv __unused)
{
        void *v;
        unsigned i;

        for (i = 0; i < UINT16_MAX + 1000; i++) {
                v = mmap(NULL, PAGE_SIZE,
                    (((i % 2) == 0) ? PROT_READ : 0) | PROT_WRITE,
                    MAP_ANON | MAP_PRIVATE, -1, 0);
                if (v == MAP_FAILED)
                        err(1, "mmap");
        }
        abort();
}

(Testing is still a work in progress, building a kernel on this laptop is pretty slow.)

Please CC anyone you think may be qualified or interested to review this.

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

cem retitled this revision from to Extend ELF coredump to support more than 65535 segments.
cem updated this object.
cem edited the test plan for this revision. (Show Details)
cem added reviewers: jhb, markj, emaste.
sys/kern/imgact_elf.c
1695–1697 ↗(On Diff #18568)

Ignore this, I intend to remove it before committing.

Does that test program actually work? I'd have thought that the consecutive mmaps would just extend a single vm_map entry, resulting in a single segment. You could defeat that by alternating the protections on consecutive pages with something like "i % 2 ? PROT_READ : PROT_WRITE".

In D7255#150846, @markj wrote:

Does that test program actually work? I'd have thought that the consecutive mmaps would just extend a single vm_map entry, resulting in a single segment. You could defeat that by alternating the protections on consecutive pages with something like "i % 2 ? PROT_READ : PROT_WRITE".

Work in progress. That sounds like a plan.

@markj: Yeah, that (alternating -w-/rw-) and adding a few extra (UINT16_MAX + 1000) does it.

$ readelf -l /var/crash/wklptp-phnum_overflow-71842.core

Elf file type is CORE (Core file)
Entry point 0x0
There are 633 program headers, starting at offset 64
...

$ procstat -v /var/crash/wklptp-phnum_overflow-71842.core | wc -l
66545
cem edited edge metadata.

After patch:

$ procstat -v /var/crash/wklptp-phnum_overflow-1027.core | wc -l
   66545
$ readelf -l /var/crash/wklptp-phnum_overflow-1027.core | wc -l
  132346
$ readelf -l /var/crash/wklptp-phnum_overflow-1027.core | head

Elf file type is CORE (Core file)
Entry point 0x0
There are 66169 program headers, starting at offset 64


$ readelf -S /var/crash/wklptp-phnum_overflow-1027.core
There are 1 section headers, starting at offset 0x388ab8:

Section Header:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0] <no-name>         NULL             0000000000000000  00000000
       0000000000000001  0000000000000000           0   66169     0

66169 % 65536 = 633

0x388ab8 (SH offset) = 64 (PH offset) + 56 (PH entity size) * 66169 (num PH)

I think this is good. Will you add the test program as well?

I think this is good. Will you add the test program as well?

Add it to where?

cem edited edge metadata.

Remove extra kassert.

markj edited edge metadata.

Looks ok to me. It's not really clear to me how standard this is, but it's better than nothing, and I've found a few other references to this trick elsewhere.

sys/kern/imgact_elf.c
1667 ↗(On Diff #18593)

Missing a period.

This revision is now accepted and ready to land.Jul 20 2016, 4:30 PM
emaste edited edge metadata.

Fine with me, although perhaps expand the comment slightly (e.g. something like "a special section is used to hold large segment counts")?

The test code could go in tests/sys/kern?

cem marked an inline comment as done.Jul 20 2016, 4:40 PM
In D7255#151043, @markj wrote:

Looks ok to me. It's not really clear to me how standard this is, but it's better than nothing, and I've found a few other references to this trick elsewhere.

Well, Linux and Solaris use the same technique, at least. And I didn't have to modify readelf(1) to be aware of it; it already knew about the special section.

Fine with me, although perhaps expand the comment slightly (e.g. something like "a special section is used to hold large segment counts")?

Good point.

The test code could go in tests/sys/kern?

I'll have to spend a little time figuring out how to use that.

I'll have to spend a little time figuring out how to use that.

I think it should be reasonably straightforward to just copy one of the examples already in there, e.g. unix_passfd_test.c or ptrace_test.c.

This revision was automatically updated to reflect the committed changes.

Please also fix gcore. The file to patch there is probably 'elfcore.c'.

In D7255#151086, @jhb wrote:

Please also fix gcore. The file to patch there is probably 'elfcore.c'.

Ok.