Skip to main content

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
30use alloc::{collections::VecDeque, string::String, vec::Vec};
31
32use zerocopy::IntoBytes;
33
34use crate::auxv::{AuxEntry, AuxType};
35
36/// Generate initial stack frame for user stack
37///
38/// # Arguments
39///
40/// * `args` - Arguments of the application
41/// * `envs` - Environment variables of the application
42/// * `auxv` - Auxiliary vectors of the application
43/// * `sp`   - Highest address of the stack
44///
45/// # Return
46///
47/// * [`Vec<u8>`] - Initial stack frame of the application
48///
49/// # Notes
50///
51/// The detailed format is described in <https://articles.manugarg.com/aboutelfauxiliaryvectors.html>
52pub fn app_stack_region(args: &[String], envs: &[String], auxv: &[AuxEntry], sp: usize) -> Vec<u8> {
53    let mut data = VecDeque::new();
54    let mut push = |src: &[u8]| -> usize {
55        data.extend(src.iter().cloned());
56        data.rotate_right(src.len());
57        sp - data.len()
58    };
59
60    // define a random string with 16 bytes
61    let random_str_pos = push("0123456789abcdef".as_bytes());
62    // Push arguments and environment variables
63    let envs_slice: Vec<_> = envs
64        .iter()
65        .map(|env| {
66            push(b"\0");
67            push(env.as_bytes())
68        })
69        .collect();
70    let argv_slice: Vec<_> = args
71        .iter()
72        .map(|arg| {
73            push(b"\0");
74            push(arg.as_bytes())
75        })
76        .collect();
77    let padding_null = "\0".repeat(8);
78    let sp = push(padding_null.as_bytes());
79
80    push(&b"\0".repeat(sp % 16));
81
82    // Align stack to 16 bytes by padding if needed.
83    // We will push following 8-byte items into stack:
84    // - auxv (each entry is 2 * usize, so item count = auxv.len() * 2)
85    // - envp (len + 1 for NULL terminator)
86    // - argv (len + 1 for NULL terminator)
87    // - argc (1 item)
88    // Total items = auxv.len() * 2 + (envs.len() + 1) + (args.len() + 1) + 1
89    //             = auxv.len() * 2 + envs.len() + args.len() + 3
90    // If odd, the stack top will not be aligned to 16 bytes unless we add 8-byte
91    // padding
92    if (envs.len() + args.len() + 3) & 1 != 0 {
93        push(padding_null.as_bytes());
94    }
95
96    // Push auxiliary vectors
97    let mut has_random = false;
98    let mut has_execfn = false;
99    for entry in auxv.iter() {
100        if entry.get_type() == AuxType::RANDOM {
101            has_random = true;
102        }
103        if entry.get_type() == AuxType::EXECFN {
104            has_execfn = true;
105        }
106        if has_random && has_execfn {
107            break;
108        }
109    }
110    push(auxv.as_bytes());
111    if !has_random {
112        push(AuxEntry::new(AuxType::RANDOM, random_str_pos).as_bytes());
113    }
114    if !has_execfn {
115        push(AuxEntry::new(AuxType::EXECFN, argv_slice[0]).as_bytes());
116    }
117
118    // Push the argv and envp pointers
119    push(padding_null.as_bytes());
120    push(envs_slice.as_bytes());
121    push(padding_null.as_bytes());
122    push(argv_slice.as_bytes());
123    // Push argc
124    let sp = push(args.len().as_bytes());
125
126    assert!(sp % 16 == 0);
127
128    let mut result = Vec::with_capacity(data.len());
129    let (first, second) = data.as_slices();
130    result.extend_from_slice(first);
131    result.extend_from_slice(second);
132    result
133}