Skip to content

Commit

Permalink
fix bugs of SYS_execve that uses SYS_mmap not correctly, and add exam…
Browse files Browse the repository at this point in the history
…ple app for ELF loader.
  • Loading branch information
thesayol committed Apr 19, 2024
1 parent 9d11be4 commit 5d0b4af
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 112 deletions.
52 changes: 19 additions & 33 deletions api/ruxos_posix_api/src/imp/execve/load_elf.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
use crate::{ctypes::kstat, utils::char_ptr_to_str, *};
use crate::{ctypes::kstat, *};
use alloc::{vec, vec::Vec};
use core::{
ffi::c_char,
ptr::{null, null_mut},
};
use core::ptr::null_mut;

#[derive(Debug)]
pub struct ElfProg {
pub name: Vec<u8>,
pub path: Vec<u8>,
pub platform: Vec<u8>,
pub rand: Vec<u64>,
pub base: usize,
pub entry: usize,
pub interp_path: *const c_char,
pub interp_path: Vec<u8>,
pub phent: usize,
pub phnum: usize,
pub phdr: usize,
Expand All @@ -23,13 +16,11 @@ impl ElfProg {
/// read elf from `path`, and copy LOAD segments to a alloacated memory
///
/// and load interp, if needed.
pub fn new(filepath: *const c_char) -> Self {
let name = char_ptr_to_str(filepath).unwrap().as_bytes().to_vec();
let path = name.clone();
debug!("sys_execve: new elf prog: {:?}", char_ptr_to_str(filepath));
pub fn new(filepath: &str) -> Self {
debug!("sys_execve: new elf prog: {filepath}");

// open file
let fd = sys_open(filepath, ctypes::O_RDWR as i32, 0);
let fd = sys_open(filepath.as_ptr() as _, ctypes::O_RDWR as _, 0);

// get file size
let mut buf = ctypes::kstat {
Expand All @@ -49,16 +40,23 @@ impl ElfProg {
.expect("parse ELF failed");

// get program's LOAD mem size
let mut msize = 0;
let mut min_addr = 0;
let mut max_addr = 0;
let segs = file.segments().unwrap();
for seg in segs {
if seg.p_type == elf::abi::PT_LOAD {
msize += seg.p_memsz;
min_addr = min_addr.min(seg.p_vaddr);
max_addr = max_addr.max(seg.p_vaddr + seg.p_memsz);
}
}
let msize = (max_addr - min_addr) as usize;

// alloc memory for LOAD
let prot = ctypes::PROT_WRITE | ctypes::PROT_READ | ctypes::PROT_EXEC;
let flags = ctypes::MAP_ANONYMOUS | ctypes::MAP_PRIVATE;
let base = crate::sys_mmap(null_mut(), msize, prot as _, flags as _, -1, 0) as usize;

// copy LOAD segments
let base = crate::sys_mmap(null_mut(), msize as usize, 0, 0, 0, 0) as usize;
for seg in segs {
if seg.p_type == elf::abi::PT_LOAD {
let data = file.segment_data(&seg).unwrap();
Expand All @@ -74,23 +72,15 @@ impl ElfProg {
let entry = file.ehdr.e_entry as usize + base;

// parse interpreter
let mut interp_path = null::<c_char>();
let mut interp_path = vec![];
for seg in file.segments().unwrap() {
if seg.p_type == elf::abi::PT_INTERP {
let data = file.segment_data(&seg).unwrap();
interp_path = data.as_ptr() as *const c_char;
let data = file.segment_data(&seg).unwrap().to_vec();
interp_path = data;
break;
}
}

// platform
#[cfg(target_arch = "aarch64")]
let platform = b"aarch64".to_vec();
#[cfg(target_arch = "x86_64")]
let platform = b"x86_64".to_vec();
#[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
let platform = b"unknown".to_vec();

// get address of .text for debugging
let text_section_addr = base
+ file
Expand All @@ -107,10 +97,6 @@ impl ElfProg {
Self {
base,
entry,
name,
path,
platform,
rand: alloc::vec![1, 2],
interp_path,
phent: file.ehdr.e_phentsize as usize,
phnum: file.ehdr.e_phnum as usize,
Expand Down
91 changes: 48 additions & 43 deletions api/ruxos_posix_api/src/imp/execve/mod.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
use core::ffi::c_char;

mod auxv;
mod load_elf;
mod stack;

use alloc::vec;
use core::ffi::c_char;

use crate::{
config,
imp::stat::{sys_getgid, sys_getuid},
sys_getegid, sys_geteuid,
sys_getegid, sys_geteuid, sys_random,
utils::char_ptr_to_str,
};

/// int execve(const char *pathname, char *const argv[], char *const envp[] );
pub fn sys_execve(pathname: *const c_char, argv: usize, envp: usize) -> ! {
use auxv::*;

let prog = load_elf::ElfProg::new(pathname);
let path = char_ptr_to_str(pathname).unwrap();
let prog = load_elf::ElfProg::new(path);

// get entry
let mut entry = prog.entry;

// if interp is needed
let mut at_base = 0;
if !prog.interp_path.is_null() {
let interp_prog = load_elf::ElfProg::new(prog.interp_path);
if !prog.interp_path.is_empty() {
let interp_path = char_ptr_to_str(prog.interp_path.as_ptr() as _).unwrap();
let interp_prog = load_elf::ElfProg::new(interp_path);
entry = interp_prog.entry;
at_base = interp_prog.base;
debug!("sys_execve: INTERP base is {:x}", at_base);
Expand All @@ -32,18 +35,13 @@ pub fn sys_execve(pathname: *const c_char, argv: usize, envp: usize) -> ! {
// create stack
let mut stack = stack::Stack::new();

let name = prog.name;
let platform = prog.platform;

// non 8B info
stack.push(vec![0u8; 32], 16);
let p_progname = stack.push(name, 16);
let _p_plat = stack.push(platform, 16); // platform
let p_rand = stack.push(prog.rand, 16); // rand
stack.push(&[0u8; 32], 16);
let rand = unsafe { [sys_random(), sys_random()] };
let p_rand = stack.push(&rand, 16);

// auxv
// TODO: vdso and rand
// TODO: a way to get pagesz instead of a constant
// TODO: vdso
let auxv = vec![
AT_PHDR,
prog.phdr,
Expand All @@ -54,9 +52,11 @@ pub fn sys_execve(pathname: *const c_char, argv: usize, envp: usize) -> ! {
AT_BASE,
at_base,
AT_PAGESZ,
0x1000,
config::PAGE_SIZE_4K,
AT_HWCAP,
0,
AT_PLATFORM,
platform(),
AT_CLKTCK,
100,
AT_FLAGS,
Expand All @@ -74,7 +74,7 @@ pub fn sys_execve(pathname: *const c_char, argv: usize, envp: usize) -> ! {
AT_SECURE,
0,
AT_EXECFN,
p_progname,
pathname as usize,
AT_RANDOM,
p_rand,
AT_SYSINFO_EHDR,
Expand All @@ -88,53 +88,48 @@ pub fn sys_execve(pathname: *const c_char, argv: usize, envp: usize) -> ! {
// handle envs and args
let mut env_vec = vec![];
let mut arg_vec = vec![];
let mut argc = 0;

let envp = envp as *const usize;
let mut envp = envp as *const usize;
unsafe {
let mut i = 0;
while *envp.add(i) != 0 {
env_vec.push(*envp.add(i));
i += 1;
while *envp != 0 {
env_vec.push(*envp);
envp = envp.add(1);
}
env_vec.push(0);
}

let argv = argv as *const usize;
let mut argv = argv as *const usize;
unsafe {
let mut i = 0;
loop {
let p = *argv.add(i);
if p == 0 {
break;
}
arg_vec.push(p);
argc += 1;
i += 1;
while *argv != 0 {
arg_vec.push(*argv);
argv = argv.add(1);
}

arg_vec.push(0);
}

// push
stack.push(auxv, 16);
stack.push(env_vec, 8);
stack.push(arg_vec, 8);
let _sp = stack.push(vec![argc as usize], 8);
stack.push(&auxv, 16);
stack.push(&env_vec, 8);
stack.push(&arg_vec, 8);
let sp = stack.push(&[arg_vec.len() - 1], 8); // argc

// try run
debug!(
"sys_execve: run at entry 0x{entry:x}, then it will jump to 0x{:x} ",
"sys_execve: sp is 0x{sp:x}, run at 0x{entry:x}, then jump to 0x{:x} ",
prog.entry
);

set_sp_and_jmp(sp, entry);
}

fn set_sp_and_jmp(sp: usize, entry: usize) -> ! {
#[cfg(target_arch = "aarch64")]
unsafe {
core::arch::asm!("
mov sp, {}
blr {}
br {}
",
in(reg)_sp,
in(reg)sp,
in(reg)entry,
);
}
Expand All @@ -144,10 +139,20 @@ pub fn sys_execve(pathname: *const c_char, argv: usize, envp: usize) -> ! {
mov rsp, {}
jmp {}
",
in(reg)_sp,
in(reg)sp,
in(reg)entry,
);
}
unreachable!("sys_execve: unknown arch, sp 0x{sp:x}, entry 0x{entry:x}");
}

fn platform() -> usize {
#[cfg(target_arch = "aarch64")]
const PLATFORM_STRING: &[u8] = b"aarch64\0";
#[cfg(target_arch = "x86_64")]
const PLATFORM_STRING: &[u8] = b"x86_64\0";
#[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
const PLATFORM_STRING: &[u8] = b"unknown\0";

unreachable!("sys_execve: unknown arch");
PLATFORM_STRING.as_ptr() as usize
}
60 changes: 24 additions & 36 deletions api/ruxos_posix_api/src/imp/execve/stack.rs
Original file line number Diff line number Diff line change
@@ -1,55 +1,43 @@
use core::{mem::size_of, ptr::null_mut};
use alloc::{vec, vec::Vec};

use crate::*;
const STACK_SIZE: usize = ruxconfig::TASK_STACK_SIZE;

#[derive(Debug)]
pub struct Stack {
sp: usize,
start: usize,
end: usize,
/// stack
data: Vec<u8>,
/// index of top byte of stack
top: usize,
}

impl Stack {
// alloc a stack
/// alloc a stack
pub fn new() -> Self {
let size = 0xa00000; // 10M
let p = sys_mmap(null_mut(), size, 0, 0, 0, 0);

let start = p as usize;
let sp = start + size;
let end = sp;

Self { sp, start, end }
Self {
data: vec![0u8; STACK_SIZE],
top: STACK_SIZE,
}
}

pub fn align(&mut self, align: usize) -> usize {
self.sp -= self.sp % align;
self.sp
/// addr of top of stack
pub fn sp(&self) -> usize {
self.data.as_ptr() as usize + self.top
}

pub fn push<T: Copy>(&mut self, thing: alloc::vec::Vec<T>, align: usize) -> usize {
let size = thing.len() * size_of::<T>();
self.sp -= size;
self.sp = self.align(align); // align 16B
/// push data to stack and return the addr of sp
pub fn push<T>(&mut self, data: &[T], align: usize) -> usize {
// move sp to right place
self.top -= core::mem::size_of_val(data);
self.top = memory_addr::align_down(self.top, align);

if self.sp < self.start {
panic!("stack overflow");
}
assert!(self.top <= self.data.len(), "sys_execve: stack overflow.");

let mut pt = self.sp as *mut T;
// write data into stack
let sp = self.sp() as *mut T;
unsafe {
for t in thing {
*pt = t;
pt = pt.add(1);
}
sp.copy_from_nonoverlapping(data.as_ptr(), data.len());
}

self.sp
}
}

impl Drop for Stack {
fn drop(&mut self) {
sys_munmap(self.start as *mut _, self.end - self.start);
sp as usize
}
}
10 changes: 10 additions & 0 deletions apps/c/dl/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
ruxgo_bld
compile_commands.json
.cache
/rootfs/bin/*
/rootfs/lib/*
/rootfs/dev
/rootfs/etc
/rootfs/proc
/rootfs/sys
/rootfs/tmp
Loading

0 comments on commit 5d0b4af

Please sign in to comment.