mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-17 02:26:46 +00:00
Support reading argv and envp from init stack
This commit is contained in:
parent
cc4111cab2
commit
29ebf8e60c
@ -358,9 +358,7 @@ fn clone_vm(parent_process_vm: &ProcessVm, clone_flags: CloneFlags) -> Result<Pr
|
|||||||
if clone_flags.contains(CloneFlags::CLONE_VM) {
|
if clone_flags.contains(CloneFlags::CLONE_VM) {
|
||||||
Ok(parent_process_vm.clone())
|
Ok(parent_process_vm.clone())
|
||||||
} else {
|
} else {
|
||||||
let root_vmar = Vmar::<Full>::fork_from(parent_process_vm.root_vmar())?;
|
ProcessVm::fork_from(parent_process_vm)
|
||||||
let user_heap = parent_process_vm.user_heap().clone();
|
|
||||||
Ok(ProcessVm::new(user_heap, root_vmar))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ pub use process::{
|
|||||||
Terminal,
|
Terminal,
|
||||||
};
|
};
|
||||||
pub use process_filter::ProcessFilter;
|
pub use process_filter::ProcessFilter;
|
||||||
|
pub use process_vm::{MAX_ARGV_NUMBER, MAX_ARG_LEN, MAX_ENVP_NUMBER, MAX_ENV_LEN};
|
||||||
pub use program_loader::{check_executable_file, load_program_to_vm};
|
pub use program_loader::{check_executable_file, load_program_to_vm};
|
||||||
pub use rlimit::ResourceType;
|
pub use rlimit::ResourceType;
|
||||||
pub use term_status::TermStatus;
|
pub use term_status::TermStatus;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use super::{
|
use super::{
|
||||||
posix_thread::PosixThreadExt,
|
posix_thread::PosixThreadExt,
|
||||||
process_table,
|
process_table,
|
||||||
process_vm::{user_heap::UserHeap, ProcessVm},
|
process_vm::{Heap, InitStackReader, ProcessVm},
|
||||||
rlimit::ResourceLimits,
|
rlimit::ResourceLimits,
|
||||||
signal::{
|
signal::{
|
||||||
constants::SIGCHLD, sig_disposition::SigDispositions, sig_mask::SigMask, signals::Signal,
|
constants::SIGCHLD, sig_disposition::SigDispositions, sig_mask::SigMask, signals::Signal,
|
||||||
@ -501,8 +501,12 @@ impl Process {
|
|||||||
self.process_vm.root_vmar()
|
self.process_vm.root_vmar()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn user_heap(&self) -> &UserHeap {
|
pub fn heap(&self) -> &Heap {
|
||||||
self.process_vm.user_heap()
|
self.process_vm.heap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_stack_reader(&self) -> InitStackReader {
|
||||||
|
self.process_vm.init_stack_reader()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************** File system ****************
|
// ************** File system ****************
|
||||||
|
@ -14,38 +14,48 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The base address of user heap
|
||||||
pub const USER_HEAP_BASE: Vaddr = 0x0000_0000_1000_0000;
|
pub const USER_HEAP_BASE: Vaddr = 0x0000_0000_1000_0000;
|
||||||
pub const USER_HEAP_SIZE_LIMIT: usize = PAGE_SIZE * 1000;
|
/// The max allowed size of user heap
|
||||||
|
pub const USER_HEAP_SIZE_LIMIT: usize = PAGE_SIZE * 1000; // 4MB
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UserHeap {
|
pub struct Heap {
|
||||||
/// the low address of user heap
|
/// The lowest address of the heap
|
||||||
heap_base: Vaddr,
|
base: Vaddr,
|
||||||
/// the max heap size
|
/// The heap size limit
|
||||||
heap_size_limit: usize,
|
limit: usize,
|
||||||
|
/// The current heap highest address
|
||||||
current_heap_end: AtomicUsize,
|
current_heap_end: AtomicUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserHeap {
|
impl Heap {
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
UserHeap {
|
Heap {
|
||||||
heap_base: USER_HEAP_BASE,
|
base: USER_HEAP_BASE,
|
||||||
heap_size_limit: USER_HEAP_SIZE_LIMIT,
|
limit: USER_HEAP_SIZE_LIMIT,
|
||||||
current_heap_end: AtomicUsize::new(USER_HEAP_BASE),
|
current_heap_end: AtomicUsize::new(USER_HEAP_BASE),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&self, root_vmar: &Vmar<Full>) -> Vaddr {
|
/// Inits and maps the heap Vmo
|
||||||
let perms = VmPerms::READ | VmPerms::WRITE;
|
pub(super) fn alloc_and_map_vmo(&self, root_vmar: &Vmar<Full>) -> Result<()> {
|
||||||
let vmo_options = VmoOptions::<Rights>::new(0).flags(VmoFlags::RESIZABLE);
|
let heap_vmo = {
|
||||||
let heap_vmo = vmo_options.alloc().unwrap();
|
let vmo_options = VmoOptions::<Rights>::new(0).flags(VmoFlags::RESIZABLE);
|
||||||
let vmar_map_options = root_vmar
|
vmo_options.alloc()?
|
||||||
.new_map(heap_vmo, perms)
|
};
|
||||||
.unwrap()
|
let vmar_map_options = {
|
||||||
.offset(self.heap_base)
|
let perms = VmPerms::READ | VmPerms::WRITE;
|
||||||
.size(self.heap_size_limit);
|
root_vmar
|
||||||
vmar_map_options.build().unwrap();
|
.new_map(heap_vmo, perms)
|
||||||
self.current_heap_end.load(Ordering::Relaxed)
|
.unwrap()
|
||||||
|
.offset(self.base)
|
||||||
|
.size(self.limit)
|
||||||
|
};
|
||||||
|
vmar_map_options.build()?;
|
||||||
|
|
||||||
|
self.set_uninitialized();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn brk(&self, new_heap_end: Option<Vaddr>) -> Result<Vaddr> {
|
pub fn brk(&self, new_heap_end: Option<Vaddr>) -> Result<Vaddr> {
|
||||||
@ -54,7 +64,7 @@ impl UserHeap {
|
|||||||
match new_heap_end {
|
match new_heap_end {
|
||||||
None => Ok(self.current_heap_end.load(Ordering::Relaxed)),
|
None => Ok(self.current_heap_end.load(Ordering::Relaxed)),
|
||||||
Some(new_heap_end) => {
|
Some(new_heap_end) => {
|
||||||
if new_heap_end > self.heap_base + self.heap_size_limit {
|
if new_heap_end > self.base + self.limit {
|
||||||
return_errno_with_message!(Errno::ENOMEM, "heap size limit was met.");
|
return_errno_with_message!(Errno::ENOMEM, "heap size limit was met.");
|
||||||
}
|
}
|
||||||
let current_heap_end = self.current_heap_end.load(Ordering::Acquire);
|
let current_heap_end = self.current_heap_end.load(Ordering::Acquire);
|
||||||
@ -62,7 +72,7 @@ impl UserHeap {
|
|||||||
// FIXME: should we allow shrink current user heap?
|
// FIXME: should we allow shrink current user heap?
|
||||||
return Ok(current_heap_end);
|
return Ok(current_heap_end);
|
||||||
}
|
}
|
||||||
let new_size = (new_heap_end - self.heap_base).align_up(PAGE_SIZE);
|
let new_size = (new_heap_end - self.base).align_up(PAGE_SIZE);
|
||||||
let heap_mapping = root_vmar.get_vm_mapping(USER_HEAP_BASE)?;
|
let heap_mapping = root_vmar.get_vm_mapping(USER_HEAP_BASE)?;
|
||||||
let heap_vmo = heap_mapping.vmo();
|
let heap_vmo = heap_mapping.vmo();
|
||||||
heap_vmo.resize(new_size)?;
|
heap_vmo.resize(new_size)?;
|
||||||
@ -72,21 +82,17 @@ impl UserHeap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set heap to the default status. i.e., point the heap end to heap base.
|
pub(super) fn set_uninitialized(&self) {
|
||||||
/// This function will we called in execve.
|
self.current_heap_end.store(self.base, Ordering::Relaxed);
|
||||||
pub fn set_default(&self, root_vmar: &Vmar<Full>) {
|
|
||||||
self.current_heap_end
|
|
||||||
.store(self.heap_base, Ordering::Relaxed);
|
|
||||||
self.init(root_vmar);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for UserHeap {
|
impl Clone for Heap {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
let current_heap_end = self.current_heap_end.load(Ordering::Relaxed);
|
let current_heap_end = self.current_heap_end.load(Ordering::Relaxed);
|
||||||
Self {
|
Self {
|
||||||
heap_base: self.heap_base,
|
base: self.base,
|
||||||
heap_size_limit: self.heap_size_limit,
|
limit: self.limit,
|
||||||
current_heap_end: AtomicUsize::new(current_heap_end),
|
current_heap_end: AtomicUsize::new(current_heap_end),
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// This implementation is from occlum.
|
|
||||||
|
|
||||||
/// Auxiliary Vector.
|
/// Auxiliary Vector.
|
||||||
///
|
///
|
||||||
/// # What is Auxiliary Vector?
|
/// # What is Auxiliary Vector?
|
410
kernel/aster-nix/src/process/process_vm/init_stack/mod.rs
Normal file
410
kernel/aster-nix/src/process/process_vm/init_stack/mod.rs
Normal file
@ -0,0 +1,410 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! The init stack for the process.
|
||||||
|
//! The init stack is used to store the `argv` and `envp` and auxiliary vectors.
|
||||||
|
//! We can read `argv` and `envp` of a process from the init stack.
|
||||||
|
//! Usually, the lowest address of init stack is
|
||||||
|
//! the highest address of the user stack of the first thread.
|
||||||
|
//!
|
||||||
|
//! However, the init stack will be mapped to user space
|
||||||
|
//! and the user process can write the content of init stack,
|
||||||
|
//! so the content reading from init stack may not be the same as the process init status.
|
||||||
|
//!
|
||||||
|
|
||||||
|
use core::{
|
||||||
|
mem,
|
||||||
|
sync::atomic::{AtomicUsize, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
|
use align_ext::AlignExt;
|
||||||
|
use aster_frame::vm::{VmIo, MAX_USERSPACE_VADDR};
|
||||||
|
use aster_rights::{Full, Rights};
|
||||||
|
|
||||||
|
use self::aux_vec::{AuxKey, AuxVec};
|
||||||
|
use crate::{
|
||||||
|
prelude::*,
|
||||||
|
util::read_cstring_from_vmar,
|
||||||
|
vm::{perms::VmPerms, vmar::Vmar, vmo::VmoOptions},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod aux_vec;
|
||||||
|
|
||||||
|
/// Set the initial stack size to 8 megabytes, following the default Linux stack size limit.
|
||||||
|
pub const INIT_STACK_SIZE: usize = 8 * 1024 * 1024; // 8 MB
|
||||||
|
|
||||||
|
/// The max number of arguments that can be used to creating a new process.
|
||||||
|
pub const MAX_ARGV_NUMBER: usize = 128;
|
||||||
|
/// The max number of environmental variables that can be used to creating a new process.
|
||||||
|
pub const MAX_ENVP_NUMBER: usize = 128;
|
||||||
|
/// The max length of each argument to create a new process.
|
||||||
|
pub const MAX_ARG_LEN: usize = 2048;
|
||||||
|
/// The max length of each environmental variable (the total length of key-value pair) to create a new process.
|
||||||
|
pub const MAX_ENV_LEN: usize = 128;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Illustration of the virtual memory space containing the processes' init stack:
|
||||||
|
*
|
||||||
|
* (high address)
|
||||||
|
* +---------------------+ <------+ Highest address
|
||||||
|
* | | Random stack paddings
|
||||||
|
* +---------------------+ <------+ The base of stack (stack grows down)
|
||||||
|
* | |
|
||||||
|
* | Null-terminated |
|
||||||
|
* | strings referenced |
|
||||||
|
* | by variables below |
|
||||||
|
* | |
|
||||||
|
* +---------------------+
|
||||||
|
* | AT_NULL |
|
||||||
|
* +---------------------+
|
||||||
|
* | AT_NULL |
|
||||||
|
* +---------------------+
|
||||||
|
* | ... |
|
||||||
|
* +---------------------+
|
||||||
|
* | aux_val[0] |
|
||||||
|
* +---------------------+
|
||||||
|
* | aux_key[0] | <------+ Auxiliary table
|
||||||
|
* +---------------------+
|
||||||
|
* | NULL |
|
||||||
|
* +---------------------+
|
||||||
|
* | ... |
|
||||||
|
* +---------------------+
|
||||||
|
* | char* envp[0] | <------+ Environment variables
|
||||||
|
* +---------------------+
|
||||||
|
* | NULL |
|
||||||
|
* +---------------------+
|
||||||
|
* | char* argv[argc-1] |
|
||||||
|
* +---------------------+
|
||||||
|
* | ... |
|
||||||
|
* +---------------------+
|
||||||
|
* | char* argv[0] |
|
||||||
|
* +---------------------+
|
||||||
|
* | long argc | <------+ Program arguments
|
||||||
|
* +---------------------+
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* +---------------------+
|
||||||
|
* | |
|
||||||
|
* +---------------------+ <------+ User stack default rlimit
|
||||||
|
* (low address)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// The initial portion of the main stack of a process.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct InitStack {
|
||||||
|
/// The initial highest address.
|
||||||
|
/// The stack grows down from this address
|
||||||
|
initial_top: Vaddr,
|
||||||
|
/// The max allowed stack size
|
||||||
|
max_size: usize,
|
||||||
|
/// The current stack pointer.
|
||||||
|
/// Before initialized, `pos` points to the `initial_top`,
|
||||||
|
/// After initialized, `pos` points to the user stack pointer(rsp)
|
||||||
|
/// of the process.
|
||||||
|
pos: Arc<AtomicUsize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InitStack {
|
||||||
|
pub(super) fn new() -> Self {
|
||||||
|
let nr_pages_padding = {
|
||||||
|
let mut random_nr_pages_padding: u8 = 0;
|
||||||
|
getrandom::getrandom(random_nr_pages_padding.as_bytes_mut()).unwrap();
|
||||||
|
random_nr_pages_padding as usize
|
||||||
|
};
|
||||||
|
let initial_top = MAX_USERSPACE_VADDR - PAGE_SIZE * nr_pages_padding;
|
||||||
|
let max_size = INIT_STACK_SIZE;
|
||||||
|
Self {
|
||||||
|
initial_top,
|
||||||
|
max_size,
|
||||||
|
pos: Arc::new(AtomicUsize::new(initial_top)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Init and map the vmo for init stack
|
||||||
|
pub(super) fn alloc_and_map_vmo(&self, root_vmar: &Vmar<Full>) -> Result<()> {
|
||||||
|
let vmo = {
|
||||||
|
let vmo_options = VmoOptions::<Rights>::new(self.max_size);
|
||||||
|
vmo_options.alloc()?
|
||||||
|
};
|
||||||
|
|
||||||
|
let vmar_map_options = {
|
||||||
|
let perms = VmPerms::READ | VmPerms::WRITE;
|
||||||
|
let map_addr = self.initial_top - self.max_size;
|
||||||
|
debug_assert!(map_addr % PAGE_SIZE == 0);
|
||||||
|
root_vmar.new_map(vmo, perms)?.offset(map_addr)
|
||||||
|
};
|
||||||
|
|
||||||
|
vmar_map_options.build()?;
|
||||||
|
|
||||||
|
self.set_uninitialized();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the user stack top(highest address), used to setup rsp.
|
||||||
|
///
|
||||||
|
/// This method should only be called after the stack is initialized.
|
||||||
|
pub fn user_stack_top(&self) -> Vaddr {
|
||||||
|
let stack_top = self.pos();
|
||||||
|
debug_assert!(self.is_initialized());
|
||||||
|
|
||||||
|
stack_top
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn writer<'a>(
|
||||||
|
&self,
|
||||||
|
vmar: &'a Vmar<Full>,
|
||||||
|
argv: Vec<CString>,
|
||||||
|
envp: Vec<CString>,
|
||||||
|
auxvec: AuxVec,
|
||||||
|
) -> InitStackWriter<'a> {
|
||||||
|
// The stack should be written only once.
|
||||||
|
debug_assert!(!self.is_initialized());
|
||||||
|
InitStackWriter {
|
||||||
|
pos: self.pos.clone(),
|
||||||
|
vmar,
|
||||||
|
argv,
|
||||||
|
envp,
|
||||||
|
auxvec,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn reader<'a>(&self, vmar: &'a Vmar<Full>) -> InitStackReader<'a> {
|
||||||
|
// The stack should only be read after initialized
|
||||||
|
debug_assert!(self.is_initialized());
|
||||||
|
InitStackReader {
|
||||||
|
base: self.pos(),
|
||||||
|
vmar,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_initialized(&self) -> bool {
|
||||||
|
self.pos() != self.initial_top
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_uninitialized(&self) {
|
||||||
|
self.pos.store(self.initial_top, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pos(&self) -> Vaddr {
|
||||||
|
self.pos.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A writer to initialize the content of an `InitStack`.
|
||||||
|
pub struct InitStackWriter<'a> {
|
||||||
|
pos: Arc<AtomicUsize>,
|
||||||
|
vmar: &'a Vmar<Full>,
|
||||||
|
argv: Vec<CString>,
|
||||||
|
envp: Vec<CString>,
|
||||||
|
auxvec: AuxVec,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> InitStackWriter<'a> {
|
||||||
|
pub fn write(mut self) -> Result<()> {
|
||||||
|
// FIXME: Some OSes may put the first page of excutable file here
|
||||||
|
// for interpreting elf headers.
|
||||||
|
|
||||||
|
let argc = self.argv.len() as u64;
|
||||||
|
|
||||||
|
// Write envp string
|
||||||
|
let envp_pointers = self.write_envp_strings()?;
|
||||||
|
// Write argv string
|
||||||
|
let argv_pointers = self.write_argv_strings()?;
|
||||||
|
// Generate random values for auxvec
|
||||||
|
let random_value_pointer = {
|
||||||
|
let random_value = generate_random_for_aux_vec();
|
||||||
|
self.write_bytes(&random_value)?
|
||||||
|
};
|
||||||
|
self.auxvec.set(AuxKey::AT_RANDOM, random_value_pointer)?;
|
||||||
|
|
||||||
|
self.adjust_stack_alignment(&envp_pointers, &argv_pointers)?;
|
||||||
|
self.write_aux_vec()?;
|
||||||
|
self.write_envp_pointers(envp_pointers)?;
|
||||||
|
self.write_argv_pointers(argv_pointers)?;
|
||||||
|
|
||||||
|
// write argc
|
||||||
|
self.write_u64(argc)?;
|
||||||
|
|
||||||
|
// Ensure stack top is 16-bytes aligned
|
||||||
|
debug_assert_eq!(self.pos() & !0xf, self.pos());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_envp_strings(&self) -> Result<Vec<u64>> {
|
||||||
|
let mut envp_pointers = Vec::with_capacity(self.envp.len());
|
||||||
|
for envp in self.envp.iter() {
|
||||||
|
let pointer = self.write_cstring(envp)?;
|
||||||
|
envp_pointers.push(pointer);
|
||||||
|
}
|
||||||
|
Ok(envp_pointers)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_argv_strings(&self) -> Result<Vec<u64>> {
|
||||||
|
let mut argv_pointers = Vec::with_capacity(self.argv.len());
|
||||||
|
for argv in self.argv.iter().rev() {
|
||||||
|
let pointer = self.write_cstring(argv)?;
|
||||||
|
debug!("argv address = 0x{:x}", pointer);
|
||||||
|
argv_pointers.push(pointer);
|
||||||
|
}
|
||||||
|
argv_pointers.reverse();
|
||||||
|
Ok(argv_pointers)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Libc ABI requires 16-byte alignment of the stack entrypoint.
|
||||||
|
/// Current postion of the stack is 8-byte aligned already, insert 8 byte
|
||||||
|
/// to meet the requirement if necessary.
|
||||||
|
fn adjust_stack_alignment(&self, envp_pointers: &[u64], argv_pointers: &[u64]) -> Result<()> {
|
||||||
|
// Ensure 8-byte alignment
|
||||||
|
self.write_u64(0)?;
|
||||||
|
let auxvec_size = (self.auxvec.table().len() + 1) * (mem::size_of::<u64>() * 2);
|
||||||
|
let envp_pointers_size = (envp_pointers.len() + 1) * mem::size_of::<u64>();
|
||||||
|
let argv_pointers_size = (argv_pointers.len() + 1) * mem::size_of::<u64>();
|
||||||
|
let argc_size = mem::size_of::<u64>();
|
||||||
|
let to_write_size = auxvec_size + envp_pointers_size + argv_pointers_size + argc_size;
|
||||||
|
if (self.pos() - to_write_size) % 16 != 0 {
|
||||||
|
self.write_u64(0)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_aux_vec(&self) -> Result<()> {
|
||||||
|
// Write NULL auxilary
|
||||||
|
self.write_u64(0)?;
|
||||||
|
self.write_u64(AuxKey::AT_NULL as u64)?;
|
||||||
|
// Write Auxiliary vectors
|
||||||
|
let aux_vec: Vec<_> = self
|
||||||
|
.auxvec
|
||||||
|
.table()
|
||||||
|
.iter()
|
||||||
|
.map(|(aux_key, aux_value)| (*aux_key, *aux_value))
|
||||||
|
.collect();
|
||||||
|
for (aux_key, aux_value) in aux_vec.iter() {
|
||||||
|
self.write_u64(*aux_value)?;
|
||||||
|
self.write_u64(*aux_key as u64)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_envp_pointers(&self, mut envp_pointers: Vec<u64>) -> Result<()> {
|
||||||
|
// write NULL pointer
|
||||||
|
self.write_u64(0)?;
|
||||||
|
// write envp pointers
|
||||||
|
envp_pointers.reverse();
|
||||||
|
for envp_pointer in envp_pointers {
|
||||||
|
self.write_u64(envp_pointer)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_argv_pointers(&self, mut argv_pointers: Vec<u64>) -> Result<()> {
|
||||||
|
// write 0
|
||||||
|
self.write_u64(0)?;
|
||||||
|
// write argv pointers
|
||||||
|
argv_pointers.reverse();
|
||||||
|
for argv_pointer in argv_pointers {
|
||||||
|
self.write_u64(argv_pointer)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes u64 to the stack.
|
||||||
|
/// Returns the writing address
|
||||||
|
fn write_u64(&self, val: u64) -> Result<u64> {
|
||||||
|
let start_address = (self.pos() - 8).align_down(8);
|
||||||
|
self.pos.store(start_address, Ordering::Relaxed);
|
||||||
|
self.vmar.write_val(start_address, &val)?;
|
||||||
|
Ok(self.pos() as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes a CString including the ending null byte to the stack.
|
||||||
|
/// Returns the writing address
|
||||||
|
fn write_cstring(&self, val: &CString) -> Result<u64> {
|
||||||
|
let bytes = val.as_bytes_with_nul();
|
||||||
|
self.write_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes u64 to the stack.
|
||||||
|
/// Returns the writing address.
|
||||||
|
fn write_bytes(&self, bytes: &[u8]) -> Result<u64> {
|
||||||
|
let len = bytes.len();
|
||||||
|
self.pos.fetch_sub(len, Ordering::Relaxed);
|
||||||
|
let pos = self.pos();
|
||||||
|
self.vmar.write_bytes(pos, bytes)?;
|
||||||
|
Ok(pos as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pos(&self) -> Vaddr {
|
||||||
|
self.pos.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_random_for_aux_vec() -> [u8; 16] {
|
||||||
|
let mut rand_val = [0; 16];
|
||||||
|
getrandom::getrandom(&mut rand_val).unwrap();
|
||||||
|
rand_val
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A reader to parse the content of an `InitStack`.
|
||||||
|
pub struct InitStackReader<'a> {
|
||||||
|
base: Vaddr,
|
||||||
|
vmar: &'a Vmar<Full>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> InitStackReader<'a> {
|
||||||
|
/// Read argc from the process init stack
|
||||||
|
pub fn argc(&self) -> Result<u64> {
|
||||||
|
let stack_base = self.user_stack_top();
|
||||||
|
Ok(self.vmar.read_val(stack_base)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read argv from the process init stack
|
||||||
|
pub fn argv(&self) -> Result<Vec<CString>> {
|
||||||
|
let argc = self.argc()? as usize;
|
||||||
|
// base = stack bottom + the size of argc
|
||||||
|
let base = self.user_stack_top() + 8;
|
||||||
|
|
||||||
|
let mut argv = Vec::with_capacity(argc);
|
||||||
|
for i in 0..argc {
|
||||||
|
let arg_ptr = {
|
||||||
|
let offset = base + i * 8;
|
||||||
|
self.vmar.read_val::<Vaddr>(offset)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let arg = read_cstring_from_vmar(self.vmar, arg_ptr, MAX_ARG_LEN)?;
|
||||||
|
argv.push(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(argv)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read envp from the process
|
||||||
|
pub fn envp(&self) -> Result<Vec<CString>> {
|
||||||
|
let argc = self.argc()? as usize;
|
||||||
|
// base = stack bottom
|
||||||
|
// + the size of argc(8)
|
||||||
|
// + the size of arg pointer(8) * the number of arg(argc)
|
||||||
|
// + the size of null pointer(8)
|
||||||
|
let base = self.user_stack_top() + 8 + 8 * argc + 8;
|
||||||
|
|
||||||
|
let mut envp = Vec::new();
|
||||||
|
for i in 0..MAX_ENVP_NUMBER {
|
||||||
|
let envp_ptr = {
|
||||||
|
let offset = base + i * 8;
|
||||||
|
self.vmar.read_val::<Vaddr>(offset)?
|
||||||
|
};
|
||||||
|
|
||||||
|
if envp_ptr == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let env = read_cstring_from_vmar(self.vmar, envp_ptr, MAX_ENV_LEN)?;
|
||||||
|
envp.push(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(envp)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn user_stack_top(&self) -> Vaddr {
|
||||||
|
self.base
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,29 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
//! This module defines the UserVm of a process.
|
//! This module defines struct `ProcessVm`
|
||||||
//! The UserSpace of a process only contains the virtual-physical memory mapping.
|
//! to represent the layout of user space process virtual memory.
|
||||||
//! But we cannot know which vaddr is user heap, which vaddr is mmap areas.
|
//!
|
||||||
//! So we define a UserVm struct to store such infomation.
|
//! The `ProcessVm` struct contains `Vmar`,
|
||||||
//! Briefly, it contains the exact usage of each segment of virtual spaces.
|
//! which stores all existing memory mappings.
|
||||||
|
//! The `Vm` also contains
|
||||||
|
//! the basic info of process level vm segments,
|
||||||
|
//! like init stack and heap.
|
||||||
|
|
||||||
pub mod user_heap;
|
mod heap;
|
||||||
|
mod init_stack;
|
||||||
|
|
||||||
use aster_rights::Full;
|
use aster_rights::Full;
|
||||||
use user_heap::UserHeap;
|
pub use heap::Heap;
|
||||||
|
|
||||||
use crate::vm::vmar::Vmar;
|
pub use self::{
|
||||||
|
heap::USER_HEAP_SIZE_LIMIT,
|
||||||
|
init_stack::{
|
||||||
|
aux_vec::{AuxKey, AuxVec},
|
||||||
|
InitStack, InitStackReader, InitStackWriter, INIT_STACK_SIZE, MAX_ARGV_NUMBER, MAX_ARG_LEN,
|
||||||
|
MAX_ENVP_NUMBER, MAX_ENV_LEN,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use crate::{prelude::*, vm::vmar::Vmar};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The user's virtual memory space layout looks like below.
|
* The user's virtual memory space layout looks like below.
|
||||||
@ -49,51 +61,77 @@ use crate::vm::vmar::Vmar;
|
|||||||
* (low address)
|
* (low address)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// The virtual space usage.
|
// The process user space virtual memory
|
||||||
/// This struct is used to control brk and mmap now.
|
|
||||||
pub struct ProcessVm {
|
pub struct ProcessVm {
|
||||||
user_heap: UserHeap,
|
|
||||||
root_vmar: Vmar<Full>,
|
root_vmar: Vmar<Full>,
|
||||||
|
init_stack: InitStack,
|
||||||
|
heap: Heap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for ProcessVm {
|
impl Clone for ProcessVm {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
root_vmar: self.root_vmar.dup().unwrap(),
|
root_vmar: self.root_vmar.dup().unwrap(),
|
||||||
user_heap: self.user_heap.clone(),
|
init_stack: self.init_stack.clone(),
|
||||||
|
heap: self.heap.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessVm {
|
impl ProcessVm {
|
||||||
|
/// Allocates a new `ProcessVm`
|
||||||
pub fn alloc() -> Self {
|
pub fn alloc() -> Self {
|
||||||
let root_vmar = Vmar::<Full>::new_root();
|
let root_vmar = Vmar::<Full>::new_root();
|
||||||
let user_heap = UserHeap::new();
|
let init_stack = InitStack::new();
|
||||||
user_heap.init(&root_vmar);
|
init_stack.alloc_and_map_vmo(&root_vmar).unwrap();
|
||||||
ProcessVm {
|
let heap = Heap::new();
|
||||||
user_heap,
|
heap.alloc_and_map_vmo(&root_vmar).unwrap();
|
||||||
root_vmar,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(user_heap: UserHeap, root_vmar: Vmar<Full>) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
user_heap,
|
|
||||||
root_vmar,
|
root_vmar,
|
||||||
|
heap,
|
||||||
|
init_stack,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn user_heap(&self) -> &UserHeap {
|
/// Forks a `ProcessVm` from `other`.
|
||||||
&self.user_heap
|
///
|
||||||
|
/// The returned `ProcessVm` will have a forked `Vmar`.
|
||||||
|
pub fn fork_from(other: &ProcessVm) -> Result<Self> {
|
||||||
|
let root_vmar = Vmar::<Full>::fork_from(&other.root_vmar)?;
|
||||||
|
Ok(Self {
|
||||||
|
root_vmar,
|
||||||
|
heap: other.heap.clone(),
|
||||||
|
init_stack: other.init_stack.clone(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn root_vmar(&self) -> &Vmar<Full> {
|
pub fn root_vmar(&self) -> &Vmar<Full> {
|
||||||
&self.root_vmar
|
&self.root_vmar
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set user vm to the init status
|
/// Returns a reader for reading contents from
|
||||||
pub fn clear(&self) {
|
/// the `InitStack`.
|
||||||
|
pub fn init_stack_reader(&self) -> InitStackReader {
|
||||||
|
self.init_stack.reader(&self.root_vmar)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn init_stack_writer(
|
||||||
|
&self,
|
||||||
|
argv: Vec<CString>,
|
||||||
|
envp: Vec<CString>,
|
||||||
|
aux_vec: AuxVec,
|
||||||
|
) -> InitStackWriter {
|
||||||
|
self.init_stack.writer(&self.root_vmar, argv, envp, aux_vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn heap(&self) -> &Heap {
|
||||||
|
&self.heap
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears existing mappings and then maps stack and heap vmo.
|
||||||
|
pub(super) fn clear_and_map(&self) {
|
||||||
self.root_vmar.clear().unwrap();
|
self.root_vmar.clear().unwrap();
|
||||||
self.user_heap.set_default(&self.root_vmar);
|
self.init_stack.alloc_and_map_vmo(&self.root_vmar).unwrap();
|
||||||
|
self.heap.alloc_and_map_vmo(&self.root_vmar).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,363 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
//! This module defines the process initial stack.
|
|
||||||
//! The process initial stack, contains arguments, environmental variables and auxiliary vectors
|
|
||||||
//! The data layout of init stack can be seen in Figure 3.9 in <https://uclibc.org/docs/psABI-x86_64.pdf>
|
|
||||||
|
|
||||||
use core::mem;
|
|
||||||
|
|
||||||
use align_ext::AlignExt;
|
|
||||||
use aster_frame::vm::{VmIo, VmPerm, MAX_USERSPACE_VADDR};
|
|
||||||
use aster_rights::{Full, Rights};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
aux_vec::{AuxKey, AuxVec},
|
|
||||||
elf_file::Elf,
|
|
||||||
load_elf::LdsoLoadInfo,
|
|
||||||
};
|
|
||||||
use crate::{
|
|
||||||
prelude::*,
|
|
||||||
vm::{perms::VmPerms, vmar::Vmar, vmo::VmoOptions},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Set the initial stack size to 8 megabytes, following the default Linux stack size limit.
|
|
||||||
pub const INIT_STACK_SIZE: usize = 8 * 1024 * 1024; // 8 MB
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Illustration of the virtual memory space containing the processes' init stack:
|
|
||||||
*
|
|
||||||
* (high address)
|
|
||||||
* +---------------------+ <------+ Highest address
|
|
||||||
* | | Random stack paddings
|
|
||||||
* +---------------------+ <------+ The base of stack (stack grows down)
|
|
||||||
* | |
|
|
||||||
* | Null-terminated |
|
|
||||||
* | strings referenced |
|
|
||||||
* | by variables below |
|
|
||||||
* | |
|
|
||||||
* +---------------------+
|
|
||||||
* | AT_NULL |
|
|
||||||
* +---------------------+
|
|
||||||
* | AT_NULL |
|
|
||||||
* +---------------------+
|
|
||||||
* | ... |
|
|
||||||
* +---------------------+
|
|
||||||
* | aux_val[0] |
|
|
||||||
* +---------------------+
|
|
||||||
* | aux_key[0] | <------+ Auxiliary table
|
|
||||||
* +---------------------+
|
|
||||||
* | NULL |
|
|
||||||
* +---------------------+
|
|
||||||
* | ... |
|
|
||||||
* +---------------------+
|
|
||||||
* | char* envp[0] | <------+ Environment variables
|
|
||||||
* +---------------------+
|
|
||||||
* | NULL |
|
|
||||||
* +---------------------+
|
|
||||||
* | char* argv[argc-1] |
|
|
||||||
* +---------------------+
|
|
||||||
* | ... |
|
|
||||||
* +---------------------+
|
|
||||||
* | char* argv[0] |
|
|
||||||
* +---------------------+
|
|
||||||
* | long argc | <------+ Program arguments
|
|
||||||
* +---------------------+
|
|
||||||
* | |
|
|
||||||
* | |
|
|
||||||
* +---------------------+
|
|
||||||
* | |
|
|
||||||
* +---------------------+ <------+ User stack default rlimit
|
|
||||||
* (low address)
|
|
||||||
*/
|
|
||||||
pub struct InitStack {
|
|
||||||
/// The high address of init stack
|
|
||||||
init_stack_top: Vaddr,
|
|
||||||
init_stack_size: usize,
|
|
||||||
pos: usize,
|
|
||||||
/// Command line args
|
|
||||||
argv: Vec<CString>,
|
|
||||||
/// Environmental variables
|
|
||||||
envp: Vec<CString>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InitStack {
|
|
||||||
/// initialize user stack on base addr
|
|
||||||
pub fn new(
|
|
||||||
init_stack_top: Vaddr,
|
|
||||||
init_stack_size: usize,
|
|
||||||
argv: Vec<CString>,
|
|
||||||
envp: Vec<CString>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
init_stack_top,
|
|
||||||
init_stack_size,
|
|
||||||
pos: init_stack_top,
|
|
||||||
argv,
|
|
||||||
envp,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_default_config(argv: Vec<CString>, envp: Vec<CString>) -> Self {
|
|
||||||
let nr_pages_padding = {
|
|
||||||
let mut random_nr_pages_padding: u8 = 0;
|
|
||||||
getrandom::getrandom(random_nr_pages_padding.as_bytes_mut()).unwrap();
|
|
||||||
random_nr_pages_padding as usize
|
|
||||||
};
|
|
||||||
let init_stack_top = MAX_USERSPACE_VADDR - PAGE_SIZE * nr_pages_padding;
|
|
||||||
let init_stack_size = INIT_STACK_SIZE;
|
|
||||||
InitStack::new(init_stack_top, init_stack_size, argv, envp)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// the user stack top(high address), used to setup rsp
|
|
||||||
pub fn user_stack_top(&self) -> Vaddr {
|
|
||||||
let stack_top = self.pos;
|
|
||||||
// ensure stack top is 16-bytes aligned
|
|
||||||
debug_assert!(stack_top & !0xf == stack_top);
|
|
||||||
stack_top
|
|
||||||
}
|
|
||||||
|
|
||||||
/// the user stack bottom(low address)
|
|
||||||
const fn user_stack_bottom(&self) -> Vaddr {
|
|
||||||
self.init_stack_top - self.init_stack_size
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(
|
|
||||||
&mut self,
|
|
||||||
root_vmar: &Vmar<Full>,
|
|
||||||
elf: &Elf,
|
|
||||||
ldso_load_info: &Option<LdsoLoadInfo>,
|
|
||||||
aux_vec: &mut AuxVec,
|
|
||||||
) -> Result<()> {
|
|
||||||
self.map_and_zeroed(root_vmar)?;
|
|
||||||
self.write_stack_content(root_vmar, elf, ldso_load_info, aux_vec)?;
|
|
||||||
self.debug_print_stack_content(root_vmar);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn map_and_zeroed(&self, root_vmar: &Vmar<Full>) -> Result<()> {
|
|
||||||
let vmo_options = VmoOptions::<Rights>::new(self.init_stack_size);
|
|
||||||
let vmo = vmo_options.alloc()?;
|
|
||||||
vmo.clear(0..vmo.size())?;
|
|
||||||
let perms = VmPerms::READ | VmPerms::WRITE;
|
|
||||||
let vmar_map_options = root_vmar
|
|
||||||
.new_map(vmo, perms)?
|
|
||||||
.offset(self.user_stack_bottom());
|
|
||||||
vmar_map_options.build().unwrap();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Libc ABI requires 16-byte alignment of the stack entrypoint.
|
|
||||||
/// Current postion of the stack is 8-byte aligned already, insert 8 byte
|
|
||||||
/// to meet the requirement if necessary.
|
|
||||||
fn adjust_stack_alignment(
|
|
||||||
&mut self,
|
|
||||||
root_vmar: &Vmar<Full>,
|
|
||||||
envp_pointers: &[u64],
|
|
||||||
argv_pointers: &[u64],
|
|
||||||
aux_vec: &AuxVec,
|
|
||||||
) -> Result<()> {
|
|
||||||
// ensure 8-byte alignment
|
|
||||||
self.write_u64(0, root_vmar)?;
|
|
||||||
let auxvec_size = (aux_vec.table().len() + 1) * (mem::size_of::<u64>() * 2);
|
|
||||||
let envp_pointers_size = (envp_pointers.len() + 1) * mem::size_of::<u64>();
|
|
||||||
let argv_pointers_size = (argv_pointers.len() + 1) * mem::size_of::<u64>();
|
|
||||||
let argc_size = mem::size_of::<u64>();
|
|
||||||
let to_write_size = auxvec_size + envp_pointers_size + argv_pointers_size + argc_size;
|
|
||||||
if (self.pos - to_write_size) % 16 != 0 {
|
|
||||||
self.write_u64(0, root_vmar)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_stack_content(
|
|
||||||
&mut self,
|
|
||||||
root_vmar: &Vmar<Full>,
|
|
||||||
elf: &Elf,
|
|
||||||
ldso_load_info: &Option<LdsoLoadInfo>,
|
|
||||||
aux_vec: &mut AuxVec,
|
|
||||||
) -> Result<()> {
|
|
||||||
// FIXME: Some OSes may put the first page of excutable file here
|
|
||||||
// for interpreting elf headers.
|
|
||||||
|
|
||||||
// write envp string
|
|
||||||
let envp_pointers = self.write_envp_strings(root_vmar)?;
|
|
||||||
// write argv string
|
|
||||||
let argv_pointers = self.write_argv_strings(root_vmar)?;
|
|
||||||
// write random value
|
|
||||||
let random_value = generate_random_for_aux_vec();
|
|
||||||
let random_value_pointer = self.write_bytes(&random_value, root_vmar)?;
|
|
||||||
aux_vec.set(AuxKey::AT_RANDOM, random_value_pointer)?;
|
|
||||||
if let Some(ldso_load_info) = ldso_load_info {
|
|
||||||
let ldso_base = ldso_load_info.base_addr();
|
|
||||||
aux_vec.set(AuxKey::AT_BASE, ldso_base as u64)?;
|
|
||||||
}
|
|
||||||
self.adjust_stack_alignment(root_vmar, &envp_pointers, &argv_pointers, aux_vec)?;
|
|
||||||
self.write_aux_vec(root_vmar, aux_vec)?;
|
|
||||||
self.write_envp_pointers(root_vmar, envp_pointers)?;
|
|
||||||
self.write_argv_pointers(root_vmar, argv_pointers)?;
|
|
||||||
// write argc
|
|
||||||
let argc = self.argc();
|
|
||||||
self.write_u64(argc, root_vmar)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_envp_strings(&mut self, root_vmar: &Vmar<Full>) -> Result<Vec<u64>> {
|
|
||||||
let envp = self.envp.to_vec();
|
|
||||||
let mut envp_pointers = Vec::with_capacity(envp.len());
|
|
||||||
for envp in envp.iter() {
|
|
||||||
let pointer = self.write_cstring(envp, root_vmar)?;
|
|
||||||
envp_pointers.push(pointer);
|
|
||||||
}
|
|
||||||
Ok(envp_pointers)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_argv_strings(&mut self, root_vmar: &Vmar<Full>) -> Result<Vec<u64>> {
|
|
||||||
let argv = self.argv.to_vec();
|
|
||||||
let mut argv_pointers = Vec::with_capacity(argv.len());
|
|
||||||
for argv in argv.iter().rev() {
|
|
||||||
let pointer = self.write_cstring(argv, root_vmar)?;
|
|
||||||
debug!("argv address = 0x{:x}", pointer);
|
|
||||||
argv_pointers.push(pointer);
|
|
||||||
}
|
|
||||||
argv_pointers.reverse();
|
|
||||||
Ok(argv_pointers)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_aux_vec(&mut self, root_vmar: &Vmar<Full>, aux_vec: &AuxVec) -> Result<()> {
|
|
||||||
// Write NULL auxilary
|
|
||||||
self.write_u64(0, root_vmar)?;
|
|
||||||
self.write_u64(AuxKey::AT_NULL as u64, root_vmar)?;
|
|
||||||
// Write Auxiliary vectors
|
|
||||||
let aux_vec: Vec<_> = aux_vec
|
|
||||||
.table()
|
|
||||||
.iter()
|
|
||||||
.map(|(aux_key, aux_value)| (*aux_key, *aux_value))
|
|
||||||
.collect();
|
|
||||||
for (aux_key, aux_value) in aux_vec.iter() {
|
|
||||||
self.write_u64(*aux_value, root_vmar)?;
|
|
||||||
self.write_u64(*aux_key as u64, root_vmar)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_envp_pointers(
|
|
||||||
&mut self,
|
|
||||||
root_vmar: &Vmar<Full>,
|
|
||||||
mut envp_pointers: Vec<u64>,
|
|
||||||
) -> Result<()> {
|
|
||||||
// write NULL pointer
|
|
||||||
self.write_u64(0, root_vmar)?;
|
|
||||||
// write envp pointers
|
|
||||||
envp_pointers.reverse();
|
|
||||||
for envp_pointer in envp_pointers {
|
|
||||||
self.write_u64(envp_pointer, root_vmar)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_argv_pointers(
|
|
||||||
&mut self,
|
|
||||||
root_vmar: &Vmar<Full>,
|
|
||||||
mut argv_pointers: Vec<u64>,
|
|
||||||
) -> Result<()> {
|
|
||||||
// write 0
|
|
||||||
self.write_u64(0, root_vmar)?;
|
|
||||||
// write argv pointers
|
|
||||||
argv_pointers.reverse();
|
|
||||||
for argv_pointer in argv_pointers {
|
|
||||||
self.write_u64(argv_pointer, root_vmar)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Command line argument counter
|
|
||||||
pub fn argc(&self) -> u64 {
|
|
||||||
self.argv.len() as u64
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Command linke argument start address
|
|
||||||
pub fn argv(&self) -> u64 {
|
|
||||||
self.user_stack_top() as u64 + 8
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Environmental variables counter
|
|
||||||
pub fn envc(&self) -> u64 {
|
|
||||||
self.envp.len() as u64
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Environmental variables pointers
|
|
||||||
pub fn envp(&self) -> u64 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// returns the top address of init stack.
|
|
||||||
/// It should points to a fixed address.
|
|
||||||
pub const fn init_stack_top(&self) -> Vaddr {
|
|
||||||
self.init_stack_top
|
|
||||||
}
|
|
||||||
|
|
||||||
/// returns the u64 start address
|
|
||||||
fn write_u64(&mut self, val: u64, root_vmar: &Vmar<Full>) -> Result<u64> {
|
|
||||||
let start_address = (self.pos - 8).align_down(8);
|
|
||||||
self.pos = start_address;
|
|
||||||
root_vmar.write_val(start_address, &val)?;
|
|
||||||
Ok(self.pos as u64)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_bytes(&mut self, bytes: &[u8], root_vmar: &Vmar<Full>) -> Result<u64> {
|
|
||||||
let len = bytes.len();
|
|
||||||
self.pos -= len;
|
|
||||||
root_vmar.write_bytes(self.pos, bytes)?;
|
|
||||||
Ok(self.pos as u64)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// returns the string start address
|
|
||||||
/// cstring will with end null byte.
|
|
||||||
fn write_cstring(&mut self, val: &CString, root_vmar: &Vmar<Full>) -> Result<u64> {
|
|
||||||
let bytes = val.as_bytes_with_nul();
|
|
||||||
self.write_bytes(bytes, root_vmar)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn perm() -> VmPerm {
|
|
||||||
VmPerm::RWU
|
|
||||||
}
|
|
||||||
|
|
||||||
fn debug_print_stack_content(&self, root_vmar: &Vmar<Full>) {
|
|
||||||
debug!("print stack content:");
|
|
||||||
let stack_top = self.user_stack_top();
|
|
||||||
let argc = root_vmar.read_val::<u64>(stack_top).unwrap();
|
|
||||||
debug!("argc = {}", argc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init_aux_vec(elf: &Elf, elf_map_addr: Vaddr, vdso_text_base: Vaddr) -> Result<AuxVec> {
|
|
||||||
let mut aux_vec = AuxVec::new();
|
|
||||||
aux_vec.set(AuxKey::AT_PAGESZ, PAGE_SIZE as _)?;
|
|
||||||
let ph_addr = if elf.is_shared_object() {
|
|
||||||
elf.ph_addr()? + elf_map_addr
|
|
||||||
} else {
|
|
||||||
elf.ph_addr()?
|
|
||||||
};
|
|
||||||
aux_vec.set(AuxKey::AT_PHDR, ph_addr as u64)?;
|
|
||||||
aux_vec.set(AuxKey::AT_PHNUM, elf.ph_count() as u64)?;
|
|
||||||
aux_vec.set(AuxKey::AT_PHENT, elf.ph_ent() as u64)?;
|
|
||||||
let elf_entry = if elf.is_shared_object() {
|
|
||||||
let base_load_offset = elf.base_load_address_offset();
|
|
||||||
elf.entry_point() + elf_map_addr - base_load_offset as usize
|
|
||||||
} else {
|
|
||||||
elf.entry_point()
|
|
||||||
};
|
|
||||||
aux_vec.set(AuxKey::AT_ENTRY, elf_entry as u64)?;
|
|
||||||
aux_vec.set(AuxKey::AT_SYSINFO_EHDR, vdso_text_base as u64)?;
|
|
||||||
Ok(aux_vec)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// generate random [u8; 16].
|
|
||||||
/// FIXME: generate really random value. Now only return array with fixed values.
|
|
||||||
fn generate_random_for_aux_vec() -> [u8; 16] {
|
|
||||||
let mut rand_val = [0; 16];
|
|
||||||
for i in 0..16u8 {
|
|
||||||
rand_val[i as usize] = 0xff - i;
|
|
||||||
}
|
|
||||||
rand_val
|
|
||||||
}
|
|
@ -20,10 +20,10 @@ use crate::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
process::{
|
process::{
|
||||||
do_exit_group,
|
do_exit_group,
|
||||||
process_vm::ProcessVm,
|
process_vm::{AuxKey, AuxVec, ProcessVm},
|
||||||
program_loader::elf::init_stack::{init_aux_vec, InitStack},
|
|
||||||
TermStatus,
|
TermStatus,
|
||||||
},
|
},
|
||||||
|
vdso::vdso_vmo,
|
||||||
vm::{
|
vm::{
|
||||||
perms::VmPerms,
|
perms::VmPerms,
|
||||||
vmar::Vmar,
|
vmar::Vmar,
|
||||||
@ -31,10 +31,10 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// load elf to the root vmar. this function will
|
/// Loads elf to the process vm.
|
||||||
/// 1. read the vaddr of each segment to get all elf pages.
|
///
|
||||||
/// 2. create a vmo for each elf segment, create a pager for each segment. Then map the vmo to the root vmar.
|
/// This function will map elf segments and
|
||||||
/// 3. write proper content to the init stack.
|
/// initialize process init stack.
|
||||||
pub fn load_elf_to_vm(
|
pub fn load_elf_to_vm(
|
||||||
process_vm: &ProcessVm,
|
process_vm: &ProcessVm,
|
||||||
file_header: &[u8],
|
file_header: &[u8],
|
||||||
@ -42,31 +42,48 @@ pub fn load_elf_to_vm(
|
|||||||
fs_resolver: &FsResolver,
|
fs_resolver: &FsResolver,
|
||||||
argv: Vec<CString>,
|
argv: Vec<CString>,
|
||||||
envp: Vec<CString>,
|
envp: Vec<CString>,
|
||||||
vdso_text_base: Vaddr,
|
|
||||||
) -> Result<ElfLoadInfo> {
|
) -> Result<ElfLoadInfo> {
|
||||||
let elf = Elf::parse_elf(file_header)?;
|
let parsed_elf = Elf::parse_elf(file_header)?;
|
||||||
|
|
||||||
let ldso = if elf.is_shared_object() {
|
let ldso = if parsed_elf.is_shared_object() {
|
||||||
Some(lookup_and_parse_ldso(&elf, file_header, fs_resolver)?)
|
Some(lookup_and_parse_ldso(
|
||||||
|
&parsed_elf,
|
||||||
|
file_header,
|
||||||
|
fs_resolver,
|
||||||
|
)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
match init_and_map_vmos(
|
match init_and_map_vmos(process_vm, ldso, &parsed_elf, &elf_file) {
|
||||||
process_vm,
|
Ok((entry_point, mut aux_vec)) => {
|
||||||
ldso,
|
// Map and set vdso entry.
|
||||||
&elf,
|
// Since vdso does not require being mapped to any specific address,
|
||||||
&elf_file,
|
// vdso is mapped after the elf file, heap and stack are mapped.
|
||||||
argv,
|
if let Some(vdso_text_base) = map_vdso_to_vm(process_vm) {
|
||||||
envp,
|
aux_vec
|
||||||
vdso_text_base,
|
.set(AuxKey::AT_SYSINFO_EHDR, vdso_text_base as u64)
|
||||||
) {
|
.unwrap();
|
||||||
Ok(elf_load_info) => Ok(elf_load_info),
|
}
|
||||||
Err(e) => {
|
|
||||||
// Since the process_vm is cleared, the process cannot return to user space again,
|
|
||||||
// so exit_group is called here.
|
|
||||||
|
|
||||||
// FIXME: if `current` macro is used when creating the init process,
|
let init_stack_writer = process_vm.init_stack_writer(argv, envp, aux_vec);
|
||||||
|
init_stack_writer.write().unwrap();
|
||||||
|
|
||||||
|
let user_stack_top = process_vm.init_stack_reader().user_stack_top();
|
||||||
|
Ok(ElfLoadInfo {
|
||||||
|
entry_point,
|
||||||
|
user_stack_top,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
// Since the process_vm is in invalid state,
|
||||||
|
// the process cannot return to user space again,
|
||||||
|
// so `Vmar::clear` and `do_exit_group` are called here.
|
||||||
|
// FIXME: sending a fault signal is an alternative approach.
|
||||||
|
process_vm.root_vmar().clear().unwrap();
|
||||||
|
|
||||||
|
// FIXME: `current` macro will be used in `do_exit_group`.
|
||||||
|
// if the macro is used when creating the init process,
|
||||||
// the macro will panic. This corner case should be handled later.
|
// the macro will panic. This corner case should be handled later.
|
||||||
// FIXME: how to set the correct exit status?
|
// FIXME: how to set the correct exit status?
|
||||||
do_exit_group(TermStatus::Exited(1));
|
do_exit_group(TermStatus::Exited(1));
|
||||||
@ -105,12 +122,9 @@ fn load_ldso(root_vmar: &Vmar<Full>, ldso_file: &Dentry, ldso_elf: &Elf) -> Resu
|
|||||||
fn init_and_map_vmos(
|
fn init_and_map_vmos(
|
||||||
process_vm: &ProcessVm,
|
process_vm: &ProcessVm,
|
||||||
ldso: Option<(Arc<Dentry>, Elf)>,
|
ldso: Option<(Arc<Dentry>, Elf)>,
|
||||||
elf: &Elf,
|
parsed_elf: &Elf,
|
||||||
elf_file: &Dentry,
|
elf_file: &Dentry,
|
||||||
argv: Vec<CString>,
|
) -> Result<(Vaddr, AuxVec)> {
|
||||||
envp: Vec<CString>,
|
|
||||||
vdso_text_base: Vaddr,
|
|
||||||
) -> Result<ElfLoadInfo> {
|
|
||||||
let root_vmar = process_vm.root_vmar();
|
let root_vmar = process_vm.root_vmar();
|
||||||
|
|
||||||
// After we clear process vm, if any error happens, we must call exit_group instead of return to user space.
|
// After we clear process vm, if any error happens, we must call exit_group instead of return to user space.
|
||||||
@ -120,23 +134,27 @@ fn init_and_map_vmos(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let map_addr = map_segment_vmos(elf, root_vmar, elf_file)?;
|
let elf_map_addr = map_segment_vmos(parsed_elf, root_vmar, elf_file)?;
|
||||||
let mut aux_vec = init_aux_vec(elf, map_addr, vdso_text_base)?;
|
|
||||||
let mut init_stack = InitStack::new_default_config(argv, envp);
|
let aux_vec = {
|
||||||
init_stack.init(root_vmar, elf, &ldso_load_info, &mut aux_vec)?;
|
let ldso_base = ldso_load_info
|
||||||
|
.as_ref()
|
||||||
|
.map(|load_info| load_info.base_addr());
|
||||||
|
init_aux_vec(parsed_elf, elf_map_addr, ldso_base)?
|
||||||
|
};
|
||||||
|
|
||||||
let entry_point = if let Some(ldso_load_info) = ldso_load_info {
|
let entry_point = if let Some(ldso_load_info) = ldso_load_info {
|
||||||
// Normal shared object
|
// Normal shared object
|
||||||
ldso_load_info.entry_point()
|
ldso_load_info.entry_point()
|
||||||
} else if elf.is_shared_object() {
|
} else if parsed_elf.is_shared_object() {
|
||||||
// ldso itself
|
// ldso itself
|
||||||
elf.entry_point() + map_addr
|
parsed_elf.entry_point() + elf_map_addr
|
||||||
} else {
|
} else {
|
||||||
// statically linked executable
|
// statically linked executable
|
||||||
elf.entry_point()
|
parsed_elf.entry_point()
|
||||||
};
|
};
|
||||||
|
|
||||||
let elf_load_info = ElfLoadInfo::new(entry_point, init_stack.user_stack_top());
|
Ok((entry_point, aux_vec))
|
||||||
Ok(elf_load_info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LdsoLoadInfo {
|
pub struct LdsoLoadInfo {
|
||||||
@ -371,3 +389,51 @@ fn check_segment_align(program_header: &ProgramHeader64) -> Result<()> {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn init_aux_vec(elf: &Elf, elf_map_addr: Vaddr, ldso_base: Option<Vaddr>) -> Result<AuxVec> {
|
||||||
|
let mut aux_vec = AuxVec::new();
|
||||||
|
aux_vec.set(AuxKey::AT_PAGESZ, PAGE_SIZE as _)?;
|
||||||
|
let ph_addr = if elf.is_shared_object() {
|
||||||
|
elf.ph_addr()? + elf_map_addr
|
||||||
|
} else {
|
||||||
|
elf.ph_addr()?
|
||||||
|
};
|
||||||
|
aux_vec.set(AuxKey::AT_PHDR, ph_addr as u64)?;
|
||||||
|
aux_vec.set(AuxKey::AT_PHNUM, elf.ph_count() as u64)?;
|
||||||
|
aux_vec.set(AuxKey::AT_PHENT, elf.ph_ent() as u64)?;
|
||||||
|
let elf_entry = if elf.is_shared_object() {
|
||||||
|
let base_load_offset = elf.base_load_address_offset();
|
||||||
|
elf.entry_point() + elf_map_addr - base_load_offset as usize
|
||||||
|
} else {
|
||||||
|
elf.entry_point()
|
||||||
|
};
|
||||||
|
aux_vec.set(AuxKey::AT_ENTRY, elf_entry as u64)?;
|
||||||
|
|
||||||
|
if let Some(ldso_base) = ldso_base {
|
||||||
|
aux_vec.set(AuxKey::AT_BASE, ldso_base as u64)?;
|
||||||
|
}
|
||||||
|
Ok(aux_vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Map the vdso vmo to the corresponding virtual memory address.
|
||||||
|
fn map_vdso_to_vm(process_vm: &ProcessVm) -> Option<Vaddr> {
|
||||||
|
let root_vmar = process_vm.root_vmar();
|
||||||
|
let vdso_vmo = vdso_vmo()?;
|
||||||
|
|
||||||
|
let options = root_vmar
|
||||||
|
.new_map(vdso_vmo.dup().unwrap(), VmPerms::empty())
|
||||||
|
.unwrap()
|
||||||
|
.size(5 * PAGE_SIZE);
|
||||||
|
let vdso_data_base = options.build().unwrap();
|
||||||
|
let vdso_text_base = vdso_data_base + 0x4000;
|
||||||
|
|
||||||
|
let data_perms = VmPerms::READ | VmPerms::WRITE;
|
||||||
|
let text_perms = VmPerms::READ | VmPerms::EXEC;
|
||||||
|
root_vmar
|
||||||
|
.protect(data_perms, vdso_data_base..vdso_data_base + PAGE_SIZE)
|
||||||
|
.unwrap();
|
||||||
|
root_vmar
|
||||||
|
.protect(text_perms, vdso_text_base..vdso_text_base + PAGE_SIZE)
|
||||||
|
.unwrap();
|
||||||
|
Some(vdso_text_base)
|
||||||
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
mod aux_vec;
|
|
||||||
mod elf_file;
|
mod elf_file;
|
||||||
mod init_stack;
|
|
||||||
mod load_elf;
|
mod load_elf;
|
||||||
|
|
||||||
pub use init_stack::INIT_STACK_SIZE;
|
|
||||||
pub use load_elf::{load_elf_to_vm, ElfLoadInfo};
|
pub use load_elf::{load_elf_to_vm, ElfLoadInfo};
|
||||||
|
@ -14,33 +14,8 @@ use crate::{
|
|||||||
utils::Dentry,
|
utils::Dentry,
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
vdso::vdso_vmo,
|
|
||||||
vm::perms::VmPerms,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Map the vdso vmo to the corresponding virtual memory address.
|
|
||||||
pub fn map_vdso_to_vm(process_vm: &ProcessVm) -> Vaddr {
|
|
||||||
let root_vmar = process_vm.root_vmar();
|
|
||||||
let vdso_vmo = vdso_vmo();
|
|
||||||
|
|
||||||
let options = root_vmar
|
|
||||||
.new_map(vdso_vmo.dup().unwrap(), VmPerms::empty())
|
|
||||||
.unwrap()
|
|
||||||
.size(5 * PAGE_SIZE);
|
|
||||||
let vdso_data_base = options.build().unwrap();
|
|
||||||
let vdso_text_base = vdso_data_base + 0x4000;
|
|
||||||
|
|
||||||
let data_perms = VmPerms::READ | VmPerms::WRITE;
|
|
||||||
let text_perms = VmPerms::READ | VmPerms::EXEC;
|
|
||||||
root_vmar
|
|
||||||
.protect(data_perms, vdso_data_base..vdso_data_base + PAGE_SIZE)
|
|
||||||
.unwrap();
|
|
||||||
root_vmar
|
|
||||||
.protect(text_perms, vdso_text_base..vdso_text_base + PAGE_SIZE)
|
|
||||||
.unwrap();
|
|
||||||
vdso_text_base
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load an executable to root vmar, including loading programe image, preparing heap and stack,
|
/// Load an executable to root vmar, including loading programe image, preparing heap and stack,
|
||||||
/// initializing argv, envp and aux tables.
|
/// initializing argv, envp and aux tables.
|
||||||
/// About recursion_limit: recursion limit is used to limit th recursion depth of shebang executables.
|
/// About recursion_limit: recursion limit is used to limit th recursion depth of shebang executables.
|
||||||
@ -84,17 +59,11 @@ pub fn load_program_to_vm(
|
|||||||
recursion_limit - 1,
|
recursion_limit - 1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
process_vm.clear();
|
|
||||||
let vdso_text_base = map_vdso_to_vm(process_vm);
|
process_vm.clear_and_map();
|
||||||
let elf_load_info = load_elf_to_vm(
|
|
||||||
process_vm,
|
let elf_load_info =
|
||||||
&*file_header,
|
load_elf_to_vm(process_vm, &*file_header, elf_file, fs_resolver, argv, envp)?;
|
||||||
elf_file,
|
|
||||||
fs_resolver,
|
|
||||||
argv,
|
|
||||||
envp,
|
|
||||||
vdso_text_base,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok((abs_path, elf_load_info))
|
Ok((abs_path, elf_load_info))
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
use super::{process_vm::user_heap::USER_HEAP_SIZE_LIMIT, program_loader::elf::INIT_STACK_SIZE};
|
use super::process_vm::{INIT_STACK_SIZE, USER_HEAP_SIZE_LIMIT};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct ResourceLimits {
|
pub struct ResourceLimits {
|
||||||
|
@ -16,7 +16,7 @@ pub fn sys_brk(heap_end: u64) -> Result<SyscallReturn> {
|
|||||||
};
|
};
|
||||||
debug!("new heap end = {:x?}", heap_end);
|
debug!("new heap end = {:x?}", heap_end);
|
||||||
let current = current!();
|
let current = current!();
|
||||||
let user_heap = current.user_heap();
|
let user_heap = current.heap();
|
||||||
let new_heap_end = user_heap.brk(new_heap_end)?;
|
let new_heap_end = user_heap.brk(new_heap_end)?;
|
||||||
|
|
||||||
Ok(SyscallReturn::Return(new_heap_end as _))
|
Ok(SyscallReturn::Return(new_heap_end as _))
|
||||||
|
@ -4,7 +4,3 @@
|
|||||||
|
|
||||||
/// LONGEST ALLOWED FILENAME
|
/// LONGEST ALLOWED FILENAME
|
||||||
pub const MAX_FILENAME_LEN: usize = 4096;
|
pub const MAX_FILENAME_LEN: usize = 4096;
|
||||||
pub const MAX_ARGV_NUMBER: usize = 128;
|
|
||||||
pub const MAX_ENVP_NUMBER: usize = 128;
|
|
||||||
pub const MAX_ARG_LEN: usize = 2048;
|
|
||||||
pub const MAX_ENV_LEN: usize = 128;
|
|
||||||
|
@ -15,7 +15,7 @@ use crate::{
|
|||||||
process::{
|
process::{
|
||||||
check_executable_file, credentials_mut, load_program_to_vm,
|
check_executable_file, credentials_mut, load_program_to_vm,
|
||||||
posix_thread::{PosixThreadExt, ThreadName},
|
posix_thread::{PosixThreadExt, ThreadName},
|
||||||
Credentials,
|
Credentials, MAX_ARGV_NUMBER, MAX_ARG_LEN, MAX_ENVP_NUMBER, MAX_ENV_LEN,
|
||||||
},
|
},
|
||||||
syscall::{SYS_EXECVE, SYS_EXECVEAT},
|
syscall::{SYS_EXECVE, SYS_EXECVEAT},
|
||||||
util::{read_cstring_from_user, read_val_from_user},
|
util::{read_cstring_from_user, read_val_from_user},
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
use aster_frame::vm::VmIo;
|
use aster_frame::vm::VmIo;
|
||||||
|
use aster_rights::Full;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::{prelude::*, vm::vmar::Vmar};
|
||||||
pub mod net;
|
pub mod net;
|
||||||
|
|
||||||
/// Read bytes into the `dest` buffer
|
/// Read bytes into the `dest` buffer
|
||||||
@ -50,13 +51,20 @@ pub fn write_val_to_user<T: Pod>(dest: Vaddr, val: &T) -> Result<()> {
|
|||||||
/// The original Linux implementation can be found at:
|
/// The original Linux implementation can be found at:
|
||||||
/// <https://elixir.bootlin.com/linux/v6.0.9/source/lib/strncpy_from_user.c#L28>
|
/// <https://elixir.bootlin.com/linux/v6.0.9/source/lib/strncpy_from_user.c#L28>
|
||||||
pub fn read_cstring_from_user(addr: Vaddr, max_len: usize) -> Result<CString> {
|
pub fn read_cstring_from_user(addr: Vaddr, max_len: usize) -> Result<CString> {
|
||||||
|
let current = current!();
|
||||||
|
let vmar = current.root_vmar();
|
||||||
|
read_cstring_from_vmar(vmar, addr, max_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read CString from `vmar`. If possible, use `read_cstring_from_user` instead.
|
||||||
|
pub fn read_cstring_from_vmar(vmar: &Vmar<Full>, addr: Vaddr, max_len: usize) -> Result<CString> {
|
||||||
let mut buffer: Vec<u8> = Vec::with_capacity(max_len);
|
let mut buffer: Vec<u8> = Vec::with_capacity(max_len);
|
||||||
let mut cur_addr = addr;
|
let mut cur_addr = addr;
|
||||||
|
|
||||||
macro_rules! read_one_byte_at_a_time_while {
|
macro_rules! read_one_byte_at_a_time_while {
|
||||||
($cond:expr) => {
|
($cond:expr) => {
|
||||||
while $cond {
|
while $cond {
|
||||||
let byte = read_val_from_user::<u8>(cur_addr)?;
|
let byte = vmar.read_val::<u8>(cur_addr)?;
|
||||||
buffer.push(byte);
|
buffer.push(byte);
|
||||||
if byte == 0 {
|
if byte == 0 {
|
||||||
return Ok(CString::from_vec_with_nul(buffer)
|
return Ok(CString::from_vec_with_nul(buffer)
|
||||||
@ -74,7 +82,7 @@ pub fn read_cstring_from_user(addr: Vaddr, max_len: usize) -> Result<CString> {
|
|||||||
|
|
||||||
// Handle the rest of the bytes in bulk
|
// Handle the rest of the bytes in bulk
|
||||||
while (buffer.len() + mem::size_of::<usize>()) <= max_len {
|
while (buffer.len() + mem::size_of::<usize>()) <= max_len {
|
||||||
let Ok(word) = read_val_from_user::<usize>(cur_addr) else {
|
let Ok(word) = vmar.read_val::<usize>(cur_addr) else {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -258,6 +258,7 @@ pub(super) fn init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the vdso vmo.
|
/// Return the vdso vmo.
|
||||||
pub(crate) fn vdso_vmo() -> Arc<Vmo> {
|
pub(crate) fn vdso_vmo() -> Option<Arc<Vmo>> {
|
||||||
VDSO.get().unwrap().vmo().clone()
|
// We allow that vdso does not exist
|
||||||
|
VDSO.get().map(|vdso| vdso.vmo())
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,12 @@ pub trait VmarRightsOp {
|
|||||||
fn check_rights(&self, rights: Rights) -> Result<()>;
|
fn check_rights(&self, rights: Rights) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<R> PartialEq for Vmar<R> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
Arc::ptr_eq(&self.0, &other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<R> VmarRightsOp for Vmar<R> {
|
impl<R> VmarRightsOp for Vmar<R> {
|
||||||
default fn rights(&self) -> Rights {
|
default fn rights(&self) -> Rights {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user