Reputation: 61388
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