ELF64 section SHT_NOTE misinterpreted by readelf as 32bit

Viewed 34

I want to use Note section of ELF file to propagate some information within my tool set. Similar method is used by Microsoft tools and by NASM in COFF modules, where payload data in section .drectve contains linker parameters, for instance the text /IMPORT:ExitProcess.

First I used NASM on Linux to create 32bit ELF module with Note section .drectve:

me@vm:~/$ cat NOTE32.asm
BITS 32
SECTION .drectve
DD 7            ; namesz = size of "ABCDEFG".
DD 8            ; descsz = size of payload.
DD 9            ; type = randomly chosen value.
DB "ABCDEFG",0  ; name = owner; aligned size=8.
DB "payload."   ; desc = useful contents; aligned size=8.

me@vm:~/$ nasm -f ELF32 NOTE32.asm -o NOTE32.o

As NASM cannot create NOTE-type sections directly, I had to edit the output file with hexaeditor and rewrite section type from SHT_PROGBITS (1) to SHT_NOTE (7). Readelf then displayed my handcrafted note correctly, although it couldn't interpret my arbitrary chosen Owner and Type, of course:

me@vm:~/$ readelf -hSn NOTE32.o
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          64 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         5
  Section header string table index: 2

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .drectve          NOTE            00000000 000110 00001c 00   A  0   0  1
  [ 2] .shstrtab         STRTAB          00000000 000130 000024 00      0   0  1
  [ 3] .symtab           SYMTAB          00000000 000160 000030 10      4   3  4
  [ 4] .strtab           STRTAB          00000000 000190 00000c 00      0   0  1

Displaying notes found at file offset 0x00000110 with length 0x0000001c:
  Owner                 Data size       Description
  ABCDEFG              0x00000008       Unknown note type: (0x00000009)
me@vm:~/$

So far, so good. Then I repeated the process with 64bit ELF module, where the fields in NOTE section are 8 bytes wide, according to chapter 9. of ELF-64 Object File Format on page 13:

Sections of type SHT_NOTE and segments of type PT_NOTE are used by compilers and other tools to mark an object file with special information that has special meaning to a particular tool set. These sections and segments contain any number of note entries, each of which is an array of 8-byte words in the byte order defined in the ELF file header. The format of a note entry is shown in Figure 7.

me@vm:~/$ cat NOTE64.asm
BITS 64
SECTION .drectve
DQ 7            ; namesz = size of "ABCDEFG".
DQ 8            ; descsz = size of payload.
DQ 9            ; type = randomly chosen value.
DB "ABCDEFG",0  ; name = owner; aligned size=8.
DB "payload."   ; desc = useful contents; aligned size=8.

me@vm:~/$ nasm -f ELF64 NOTE64.asm -o NOTE64.o

Here is the file dump with SHT_PROGBITS at offset 84h manually rewritten to SHT_NOTE:

me@vm:~/$ xxd NOTE64.o
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
00000010: 0100 3e00 0100 0000 0000 0000 0000 0000  ..>.............
00000020: 0000 0000 0000 0000 4000 0000 0000 0000  ........@.......
00000030: 0000 0000 4000 0000 0000 4000 0500 0200  ....@.....@.....
00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000080: 0100 0000 0700 0000 0200 0000 0000 0000  ................
00000090: 0000 0000 0000 0000 8001 0000 0000 0000  ................
000000a0: 2800 0000 0000 0000 0000 0000 0000 0000  (...............
000000b0: 0800 0000 0000 0000 0800 0000 0000 0000  ................
000000c0: 0a00 0000 0300 0000 0000 0000 0000 0000  ................
000000d0: 0000 0000 0000 0000 b001 0000 0000 0000  ................
000000e0: 2400 0000 0000 0000 0000 0000 0000 0000  $...............
000000f0: 0100 0000 0000 0000 0000 0000 0000 0000  ................
00000100: 1400 0000 0200 0000 0000 0000 0000 0000  ................
00000110: 0000 0000 0000 0000 e001 0000 0000 0000  ................
00000120: 4800 0000 0000 0000 0400 0000 0300 0000  H...............
00000130: 0400 0000 0000 0000 1800 0000 0000 0000  ................
00000140: 1c00 0000 0300 0000 0000 0000 0000 0000  ................
00000150: 0000 0000 0000 0000 3002 0000 0000 0000  ........0.......
00000160: 0c00 0000 0000 0000 0000 0000 0000 0000  ................
00000170: 0100 0000 0000 0000 0000 0000 0000 0000  ................
00000180: 0700 0000 0000 0000 0800 0000 0000 0000  ................
00000190: 0900 0000 0000 0000 4142 4344 4546 4700  ........ABCDEFG.
000001a0: 7061 796c 6f61 642e 0000 0000 0000 0000  payload.........
000001b0: 002e 6472 6563 7476 6500 2e73 6873 7472  ..drectve..shstr
000001c0: 7461 6200 2e73 796d 7461 6200 2e73 7472  tab..symtab..str
000001d0: 7461 6200 0000 0000 0000 0000 0000 0000  tab.............
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001f0: 0000 0000 0000 0000 0100 0000 0400 f1ff  ................
00000200: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000210: 0000 0000 0300 0100 0000 0000 0000 0000  ................
00000220: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000230: 004e 4f54 4536 342e 6173 6d00 0000 0000  .NOTE64.asm.....
me@vm:~/$

GNU readelf (GNU Binutils for Ubuntu) 2.26.1 interprets the 64bit NOTE section .drectve incorrectly:

me@vm:~/$ readelf -hSnW NOTE64.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          64 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         5
  Section header string table index: 2

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .drectve          NOTE            0000000000000000 000180 000028 08   A  0   0  8
  [ 2] .shstrtab         STRTAB          0000000000000000 0001b0 000024 00      0   0  1
  [ 3] .symtab           SYMTAB          0000000000000000 0001e0 000048 18      4   3  4
  [ 4] .strtab           STRTAB          0000000000000000 000230 00000c 00      0   0  1

Displaying notes found at file offset 0x00000180 with length 0x00000028:
  Owner                 Data size       Description
                       0x00000000       Unknown note type: (0x00000008)
readelf: Warning: note with invalid namesz and/or descsz found at offset 0x14
readelf: Warning:  type: 0x474645, namesize: 0x00000000, descsize: 0x44434241
me@vm:~/$

Apparently readelf misinterprets the section contents at file offset 180h as two NOTE arrays of 32bit DWORDs, the second entry starting at file offset 194h.

I have also tried to change OS/ABI value from UNIX - System V (0) to UNIX - GNU (3) in ELF_header.e_ident.EI_OSABI but with no effect.

Now I am in dilemma whether I should

  1. generate DWORD fields in both ELF32 and ELF64 formats produced by my tool (which contradicts ELF64 specification), or
  2. keep QWORD fields in ELF64 and face readelf's complains.
1 Answers

From /usr/include/elf.h:

typedef uint32_t Elf64_Word;
...
typedef struct
{
  Elf64_Word n_namesz;                  /* Length of the note's name.  */
  Elf64_Word n_descsz;                  /* Length of the note's descriptor.  */
  Elf64_Word n_type;                    /* Type of the note.  */
} Elf64_Nhdr;

Clearly the size of the 64-bit n_namesz etc. is 4 bytes, not 8.

The source you cite is:

  • not authoritative and
  • wrong

A more authoritative source states: "For 64–bit objects and 32–bit objects, each entry is an array of 4-byte words in the format of the target processor."

Related