Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ pub fn load(
.unwrap();
let page_round_down = |addr: usize| addr / page_size * page_size;
let page_round_up = |addr: usize| (addr + (page_size - 1)) / page_size * page_size;

let mut segments: Vec<(usize, usize, ProtFlags)> = Vec::new();

for ph in elf.program_headers {
if ph.p_type != PT_LOAD {
continue;
Expand All @@ -104,7 +107,7 @@ pub fn load(
mmap(
Some(addr),
size,
prot | ProtFlags::PROT_WRITE, // TODO: read only fix
prot | ProtFlags::PROT_WRITE,
MapFlags::MAP_PRIVATE | MapFlags::MAP_FIXED,
Some(&file),
offset,
Expand All @@ -119,6 +122,7 @@ pub fn load(
page_round_up(file_end_addr) - file_end_addr,
);
}
segments.push((addr.get(), size.get(), prot));
}

// Relocations (needed for musl but not glibc FWICT)
Expand All @@ -130,5 +134,12 @@ pub fn load(
unsafe { ptr::write(dst, src) }
}

// after relocations, so writes into not-yet-protected segments still work
for (addr, size, prot) in segments {
unsafe {
nix::sys::mman::mprotect(addr as *mut nix::libc::c_void, size, prot).unwrap();
}
}

(base_addr, elf.header, opt_interp)
}
37 changes: 36 additions & 1 deletion src/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use nix::{
libc::{
getauxval, AT_BASE, AT_CLKTCK, AT_EGID, AT_ENTRY, AT_EUID, AT_EXECFN, AT_FLAGS, AT_GID,
AT_HWCAP, AT_NULL, AT_PAGESZ, AT_PHDR, AT_PHENT, AT_PHNUM, AT_PLATFORM, AT_RANDOM,
AT_SECURE, AT_UID,
AT_SECURE, AT_SYSINFO_EHDR, AT_UID,
},
sys::mman::{mmap, MapFlags, ProtFlags},
unistd::{getegid, geteuid, getgid, getuid, SysconfVar},
Expand Down Expand Up @@ -69,6 +69,7 @@ impl<'a, A: AsRef<CStr>, E: AsRef<CStr>> StackBuilder<'a, A, E> {
(AT_RANDOM, at_random_addr),
(AT_CLKTCK, sysconf(SysconfVar::CLK_TCK)),
(AT_HWCAP, unsafe { getauxval(AT_HWCAP) }),
(AT_SYSINFO_EHDR, unsafe { getauxval(AT_SYSINFO_EHDR) }),
(AT_EGID, getegid().as_raw().into()),
(AT_GID, getgid().as_raw().into()),
(AT_EUID, geteuid().as_raw().into()),
Expand Down Expand Up @@ -153,6 +154,23 @@ impl<'a, A: AsRef<CStr>, E: AsRef<CStr>> StackBuilder<'a, A, E> {
}
}

// start_stack (field 28) is the initial sp; unlike environ it survives setenv().
fn original_auxv() -> Option<*mut usize> {
let stat = std::fs::read_to_string("/proc/self/stat").ok()?;
let fields = stat.rsplit_once(')')?.1;
let start_stack: usize = fields.split_whitespace().nth(25)?.parse().ok()?;
let sp = start_stack as *const usize;
if sp.is_null() {
return None;
}
let argc = unsafe { *sp };
let mut envp = unsafe { (sp as *const usize).add(argc + 2) };
while unsafe { *envp } != 0 {
envp = unsafe { envp.add(1) };
}
Some(unsafe { (envp as *mut usize).add(1) })
}

pub fn make_stack(
interp_addr: Option<usize>,
bin_addr: usize,
Expand Down Expand Up @@ -203,5 +221,22 @@ pub fn make_stack(

unsafe { std::ptr::copy_nonoverlapping(data.as_ptr(), sp as *mut u8, data.len()) }

if let Some(mut auxv) = original_auxv() {
unsafe {
while *auxv != AT_NULL as usize {
let value = auxv.add(1);
match *auxv {
x if x == AT_BASE as usize => *value = interp_addr.unwrap_or_default(),
x if x == AT_PHDR as usize => *value = bin_addr + bin_header.e_phoff as usize,
x if x == AT_PHNUM as usize => *value = bin_header.e_phnum as usize,
x if x == AT_PHENT as usize => *value = bin_header.e_phentsize as usize,
x if x == AT_ENTRY as usize => *value = bin_addr + bin_header.e_entry as usize,
_ => {}
}
auxv = auxv.add(2);
}
}
}

sp
}