kernel_elf_parser/
user_stack.rs

1//! Initialize the user stack for the application
2//!
3//! The structure of the user stack is described in the following figure:
4//! position            content                     size (bytes) + comment
5//!   ------------------------------------------------------------------------
6//! stack pointer ->  [ argc = number of args ]     8
7//!                   [ argv[0] (pointer) ]         8   (program name)
8//!                   [ argv[1] (pointer) ]         8
9//!                   [ argv[..] (pointer) ]        8 * x
10//!                   [ argv[n - 1] (pointer) ]     8
11//!                   [ argv[n] (pointer) ]         8   (= NULL)
12//!                   [ envp[0] (pointer) ]         8
13//!                   [ envp[1] (pointer) ]         8
14//!                   [ envp[..] (pointer) ]        8
15//!                   [ envp[term] (pointer) ]      8   (= NULL)
16//!                   [ auxv[0] (Elf32_auxv_t) ]    16
17//!                   [ auxv[1] (Elf32_auxv_t) ]    16
18//!                   [ auxv[..] (Elf32_auxv_t) ]   16
19//!                   [ auxv[term] (Elf32_auxv_t) ] 16  (= AT_NULL vector)
20//!                   [ padding ]                   0 - 16
21//!                   [ argument ASCIIZ strings ]   >= 0
22//!                   [ environment ASCIIZ str. ]   >= 0
23//!
24//! (0xbffffff8)      [ end marker ]                8   (= NULL)
25//!
26//! (0xc0000000)      < bottom of stack >           0   (virtual)
27//!
28//! More details can be found in the link: <https://articles.manugarg.com/aboutelfauxiliaryvectors.html>
29
30extern crate alloc;
31
32use alloc::{string::String, vec::Vec};
33use memory_addr::VirtAddr;
34
35use crate::auxv::{AuxvEntry, AuxvType};
36
37struct UserStack {
38    sp: usize,
39}
40
41impl UserStack {
42    pub fn new(sp: usize) -> Self {
43        Self { sp }
44    }
45    fn push(&mut self, src: &[u8], stack_data: &mut Vec<u8>) {
46        self.sp -= src.len();
47        // let mut target_data = src.to_vec();
48        // target_data.append(stack_data);
49        // *stack_data = target_data;
50        stack_data.splice(0..0, src.iter().cloned());
51    }
52    pub fn push_usize_slice(&mut self, src: &[usize], stack_data: &mut Vec<u8>) {
53        for val in src.iter().rev() {
54            let bytes = val.to_le_bytes();
55            self.push(&bytes, stack_data);
56        }
57    }
58    pub fn push_str(&mut self, str: &str, stack_data: &mut Vec<u8>) -> usize {
59        self.push(b"\0", stack_data);
60
61        self.push(str.as_bytes(), stack_data);
62        self.sp
63    }
64    pub fn get_sp(&self) -> usize {
65        self.sp
66    }
67}
68
69fn init_stack(args: &[String], envs: &[String], auxv: &mut [AuxvEntry], sp: usize) -> Vec<u8> {
70    let mut data = Vec::new();
71    let mut stack = UserStack::new(sp);
72    // define a random string with 16 bytes
73    stack.push("0123456789abcdef".as_bytes(), &mut data);
74    let random_str_pos = stack.get_sp();
75    // Push arguments and environment variables
76    let envs_slice: Vec<_> = envs
77        .iter()
78        .map(|env| stack.push_str(env, &mut data))
79        .collect();
80    let argv_slice: Vec<_> = args
81        .iter()
82        .map(|arg| stack.push_str(arg, &mut data))
83        .collect();
84    let padding_null = "\0".repeat(8);
85    stack.push(padding_null.as_bytes(), &mut data);
86
87    stack.push("\0".repeat(stack.get_sp() % 16).as_bytes(), &mut data);
88
89    // Align stack to 16 bytes by padding if needed.
90    // We will push following 8-byte items into stack:
91    // - auxv (each entry is 2 * usize, so item count = auxv.len() * 2)
92    // - envp (len + 1 for NULL terminator)
93    // - argv (len + 1 for NULL terminator)
94    // - argc (1 item)
95    // Total items = auxv.len() * 2 + (envs.len() + 1) + (args.len() + 1) + 1
96    //             = auxv.len() * 2 + envs.len() + args.len() + 3
97    // If odd, the stack top will not be aligned to 16 bytes unless we add 8-byte padding
98    if (envs.len() + args.len() + 3) & 1 != 0 {
99        stack.push(padding_null.as_bytes(), &mut data);
100    }
101
102    // Push auxiliary vectors
103    for auxv_entry in auxv.iter_mut() {
104        if auxv_entry.get_type() == AuxvType::RANDOM {
105            *auxv_entry.value_mut_ref() = random_str_pos;
106        }
107        if auxv_entry.get_type() == AuxvType::EXECFN {
108            *auxv_entry.value_mut_ref() = argv_slice[0];
109        }
110    }
111    stack.push_usize_slice(
112        unsafe {
113            core::slice::from_raw_parts(
114                auxv.as_ptr() as *const usize,
115                core::mem::size_of_val(auxv) / core::mem::size_of::<usize>(),
116            )
117        },
118        &mut data,
119    );
120
121    // Push the argv and envp pointers
122    stack.push(padding_null.as_bytes(), &mut data);
123    stack.push_usize_slice(envs_slice.as_slice(), &mut data);
124    stack.push(padding_null.as_bytes(), &mut data);
125    stack.push_usize_slice(argv_slice.as_slice(), &mut data);
126    // Push argc
127    stack.push_usize_slice(&[args.len()], &mut data);
128    assert!(stack.get_sp() % 16 == 0);
129    data
130}
131
132/// Generate initial stack frame for user stack
133///
134/// # Arguments
135///
136/// * `args` - Arguments of the application
137/// * `envs` - Environment variables of the application
138/// * `auxv` - Auxiliary vectors of the application
139/// * `stack_base` - Lowest address of the stack
140/// * `stack_size` - Size of the stack.
141///
142/// # Return
143///
144/// * [`Vec<u8>`] - Initial stack frame of the application
145///
146/// # Notes
147///
148/// The detailed format is described in <https://articles.manugarg.com/aboutelfauxiliaryvectors.html>
149pub fn app_stack_region(
150    args: &[String],
151    envs: &[String],
152    auxv: &mut [AuxvEntry],
153    stack_base: VirtAddr,
154    stack_size: usize,
155) -> Vec<u8> {
156    let ustack_bottom = stack_base;
157    let ustack_top = ustack_bottom + stack_size;
158    init_stack(args, envs, auxv, ustack_top.into())
159}