Skip to content

Commit

Permalink
Split the ELF binary format handling from the script binary format.
Browse files Browse the repository at this point in the history
This makes it more clear what code is doing what, and highlights that
scripts aren't getting passed their arguments.
  • Loading branch information
anholt committed Sep 29, 2024
1 parent 9816b67 commit 831c8f8
Showing 1 changed file with 56 additions and 35 deletions.
91 changes: 56 additions & 35 deletions kernel/process/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::{
ctypes::*,
fs::{
devfs::SERIAL_TTY,
inode::FileLike,
mount::RootFs,
opened_file::{Fd, OpenFlags, OpenOptions, OpenedFile, OpenedFileTable, PathComponent},
path::Path,
Expand Down Expand Up @@ -560,44 +561,39 @@ fn setup_userspace(
do_setup_userspace(executable_path, argv, envp, root_fs, true)
}

/// Creates a new virtual memory space, parses and maps an executable file,
/// and set up the user stack.
fn do_setup_userspace(
executable_path: Arc<PathComponent>,
argv: &[&[u8]],
fn do_script_binfmt(
executable_path: &Arc<PathComponent>,
_argv: &[&[u8]], // TODO: Ignoring this seems wrong
envp: &[&[u8]],
root_fs: &Arc<SpinLock<RootFs>>,
handle_shebang: bool,
buf: &[u8],
) -> Result<UserspaceEntry> {
// Read the ELF header in the executable file.
let file_header_len = PAGE_SIZE;
let file_header_top = USER_STACK_TOP;
let file_header_pages = alloc_pages(file_header_len / PAGE_SIZE, AllocPageFlags::KERNEL)?;
let buf =
unsafe { core::slice::from_raw_parts_mut(file_header_pages.as_mut_ptr(), file_header_len) };

let executable = executable_path.inode.as_file()?;
executable.read(0, buf.into(), &OpenOptions::readwrite())?;

if handle_shebang && buf.starts_with(b"#!") && buf.contains(&b'\n') {
let mut argv: Vec<&[u8]> = buf[2..buf.iter().position(|&ch| ch == b'\n').unwrap()]
.split(|&ch| ch == b' ')
.collect();
if argv.is_empty() {
return Err(Errno::EINVAL.into());
}
let mut argv: Vec<&[u8]> = buf[2..buf.iter().position(|&ch| ch == b'\n').unwrap()]
.split(|&ch| ch == b' ')
.collect();
if argv.is_empty() {
return Err(Errno::EINVAL.into());
}

let executable_pathbuf = executable_path.resolve_absolute_path();
argv.push(executable_pathbuf.as_str().as_bytes());
let executable_pathbuf = executable_path.resolve_absolute_path();
argv.push(executable_pathbuf.as_str().as_bytes());

let shebang_path = root_fs.lock().lookup_path(
Path::new(core::str::from_utf8(argv[0]).map_err(|_| Error::new(Errno::EINVAL))?),
true,
)?;
let shebang_path = root_fs.lock().lookup_path(
Path::new(core::str::from_utf8(argv[0]).map_err(|_| Error::new(Errno::EINVAL))?),
true,
)?;

return do_setup_userspace(shebang_path, &argv, envp, root_fs, false);
}
do_setup_userspace(shebang_path, &argv, envp, root_fs, false)
}

fn do_elf_binfmt(
executable: &Arc<dyn FileLike>,
argv: &[&[u8]],
envp: &[&[u8]],
file_header_pages: kerla_api::address::PAddr,
buf: &[u8],
) -> Result<UserspaceEntry> {
let file_header_top = USER_STACK_TOP;
let elf = Elf::parse(buf)?;
let ip = elf.entry()?;

Expand All @@ -615,7 +611,7 @@ fn do_setup_userspace(
let auxv = &[
Auxv::Phdr(
file_header_top
.sub(file_header_len)
.sub(buf.len())
.add(elf.header().e_phoff as usize),
),
Auxv::Phnum(elf.program_headers().len()),
Expand All @@ -624,7 +620,7 @@ fn do_setup_userspace(
Auxv::Random(random_bytes),
];
const USER_STACK_LEN: usize = 128 * 1024; // TODO: Implement rlimit
let init_stack_top = file_header_top.sub(file_header_len);
let init_stack_top = file_header_top.sub(buf.len());
let user_stack_bottom = init_stack_top.sub(USER_STACK_LEN).value();
let user_heap_bottom = align_up(end_of_image, PAGE_SIZE);
let init_stack_len = align_up(estimate_user_init_stack_size(argv, envp, auxv), PAGE_SIZE);
Expand All @@ -646,9 +642,9 @@ fn do_setup_userspace(
UserVAddr::new(user_stack_bottom).unwrap(),
UserVAddr::new(user_heap_bottom).unwrap(),
)?;
for i in 0..(file_header_len / PAGE_SIZE) {
for i in 0..(buf.len() / PAGE_SIZE) {
vm.page_table_mut().map_user_page(
file_header_top.sub(((file_header_len / PAGE_SIZE) - i) * PAGE_SIZE),
file_header_top.sub(((buf.len() / PAGE_SIZE) - i) * PAGE_SIZE),
file_header_pages.add(i * PAGE_SIZE),
);
}
Expand Down Expand Up @@ -686,6 +682,31 @@ fn do_setup_userspace(
Ok(UserspaceEntry { vm, ip, user_sp })
}

/// Creates a new virtual memory space, parses and maps an executable file,
/// and set up the user stack.
fn do_setup_userspace(
executable_path: Arc<PathComponent>,
argv: &[&[u8]],
envp: &[&[u8]],
root_fs: &Arc<SpinLock<RootFs>>,
handle_shebang: bool,
) -> Result<UserspaceEntry> {
// Read the ELF header in the executable file.
let file_header_len = PAGE_SIZE;
let file_header_pages = alloc_pages(file_header_len / PAGE_SIZE, AllocPageFlags::KERNEL)?;
let buf =
unsafe { core::slice::from_raw_parts_mut(file_header_pages.as_mut_ptr(), file_header_len) };

let executable = executable_path.inode.as_file()?;
executable.read(0, buf.into(), &OpenOptions::readwrite())?;

if handle_shebang && buf.starts_with(b"#!") && buf.contains(&b'\n') {
return do_script_binfmt(&executable_path, argv, envp, root_fs, buf);
}

do_elf_binfmt(executable, argv, envp, file_header_pages, buf)
}

pub fn gc_exited_processes() {
if current_process().is_idle() {
// If we're in an idle thread, it's safe to free kernel stacks allocated
Expand Down

0 comments on commit 831c8f8

Please sign in to comment.