Skip to content

Commit

Permalink
add some syscalls for x86_64 and aarch64.
Browse files Browse the repository at this point in the history
  • Loading branch information
thesayol committed Apr 8, 2024
1 parent 8c43a6a commit 20da344
Show file tree
Hide file tree
Showing 37 changed files with 772 additions and 50 deletions.
2 changes: 1 addition & 1 deletion api/ruxos_posix_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ static_assertions = "1.1.0"
spin = { version = "0.9" }
lazy_static = { version = "1.4", features = ["spin_no_std"] }
flatten_objects = { path = "../../crates/flatten_objects" }

elf = { version = "0.7", default-features = false }
bitflags = "2.2"

[build-dependencies]
Expand Down
42 changes: 42 additions & 0 deletions api/ruxos_posix_api/src/imp/cap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use core::ffi::c_int;

#[derive(Debug, Clone, Copy)]
struct UserCapHeader {
/// Linux Cap Version:
/// Version1 = 0x19980330,
/// Version2 = 0x20071026,
/// Version3 = 0x20080522,
version: u32,
pid: i32,
}

/// The effective, permitted, and inheritable fields are bit masks of the capabilities.
/// Note that the CAP_* values are bit indexes and need to be bit-shifted before ORing into the bit fields.
#[derive(Debug, Clone, Copy)]
struct UserCapData {
effective: u32,
permitted: u32,
inheritable: u32,
}

/// get thread capabilities. specific to Linux.
pub fn sys_cap_get(cap_user_header: usize, cap_user_data: usize) -> c_int {
let hdrp = cap_user_header as *const UserCapHeader;
let datap = cap_user_data as *mut UserCapData;
unsafe {
debug!(
"sys_cap_get <= pid {:?}, version {:x?} ",
(*hdrp).pid,
(*hdrp).version
);
}
syscall_body!(sys_cap_get, {
unsafe {
// allow all
(*datap).effective = u32::MAX;
(*datap).inheritable = u32::MAX;
(*datap).permitted = u32::MAX;
};
Ok(0)
})
}
41 changes: 41 additions & 0 deletions api/ruxos_posix_api/src/imp/execve/auxv.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#![allow(unused)]

pub const AT_NULL: usize = 0;
pub const AT_IGNORE: usize = 1;

pub const AT_EXECFD: usize = 2;

/// The address of the program headers of the executable.
pub const AT_PHDR: usize = 3;

pub const AT_PHENT: usize = 4;
pub const AT_PHNUM: usize = 5;
pub const AT_PAGESZ: usize = 6;

/// The base address of the program interpreter (usually, the dynamic linker).
pub const AT_BASE: usize = 7;

pub const AT_FLAGS: usize = 8;
pub const AT_ENTRY: usize = 9;
pub const AT_NOTELF: usize = 10;
pub const AT_UID: usize = 11;
pub const AT_EUID: usize = 12;
pub const AT_GID: usize = 13;
pub const AT_EGID: usize = 14;
pub const AT_PLATFORM: usize = 15;
pub const AT_HWCAP: usize = 16;
pub const AT_CLKTCK: usize = 17;
pub const AT_DCACHEBSIZE: usize = 19;
pub const AT_ICACHEBSIZE: usize = 20;
pub const AT_UCACHEBSIZE: usize = 21;
pub const AT_SECURE: usize = 23;
pub const AT_RANDOM: usize = 25;

/// A pointer to a string containing the pathname used to execute the program.
pub const AT_EXECFN: usize = 31;

/// The address of a page containing the vDSO that the kernel creates
pub const AT_SYSINFO_EHDR: usize = 33;

/// The entry point to the system call function in the vDSO. Not present/needed on all architectures (e.g., absent on x86-64).
pub const AT_SYSINFO: usize = 32;
120 changes: 120 additions & 0 deletions api/ruxos_posix_api/src/imp/execve/load_elf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use crate::{ctypes::kstat, utils::char_ptr_to_str, *};
use alloc::{vec, vec::Vec};
use core::{
ffi::c_char,
ptr::{null, 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 phent: usize,
pub phnum: usize,
pub phdr: usize,
}

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));

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

// get file size
let mut buf = ctypes::kstat {
..Default::default()
};
sys_fstat(fd, &mut buf as *const kstat as *mut _);
let filesize = buf.st_size as usize;

// read file
let mut file = vec![0u8; filesize];
sys_read(fd, file.as_mut_ptr() as *mut _, filesize);
debug!("sys_execve: read file size 0x{filesize:x}");
sys_close(fd);

// parse elf
let file = elf::ElfBytes::<elf::endian::AnyEndian>::minimal_parse(&file)
.expect("parse ELF failed");

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

// 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();
let dst = (seg.p_vaddr as usize + base) as *mut u8;
unsafe { dst.copy_from_nonoverlapping(data.as_ptr(), data.len()) };
}
}

// phdr
let phdr = base + file.ehdr.e_phoff as usize;

// get entry
let entry = file.ehdr.e_entry as usize + base;

// parse interpreter
let mut interp_path = null::<c_char>();
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;
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
.section_header_by_name(".text")
.unwrap()
.unwrap()
.sh_offset as usize;
debug!(
"sys_execve: loaded ELF in 0x{:x}, .text is 0x{:x}",
base, text_section_addr
);

// create retval
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,
phdr,
}
}
}
153 changes: 153 additions & 0 deletions api/ruxos_posix_api/src/imp/execve/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
use core::ffi::c_char;

mod auxv;
mod load_elf;
mod stack;

use alloc::vec;

use crate::{
imp::stat::{sys_getgid, sys_getuid},
sys_getegid, sys_geteuid,
};

/// 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);

// 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);
entry = interp_prog.entry;
at_base = interp_prog.base;
debug!("sys_execve: INTERP base is {:x}", at_base);
};

// 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

// auxv
// TODO: vdso and rand
// TODO: a way to get pagesz instead of a constant
let auxv = vec![
AT_PHDR,
prog.phdr,
AT_PHNUM,
prog.phnum,
AT_PHENT,
prog.phent,
AT_BASE,
at_base,
AT_PAGESZ,
0x1000,
AT_HWCAP,
0,
AT_CLKTCK,
100,
AT_FLAGS,
0,
AT_ENTRY,
prog.entry,
AT_UID,
sys_getuid() as usize,
AT_EUID,
sys_geteuid() as usize,
AT_EGID,
sys_getegid() as usize,
AT_GID,
sys_getgid() as usize,
AT_SECURE,
0,
AT_EXECFN,
p_progname,
AT_RANDOM,
p_rand,
AT_SYSINFO_EHDR,
0,
AT_IGNORE,
0,
AT_NULL,
0,
];

// handle envs and args
let mut env_vec = vec![];
let mut arg_vec = vec![];
let mut argc = 0;

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

let 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;
}

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);

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

#[cfg(target_arch = "aarch64")]
unsafe {
core::arch::asm!("
mov sp, {}
blr {}
",
in(reg)_sp,
in(reg)entry,
);
}
#[cfg(target_arch = "x86_64")]
unsafe {
core::arch::asm!("
mov rsp, {}
jmp {}
",
in(reg)_sp,
in(reg)entry,
);
}

unreachable!("sys_execve: unknown arch");
}
Loading

0 comments on commit 20da344

Please sign in to comment.