Skip to content

Commit

Permalink
Feature - Strict ELF parser (#624)
Browse files Browse the repository at this point in the history
* Moves ELF header parsing from load() to load_with_parser().

* Reorders UnsupportedSBPFVersion to be directly checked behind the header OutOfBounds.

* Splits out Executable::load_with_lenient_parser().

* Adds Executable::load_with_strict_parser().

* Adds new linker script and test ELF.

* Adds tests.
  • Loading branch information
Lichtso authored Nov 15, 2024
1 parent 8d36530 commit b78c20f
Show file tree
Hide file tree
Showing 10 changed files with 471 additions and 42 deletions.
390 changes: 374 additions & 16 deletions src/elf.rs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/elf_parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ impl<'a> Elf64<'a> {
}

/// Returns the `&[T]` contained at `bytes[range]`
fn slice_from_bytes<T: 'static>(
pub fn slice_from_bytes<T: 'static>(
bytes: &[u8],
range: Range<usize>,
) -> Result<&[T], ElfParserError> {
Expand Down
9 changes: 7 additions & 2 deletions src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ pub enum SBPFVersion {
V1,
/// The current format
V2,
/// The future format with BTF support
V3,
/// Used for future versions
Reserved,
}

impl SBPFVersion {
Expand Down Expand Up @@ -95,6 +95,11 @@ impl SBPFVersion {
pub fn move_memory_instruction_classes(self) -> bool {
self != SBPFVersion::V1
}

/// Constrain ELF format to ignore section headers and relocations
pub fn enable_stricter_elf_headers(self) -> bool {
self != SBPFVersion::V1
}
}

/// Holds the function symbols of an Executable
Expand Down
45 changes: 25 additions & 20 deletions tests/elfs/elf.ld
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
PHDRS
{
text PT_LOAD ;
rodata PT_LOAD ;
data PT_LOAD ;
dynamic PT_DYNAMIC ;
}

SECTIONS
{
. = SIZEOF_HEADERS;
.text : { *(.text*) } :text
.rodata : { *(.rodata*) } :rodata
.data.rel.ro : { *(.data.rel.ro*) } :rodata
.dynamic : { *(.dynamic) } :dynamic
.dynsym : { *(.dynsym) } :data
.dynstr : { *(.dynstr) } :data
.rel.dyn : { *(.rel.dyn) } :data
.data : { *(.data*) } :data
.bss : { *(.bss*) } :data
.text 0x000000000 : { *(.text*) } :text
.rodata 0x100000000 : { *(.rodata*) } :rodata
.bss.stack 0x200000000 : { *(.bss.stack*) } :stack
.bss.heap 0x300000000 : { *(.bss.heap*) } :heap
.dynsym 0xFFFFFFFF00000000 : { *(.dynsym) } :dynsym
.dynstr : { *(.dynstr) } :other
.dynamic : { *(.dynamic) } :other
.symtab : { *(.symtab) } :other
.shstrtab : { *(.shstrtab) } :other
.strtab : { *(.strtab) } :other
/DISCARD/ : {
*(.comment*)
*(.eh_frame*)
*(.gnu.hash*)
*(.hash*)
*(*hash*)
*(.bss*)
*(.data*)
*(.rel.dyn*)
}
}

PHDRS
{
text PT_LOAD FLAGS(1);
rodata PT_LOAD FLAGS(4);
stack PT_GNU_STACK FLAGS(6);
heap PT_LOAD FLAGS(6);
dynsym PT_NULL FLAGS(0);
other PT_NULL FLAGS(0);
}
26 changes: 26 additions & 0 deletions tests/elfs/elf_sbpfv1.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
PHDRS
{
text PT_LOAD ;
rodata PT_LOAD ;
data PT_LOAD ;
dynamic PT_DYNAMIC ;
}

SECTIONS
{
. = SIZEOF_HEADERS;
.text : { *(.text*) } :text
.rodata : { *(.rodata*) } :rodata
.data.rel.ro : { *(.data.rel.ro*) } :rodata
.dynamic : { *(.dynamic) } :dynamic
.dynsym : { *(.dynsym) } :data
.dynstr : { *(.dynstr) } :data
.rel.dyn : { *(.rel.dyn) } :data
.data : { *(.data*) } :data
.bss : { *(.bss*) } :data
/DISCARD/ : {
*(.eh_frame*)
*(.gnu.hash*)
*(.hash*)
}
}
9 changes: 6 additions & 3 deletions tests/elfs/elfs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ TOOLCHAIN=../../../agave/sdk/sbf/dependencies/platform-tools
RC_COMMON="$TOOLCHAIN/rust/bin/rustc --target sbf-solana-solana --crate-type lib -C panic=abort -C opt-level=2"
RC="$RC_COMMON -C target_cpu=sbfv2"
RC_V1="$RC_COMMON -C target_cpu=generic"
LD_COMMON="$TOOLCHAIN/llvm/bin/ld.lld -z notext -shared --Bdynamic -entry entrypoint --script elf.ld"
LD="$LD_COMMON --section-start=.text=0x100000000"
LD_V1=$LD_COMMON
LD_COMMON="$TOOLCHAIN/llvm/bin/ld.lld -z notext -shared --Bdynamic -entry entrypoint"
LD="$LD_COMMON --script elf.ld"
LD_V1="$LD_COMMON --script elf_sbpfv1.ld"

$RC -o strict_header.o strict_header.rs
$LD -o strict_header.so strict_header.o

$RC_V1 -o relative_call.o relative_call.rs
$LD_V1 -o relative_call_sbpfv1.so relative_call.o
Expand Down
Binary file modified tests/elfs/program_headers_overflow.so
Binary file not shown.
21 changes: 21 additions & 0 deletions tests/elfs/strict_header.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#![feature(linkage)]

#[link_section = ".bss.stack"]
pub static _STACK: [u8; 0x1000] = [0; 0x1000];
#[link_section = ".bss.heap"]
pub static _HEAP: [u8; 0x1000] = [0; 0x1000];

static _VAL_A: u64 = 41;
static VAL_B: u64 = 42;
static _VAL_C: u64 = 43;

#[inline(never)]
#[linkage="external"]
fn foo() -> u64 {
return unsafe { core::ptr::read_volatile(&VAL_B) };
}

#[no_mangle]
pub fn entrypoint() -> u64 {
return foo();
}
Binary file added tests/elfs/strict_header.so
Binary file not shown.
11 changes: 11 additions & 0 deletions tests/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3049,6 +3049,17 @@ fn test_struct_func_pointer() {
);
}

#[test]
fn test_strict_header() {
test_interpreter_and_jit_elf!(
"tests/elfs/strict_header.so",
[],
(),
TestContextObject::new(6),
ProgramResult::Ok(42),
);
}

// Programs

#[test]
Expand Down

0 comments on commit b78c20f

Please sign in to comment.