Seva Alekseyev
Seva Alekseyev

Reputation: 61388

PT_NOTE segment in ELF files has bogus offset/address

I'm looking at a bunch of ELF binaries that have a curious entry in the program header (segment) table:

Type PT_NOTE, p_offset=p_addr=0x254, p_filesz=p_memsz=0x44

The offset points in the middle of the ELF header (somewhere in the segment table). The bytes it points at don't look like valid notes - it's legit program header data. The numbers 0x254/0x44 pop up too consistently for coincidence.

From what I can see, PT_NOTE type segments are ignored by the Linux loader anyway. It looks like some toolchain vendor decided to use fields in a note type segment as scratch space - not to be loaded and/or mapped, but to be interpreted somehow else. The ABI document doesn't suggest anything of the sort. The binaries also have note type sections, elsewhere and with perfectly valid format.

What's the story here?

EDIT: maybe it's not scratch after all; at least in the binaries that I have, the number 0x44 happens to be the total size of note sections in them (ABI-tag of 0x20 and build-id of 0x24). Still, what's with the offset and the address?

In my recently built (with GCC) binaries, there is a PT_NOTE segment of size 0x44, but the offset/address corresponds to two contiguous note sections in the binary. So it could be either an old linker bug that the loader would forgive, fixed since, or some kind of magic provision specific to PT_NOTEs...


Evidence elsewhere:


Here is readelf -Wl from one of those:

Elf file type is DYN (Position-Independent Executable file)
Entry point 0x8a0
There are 11 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000000040 0x0000000000000040 0x000268 0x000268 R   0x8
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x000ee0 0x000ee0 R E 0x200000
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  NOTE           0x000254 0x0000000000000254 0x0000000000000254 0x000044 0x000044 R   0x4
  GNU_EH_FRAME   0x000cac 0x0000000000000cac 0x0000000000000cac 0x00006c 0x00006c R   0x4
  LOAD           0x001d70 0x0000000000201d70 0x0000000000201d70 0x0002a0 0x0002f0 RW  0x200000
  GNU_RELRO      0x001d70 0x0000000000201d70 0x0000000000201d70 0x000290 0x000290 R   0x1
  DYNAMIC        0x001d80 0x0000000000201d80 0x0000000000201d80 0x0001f0 0x0001f0 RW  0x8
  INTERP         0x004000 0x0000000000203000 0x0000000000203000 0x00000d 0x00000d R   0x1
      [Requesting program interpreter: ./ld-2.27.so]
  LOAD           0x004000 0x0000000000203000 0x0000000000203000 0x000030 0x000030 RW  0x1000
  LOAD           0x005000 0x0000000000204000 0x0000000000204000 0x000148 0x000148 RW  0x1000

 Section to Segment mapping:
  Segment Sections...
   00
   01     .dynsym .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
   02
   03
   04     .eh_frame_hdr
   05     .init_array .fini_array .dynamic .got .data .bss
   06     .init_array .fini_array .dynamic .got
   07     .dynamic
   08     .interp
   09     .interp .note.ABI-tag
   10     .dynstr .gnu.hash .note.gnu.build-id

Note how segment 3 is in the middle of file header (seen as segment 0).


And here is readelf -WS:

There are 29 section headers, starting at offset 0x2c28:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .dynsym           DYNSYM          00000000000002c8 0002c8 0001c8 18   A 26   1  8
  [ 2] .gnu.version      VERSYM          0000000000000570 000570 000026 02   A  1   0  2
  [ 3] .gnu.version_r    VERNEED         0000000000000598 000598 000030 00   A 26   1  8
  [ 4] .rela.dyn         RELA            00000000000005c8 0005c8 000108 18   A  1   0  8
  [ 5] .rela.plt         RELA            00000000000006d0 0006d0 0000f0 18  AI  1  17  8
  [ 6] .init             PROGBITS        00000000000007c0 0007c0 000017 00  AX  0   0  4
  [ 7] .plt              PROGBITS        00000000000007e0 0007e0 0000b0 10  AX  0   0 16
  [ 8] .plt.got          PROGBITS        0000000000000890 000890 000008 08  AX  0   0  8
  [ 9] .text             PROGBITS        00000000000008a0 0008a0 0003a2 00  AX  0   0 16
  [10] .fini             PROGBITS        0000000000000c44 000c44 000009 00  AX  0   0  4
  [11] .rodata           PROGBITS        0000000000000c50 000c50 00005b 00   A  0   0  4
  [12] .eh_frame_hdr     PROGBITS        0000000000000cac 000cac 00006c 00   A  0   0  4
  [13] .eh_frame         PROGBITS        0000000000000d18 000d18 0001c8 00   A  0   0  8
  [14] .init_array       INIT_ARRAY      0000000000201d70 001d70 000008 08  WA  0   0  8
  [15] .fini_array       FINI_ARRAY      0000000000201d78 001d78 000008 08  WA  0   0  8
  [16] .dynamic          DYNAMIC         0000000000201d80 001d80 0001f0 10  WA 26   0  8
  [17] .got              PROGBITS        0000000000201f70 001f70 000090 08  WA  0   0  8
  [18] .data             PROGBITS        0000000000202000 002000 000010 00  WA  0   0  8
  [19] .bss              NOBITS          0000000000202020 002010 000040 00  WA  0   0 32
  [20] .comment          PROGBITS        0000000000000000 002010 00002b 01  MS  0   0  1
  [21] .symtab           SYMTAB          0000000000000000 002040 0007c8 18     22  43  8
  [22] .strtab           STRTAB          0000000000000000 002808 000320 00      0   0  1
  [23] .shstrtab         STRTAB          0000000000000000 002b28 0000fe 00      0   0  1
  [24] .interp           PROGBITS        0000000000203000 004000 00000d 00   A  0   0  8
  [25] .note.ABI-tag     NOTE            0000000000203010 004010 000020 00   A  0   0  8
  [26] .dynstr           STRTAB          0000000000204000 005000 0000ef 00   A  0   0  8
  [27] .gnu.hash         GNU_HASH        00000000002040f0 0050f0 000030 00   A  1   0  8
  [28] .note.gnu.build-id NOTE            0000000000204120 005120 000024 00   A  0   0  8
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), l (large), p (processor specific)

Note the two note sections near the end.

The comment section points at the toolchain:

GCC: (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0

Presuming it was built on Ubuntu 18...

The binaries themselves can be downloaded as attachments in this GitHub issue.

Upvotes: 0

Views: 109

Answers (0)

Related Questions