Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

elf_add_section example breaks ELF file #1175

Open
andreasWallner opened this issue Mar 3, 2025 · 1 comment
Open

elf_add_section example breaks ELF file #1175

andreasWallner opened this issue Mar 3, 2025 · 1 comment
Assignees

Comments

@andreasWallner
Copy link

Describe the bug
I'm currently trying to add some data to an ELF binary (as a note section for now), and failed for a while to get valid ELFs. Trying to narrow down the issue I tried the cpp/elf_add_section example and it exhibits the same issue (I have not debugged further for now).

After running elf_add_section on a binary for our embedded target, segments and some internals of the ELF binary are broken. As described below it looks like LIEF places the (modified) program header table to overlap with existing data in the file, explaining the corruptions that I had observed.

The binary itself is the output from a Rust build.

To Reproduce

  • run ./build/examples/cpp/elf_add_section test.elf test.patched.elf (both are attached)
  • use readelf / elf-info to investigate:
    • readelf reports a warning when reading the patched file: readelf: Warning: Corrupt unit length (got 0x2b000019 expected at most 0x1417) in section .debug_info [1]
    • the content of sections starting with .stack_sizes changed [2]
    • post-patch the RISCV_ATTRIBUTES segment does not get reported correctly anymore [3]
    • even though we added two sections, readelf reports two additional segments as well [4]

Note that LIEF does shrink the .strtab section, but this does not seem connected to the issue as the problems also occur with a file that was first shrunk (with a single parse/write cycle w/o any modifications). I stuck with the original file to be sure it's a valid input file.

Expected behavior

  • no addition segments should be added
  • other segments/sections should be unchanged

Environment (please complete the following information):

  • System and Version: Ubuntu 22.04, CPP compiled with gcc-12
  • Target format (PE, ELF, Mach-O): ELF
  • LIEF commit version: C++ was tested with dd291ae1, the original python issues occured with 0.16.4-10f74acf

Additional context, command line outputs for observed issues

All outputs below are from after running

$ ./build/examples/cpp/elf_add_section test.elf test.patched.elf

after building LIEF via

$ mkdir build && cd build
$ cmake -G Ninja ..
$ ninja
warning & changed contents [1] & [2]
~/LIEF[main] 1 % readelf -x .stack_sizes test.elf

Hex dump of section '.stack_sizes':
  0x00000000 9c000200 109c0102 00101402 0200006e ...............n
  0x00000010 02020000 70020200 00720202 00007402 ....p....r....t.
  0x00000020 02000080 02020000                   ........

~/LIEF[main]% readelf -x .stack_sizes test.patched.elf
readelf: Warning: Corrupt unit length (got 0x2b000019 expected at most 0x1417) in section .debug_info

Hex dump of section '.stack_sizes':
  0x00000000 01000000 00100000 00000200 00000200 ................
  0x00000010 8e020000 8e020000 05000000 00100000 ................
  0x00000020 01000000 90120000                   ........
RISCV_ATTRIBUTES segment missing & additional segements [3] & [4]
~/LIEF[main]% readelf --segment test.elf

Elf file type is EXEC (Executable file)
Entry point 0x20000
There are 5 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x00020000 0x00020000 0x0028e 0x0028e R E 0x1000
  LOAD           0x001290 0x00020290 0x00020290 0x0007c 0x0007c R   0x1000
  LOAD           0x002000 0x00010000 0x00010000 0x00000 0x0a000 RW  0x1000
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0
  RISCV_ATTRIBUT 0x00585b 0x00000000 0x00000000 0x0002a 0x0002a R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     .text.dummy .text
   01     .rodata
   02     .bss .heap .stack
   03
   04     .riscv.attributes
~/LIEF[main]% readelf --segment test.patched.elf

Elf file type is EXEC (Executable file)
Entry point 0x20000
There are 7 program headers, starting at offset 8192

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x00020000 0x00020000 0x0028e 0x0028e R E 0x1000
  LOAD           0x001290 0x00020290 0x00020290 0x0007c 0x0007c R   0x1000
  LOAD           0x002000 0x00010000 0x00010000 0x00000 0x0a000 RW  0x1000
  LOAD           0x002000 0x00021000 0x00021000 0x001e0 0x001e0 R   0x1000
  LOAD           0x00c000 0x0004c000 0x0004c000 0x01000 0x01000 R   0x1000
  LOAD           0x00d000 0x0008d000 0x0008d000 0x01000 0x01000 R   0x1000
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0

 Section to Segment mapping:
  Segment Sections...
   00     .text.dummy .text
   01     .rodata
   02     .bss .heap .stack
   03
   04
   05
   06
readelf: Warning: Corrupt unit length (got 0x2b000019 expected at most 0x1417) in section .debug_info

Analysis of output

Some analysis of the written ELF binary

Looking at the ELF header:

~/LIEF[main]% readelf -h test.patched.elf
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:                              EXEC (Executable file)
  Machine:                           RISC-V
  Version:                           0x1
  Entry point address:               0x20000
  Start of program headers:          8192 (bytes into file)
  Start of section headers:          57569 (bytes into file)
  Flags:                             0x1, RVC, soft-float ABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         7
  Size of section headers:           40 (bytes)
  Number of section headers:         24
  Section header string table index: 23

The program header table extends from 8192 (0x2000) to 8416 (0x20e0).

Looking at the section offsets:

~/LIEF[main]% readelf -lS test.elf
There are 22 section headers, starting at offset 0x78d8:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text.dummy       NOBITS          00020000 000154 000000 00   A  0   0  1
  [ 2] .text             PROGBITS        00020000 001000 00028e 00  AX  0   0  2
  [ 3] .rodata           PROGBITS        00020290 001290 00007c 00   A  0   0  4
  [ 4] .data             PROGBITS        00010000 00130c 000000 00   A  0   0  4
  [ 5] .bss              NOBITS          00010000 002000 000000 00  WA  0   0  4
  [ 6] .heap             NOBITS          00010000 002000 000000 00  WA  0   0  1
  [ 7] .stack            NOBITS          00010000 002000 00a000 00  WA  0   0  1
  [ 8] .stack_sizes      PROGBITS        00000000 002000 000028 00   L  2   0  1
  [ 9] .debug_loc        PROGBITS        00000000 002028 0003a3 00      0   0  1
  ...SNIP...

It overlaps with the .stack_sizes section, which is at offset 0x2000, explaining the corruption.
This overlap extends into the .debug_xxx sections which may explain the readelf warning.

PS: sry I had to zip the ELFs, github doesn't allow those...

test.zip

@romainthomas
Copy link
Member

Hi @andreasWallner

Thank you for this well-detailed issue. The RISC-V support in LIEF is not strongly tested and I'll investigate the root cause of you issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants