Git Product home page Git Product logo

xmas-elf's Introduction

xmas-elf

A library for parsing and navigating ELF files.

  • Pure Rust
  • Zero allocation (minimal allocation for interpreting the data)
  • Strongly, statically typed.

xmas-elf's People

Contributors

aleksander avatar diodesign avatar emberian avatar freax13 avatar fshaked avatar globin avatar gz avatar jeamland avatar jightuse avatar khernyo avatar khuey avatar kornelski avatar matts1 avatar nrc avatar phil-opp avatar philipc avatar photoszzt avatar rocallahan avatar samgiles avatar samueltardieu avatar teskje avatar toku-sa-n avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

xmas-elf's Issues

Make it no_std

I don't think I use anything from std itself, just re-exports, but I might be wrong

Weird panic when looking up section in my boot loader

Hi, I'm using your library for ELF executable parsing in my UEFI boot loader. I'm looking up the .bss section so I can zero it out, but the library is panicking instead:

[ERROR]: C:\Users\Visual\.cargo\registry\src\github.com-1ecc6299db9ec823\uefi-services-0.9.0\src\lib.rs@133: Panic in C:\Users\Visual\.cargo\registry\src\github.com-1ecc6299db9ec823\xmas-elf-0.8.0\src\lib.rs at (113, 25):
[ERROR]: C:\Users\Visual\.cargo\registry\src\github.com-1ecc6299db9ec823\uefi-services-0.9.0\src\lib.rs@140: range start index 3564710587087271204 out of range for slice of length 1033888

Related code:

let bss = elf
    .find_section_by_name(".bss")
    .expect("No .bss section found");
unsafe {
    (bss.address() as *mut u8).write_bytes(0, bss.size().try_into().unwrap());
}

Linker script: https://gist.github.com/VisualDevelopment/70c6aa6bd1cf0558f3c18909682bfd03

Don't use enums in Pod types

We can't guarantee that the raw data is valid, so it's not safe to interpret it as an enum value. It should use a new type instead.

This is causing the interpret_class test to fail when giving a value of 42u8 for the class.

I notice that this is already done for struct Type_, with an enum Type for the constants. Should the rest of the enums be converted to this style?

`parse_header` constructs an unaligned reference

Running cargo +nightly miri test causes the following error:

Crash log
Preparing a sysroot for Miri (target: x86_64-unknown-linux-gnu)... done
  Finished test [unoptimized + debuginfo] target(s) in 0.01s
   Running unittests src/lib.rs (target/miri/x86_64-unknown-linux-gnu/debug/deps/xmas_elf-3090fb77e8659e43)

running 1 test
test test::interpret_class ... error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1)
 --> /home/freax13/.cargo/registry/src/github.com-1ecc6299db9ec823/zero-0.1.2/src/lib.rs:107:5
  |
107 |     mem::transmute(input as *const [u8] as *const u8 as *const T)
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1)
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
  = note: BACKTRACE:
  = note: inside `zero::read_unsafe::<header::HeaderPt2_<u32>>` at /home/freax13/.cargo/registry/src/github.com-1ecc6299db9ec823/zero-0.1.2/src/lib.rs:107:5
  = note: inside `zero::read::<header::HeaderPt2_<u32>>` at /home/freax13/.cargo/registry/src/github.com-1ecc6299db9ec823/zero-0.1.2/src/lib.rs:42:9
note: inside `header::parse_header` at src/header.rs:27:17
 --> src/header.rs:27:17
  |
27  |                 read(&input[size_pt1..size_pt1 + mem::size_of::<HeaderPt2_<P32>>()]);
  |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `ElfFile::<'_>::new` at src/lib.rs:50:22
 --> src/lib.rs:50:22
  |
50  |         let header = header::parse_header(input)?;
  |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `test::interpret_class` at src/lib.rs:196:17
 --> src/lib.rs:196:17
  |
196 |         assert!(ElfFile::new(&mk_elf_header(1)).is_ok());
  |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside closure at src/lib.rs:194:5
 --> src/lib.rs:194:5
  |
193 |       #[test]
  |       ------- in this procedural macro expansion
194 | /     fn interpret_class() {
195 | |         assert!(ElfFile::new(&mk_elf_header(0)).is_err());
196 | |         assert!(ElfFile::new(&mk_elf_header(1)).is_ok());
197 | |         assert!(ElfFile::new(&mk_elf_header(2)).is_ok());
198 | |         assert!(ElfFile::new(&mk_elf_header(42u8)).is_err());
199 | |     }
  | |_____^
  = note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to previous error

error: test failed, to rerun pass `--lib`

Caused by:
process didn't exit successfully: `/home/freax13/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner /home/freax13/code/xmas-elf/target/miri/x86_64-unknown-linux-gnu/debug/deps/xmas_elf-3090fb77e8659e43` (exit status: 1)

The unaligned reference is created by the zero dependency. This dependency has already been patched to panic on unaligned references (nrc/zero@1d571c9), but there's no release containing this patch.

We probably want to prevent both UB and panics; I'm not sure what other parts of the code suffer from similar problems. Worst case scenario, we can probably put #[repr(packed)] on all the structs.

Load data using the correct byte order.

Except for the type named HeaderPt1, the rest of the ELF data uses the byte order indicated by the e_ident. Currently data will be read using the host's native byte order, which isn't correct in general.

It's not clear to me how to fix this, as the parsing approach taken by zero isn't particularly friendly to reinterpreting data.

Implement Eq on enums

Some enums should really implement Eq, such as xmas_elf::header::Class and probably others.

Program header flags are private and cannot be read

pub struct Flags(u32);

Flags are not useful because you cannot check the value of the flags element (flags.0 doesn't work) to see which flags are set (W, R, X) because the pub struct Flags(u32) is not public. It should either be public, or there should be getter/contain methods such as Flags::is_read()/is_write()/is_execute().

`parse_str` should probably be marked as unsafe

parse_str can violate memory safety: it can go beyond the input slice while looking for 0. The initial offset also can point outside of the slice. My understanding is that in Rust such functions should either be marked with unsafe or use assert to enforce memory safety.

Publish on crates.io

I'm getting ready to release one of my projects depending on xmas-elf, but I can't put it on crates.io because of the git dependency.

Panic on array index out of bounds

Found with honggfuzz.

The following input causes the panic: \x7F\x45\x4C\x46\x02\x07\x35\x38\x35\x33\x30\x38\x32\x30\x37\x30\x34\x32\x31\x36\x34\x37\x33\x32\x37\x35

thread 'main' panicked at 'index 64 out of range for slice of length 26', libcore/slice/mod.rs:2256:5
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::print
             at libstd/sys_common/backtrace.rs:71
             at libstd/sys_common/backtrace.rs:59
   2: std::panicking::default_hook::{{closure}}
             at libstd/panicking.rs:211
   3: std::panicking::default_hook
             at libstd/panicking.rs:227
   4: std::panicking::rust_panic_with_hook
             at libstd/panicking.rs:463
   5: std::panicking::begin_panic_fmt
             at libstd/panicking.rs:350
   6: rust_begin_unwind
             at libstd/panicking.rs:328
   7: core::panicking::panic_fmt
             at libcore/panicking.rs:71
   8: core::slice::slice_index_len_fail
             at libcore/slice/mod.rs:2256
   9: <core::ops::range::Range<usize> as core::slice::SliceIndex<[T]>>::index
             at /checkout/src/libcore/slice/mod.rs:2387
  10: core::slice::<impl core::ops::index::Index<I> for [T]>::index
             at /checkout/src/libcore/slice/mod.rs:2238
  11: xmas_elf::header::parse_header
             at /home/user/.cargo/git/checkouts/xmas-elf-0bb86b20f57b2942/720e94d/src/header.rs:28
  12: xmas_elf::ElfFile::new
             at /home/user/.cargo/git/checkouts/xmas-elf-0bb86b20f57b2942/720e94d/src/lib.rs:50
  13: elf_parse::main::{{closure}}
             at /home/user/daniel/targets/common/src/lib.rs:967
             at fuzzer-honggfuzz/src/bin/elf_parse.rs:8
  14: honggfuzz::fuzz
             at /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/honggfuzz-0.5.20/src/lib.rs:301
  15: elf_parse::main
             at fuzzer-honggfuzz/src/bin/elf_parse.rs:7
  16: std::rt::lang_start::{{closure}}
             at /checkout/src/libstd/rt.rs:74
  17: std::panicking::try::do_call
             at libstd/rt.rs:59
             at libstd/panicking.rs:310
  18: __rust_maybe_catch_panic
             at libpanic_unwind/lib.rs:105
  19: std::rt::lang_start_internal
             at libstd/panicking.rs:289
             at libstd/panic.rs:374
             at libstd/rt.rs:58
  20: std::rt::lang_start
             at /checkout/src/libstd/rt.rs:74
  21: main
  22: __libc_start_main
  23: _start

Return Rela types

Just wanted to get a sense if you would want to include specific type meanings (as an enum) for relocation types or is this out of scope for the library?

pub fn get_type(&self) -> u32 {

It's a bit tricky because values will be different for x86-64, x86-32, AARCH64 etc. But if you think it makes sense, I can prepare a pull request.

Weird index out of bound while parsing RISC-V 32-bit binary

While parsing the attached RISC-V 32-bit binary, xmas-elf crashes with the following error:

thread 'main' panicked at 'range end index 139232 out of range for slice of length 138600', library/core/src/slice/index.rs:73:5

The method that panics is sections.rs.SectionHeader.raw_data(), line 171.

readelf -e doesn't seem to complain at all:

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:               0x2c9e0
  Start of program headers:          52 (bytes into file)
  Start of section headers:          138160 (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:         6
  Size of section headers:           40 (bytes)
  Number of section headers:         11
  Section header string table index: 10

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .rodata           PROGBITS        000100f4 0000f4 0050ba 00  AM  0   0  4
  [ 2] .eh_frame_hdr     PROGBITS        000151b0 0051b0 00077c 00   A  0   0  4
  [ 3] .eh_frame         PROGBITS        0001592c 00592c 0019a0 00   A  0   0  4
  [ 4] .text             PROGBITS        000182cc 0072cc 01a7f2 00  AX  0   0  2
  [ 5] .sdata            PROGBITS        00033ac0 021ac0 000054 00  WA  0   0  8
  [ 6] .sbss             NOBITS          00033b14 021b14 000040 00  WA  0   0  4
  [ 7] .bss              NOBITS          00033b54 021b14 0004cc 00  WA  0   0  4
  [ 8] .riscv.attributes RISCV_ATTRIBUTE 00000000 021b14 00002b 00      0   0  1
  [ 9] .comment          PROGBITS        00000000 021b3f 000013 01  MS  0   0  1
  [10] .shstrtab         STRTAB          00000000 021b52 00005e 00      0   0  1
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), p (processor specific)

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x00010034 0x00010034 0x000c0 0x000c0 R   0x4
  LOAD           0x000000 0x00010000 0x00010000 0x072cc 0x072cc R   0x1000
  LOAD           0x0072cc 0x000182cc 0x000182cc 0x1a7f2 0x1a7f2 R E 0x1000
  LOAD           0x021ac0 0x00033ac0 0x00033ac0 0x00054 0x00560 RW  0x1000
  GNU_EH_FRAME   0x0051b0 0x000151b0 0x000151b0 0x0077c 0x0077c R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .rodata .eh_frame_hdr .eh_frame 
   02     .text 
   03     .sdata .sbss .bss 
   04     .eh_frame_hdr 
   05

keyboard-backlight.zip (since this is an executable, here's the VirusTotal analysis :-)

Fix note section handling

There are several issues with note sections:

  1. There are currently not supported in 32-bit ELF files, but as far as I know, the parsing of note sections in 32-bit and 64-bit ELF files is exactly the same. confusing comment here and documentation here
  2. A note section can contain many notes, not just the one at the start of the section.
  3. There is no way to obtain the note type, but the spec says you have to check both the name and the type before interpreting a note.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.