1use crate::{
5 memory::{AddressSpace, UserSliceRead, VmaFlags, VmaPageSize, VmaType},
6 process::{
7 current_task_clone,
8 elf::{load_elf_image, LoadedElfInfo, USER_STACK_PAGES},
9 get_task_ids_in_tgid,
10 },
11 syscall::{error::SyscallError, SyscallFrame},
12 vfs,
13};
14use alloc::vec::Vec;
15
16const AT_NULL: u64 = 0;
17const AT_PHDR: u64 = 3;
18const AT_PHENT: u64 = 4;
19const AT_PHNUM: u64 = 5;
20const AT_PAGESZ: u64 = 6;
21const AT_BASE: u64 = 7;
22const AT_ENTRY: u64 = 9;
23const AT_RANDOM: u64 = 25;
24const AT_EXECFN: u64 = 31;
25
26fn read_exec_image(path: &str) -> Result<Option<Vec<u8>>, SyscallError> {
28 if crate::vfs::get_initfs_file_bytes(path).is_some() {
29 return Ok(None);
30 }
31
32 let fd = vfs::open(path, vfs::OpenFlags::READ)?;
33
34 const MAX_EXEC_SIZE: usize = 64 * 1024 * 1024;
35 let mut elf_data = Vec::new();
36 let mut buf = [0u8; 4096];
37 loop {
38 match vfs::read(fd, &mut buf) {
39 Ok(n) => {
40 if n == 0 {
41 break;
42 }
43 if elf_data.len() + n > MAX_EXEC_SIZE {
44 let _ = vfs::close(fd);
45 return Err(SyscallError::OutOfMemory);
46 }
47 elf_data.extend_from_slice(&buf[..n]);
48 }
49 Err(e) => {
50 let _ = vfs::close(fd);
51 return Err(e);
52 }
53 }
54 }
55 let _ = vfs::close(fd);
56
57 Ok(Some(elf_data))
58}
59
60pub fn sys_execve(
75 frame: &mut SyscallFrame,
76 path_ptr: u64,
77 argv_ptr: u64,
78 envp_ptr: u64,
79) -> Result<u64, SyscallError> {
80 let current = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
81
82 if get_task_ids_in_tgid(current.tgid).len() > 1 {
86 return Err(SyscallError::NotSupported);
87 }
88
89 let mut path_buf = [0u8; 4096];
90 let path_slice = UserSliceRead::new(path_ptr, 4096).map_err(|_| SyscallError::Fault)?;
91
92 let mut len = 0;
93
94 loop {
95 if len >= 4096 {
96 return Err(SyscallError::ArgumentListTooLong);
97 } let b = path_slice.read_u8(len).map_err(|_| SyscallError::Fault)?;
99 if b == 0 {
100 break;
101 }
102 path_buf[len] = b;
103 len += 1;
104 }
105 let path_str =
106 core::str::from_utf8(&path_buf[..len]).map_err(|_| SyscallError::InvalidArgument)?;
107
108 let exec_path = vfs::resolve_and_check_path_for_current_task(path_str, true, false, true)?;
109
110 let owned_elf_data = read_exec_image(&exec_path)?;
111 let elf_data = owned_elf_data
112 .as_deref()
113 .or_else(|| crate::vfs::get_initfs_file_bytes(&exec_path))
114 .ok_or(SyscallError::NotFound)?;
115
116 if elf_data.len() < 4 {
117 return Err(SyscallError::ExecFormatError);
118 }
119
120 let new_as = AddressSpace::new_user().map_err(|_| SyscallError::OutOfMemory)?;
121 let new_as_arc = alloc::sync::Arc::new(new_as);
122 new_as_arc.set_owner_pid(current.pid);
123
124 let load_info = match load_elf_image(elf_data, &new_as_arc) {
125 Ok(info) => info,
126 Err("PT_INTERP execute denied") => return Err(SyscallError::PermissionDenied),
127 Err(_) => return Err(SyscallError::ExecFormatError),
128 };
129
130 let stack_flags = VmaFlags {
131 readable: true,
132 writable: true,
133 executable: false,
134 user_accessible: true,
135 };
136 let stack_base = crate::kaslr::stack_base_with_jitter(crate::kaslr::draw_stack_jitter());
139 let stack_top = crate::kaslr::stack_top_for(stack_base, USER_STACK_PAGES);
140 new_as_arc
141 .map_region(
142 stack_base,
143 USER_STACK_PAGES,
144 stack_flags,
145 VmaType::Stack,
146 VmaPageSize::Small,
147 )
148 .map_err(|_| SyscallError::OutOfMemory)?;
149
150 let mut canary_bytes = [0u8; 8];
152 crate::entropy::fill_random(&mut canary_bytes);
153 let stack_canary = u64::from_le_bytes(canary_bytes) | 1; write_bytes_to_as(&new_as_arc, stack_top - 8, &stack_canary.to_le_bytes())?;
155 current
156 .stack_canary
157 .store(stack_canary, core::sync::atomic::Ordering::Relaxed);
158 current
159 .stack_canary_addr
160 .store(stack_top - 8, core::sync::atomic::Ordering::Relaxed);
161
162 let sp = setup_user_stack(
163 &new_as_arc,
164 argv_ptr,
165 envp_ptr,
166 &load_info,
167 path_str.as_bytes(),
168 stack_base,
169 stack_top - 8, )?;
171
172 let mut new_fs_base = 0u64;
174 if load_info.tls_memsz > 0 {
175 let tls_align = core::cmp::max(load_info.tls_align, 8).next_power_of_two();
176 let aligned_memsz = (load_info.tls_memsz + tls_align - 1) & !(tls_align - 1);
177 let total_size = aligned_memsz + 8;
178 let n_pages = ((total_size + 4095) / 4096) as usize;
179 let tls_flags = VmaFlags {
180 readable: true,
181 writable: true,
182 executable: false,
183 user_accessible: true,
184 };
185 let tls_base = new_as_arc
186 .find_free_vma_range(0x7FFF_E000_0000, n_pages, VmaPageSize::Small)
187 .ok_or(SyscallError::OutOfMemory)?;
188 new_as_arc
189 .map_region(
190 tls_base,
191 n_pages,
192 tls_flags,
193 VmaType::Anonymous,
194 VmaPageSize::Small,
195 )
196 .map_err(|_| SyscallError::OutOfMemory)?;
197 if load_info.tls_filesz > 0 && load_info.tls_vaddr != 0 {
198 let src_vaddr = load_info.tls_vaddr;
199 let mut off = 0u64;
200 let mut tmp = [0u8; 256];
201 while off < load_info.tls_filesz {
202 let chunk = core::cmp::min(256, (load_info.tls_filesz - off) as usize);
203 crate::process::elf::read_user_mapped_bytes_pub(
204 &new_as_arc,
205 src_vaddr + off,
206 &mut tmp[..chunk],
207 )
208 .map_err(|_| SyscallError::Fault)?;
209 crate::process::elf::write_user_mapped_bytes_pub(
210 &new_as_arc,
211 tls_base + off,
212 &tmp[..chunk],
213 )
214 .map_err(|_| SyscallError::Fault)?;
215 off += chunk as u64;
216 }
217 }
218 let tp = tls_base + aligned_memsz;
219 crate::process::elf::write_user_u64_pub(&new_as_arc, tp, tp)
220 .map_err(|_| SyscallError::Fault)?;
221 new_fs_base = tp;
222 }
223
224 unsafe {
229 let fd_table = &mut *current.process.fd_table.get();
230 fd_table.close_cloexec();
231 }
232
233 current.reset_signals();
235
236 unsafe {
238 *current.signal_stack.get() = None;
239 }
240
241 current
243 .clear_child_tid
244 .store(0, core::sync::atomic::Ordering::Relaxed);
245 current
246 .user_fs_base
247 .store(new_fs_base, core::sync::atomic::Ordering::Relaxed);
248
249 current
251 .process
252 .brk
253 .store(0, core::sync::atomic::Ordering::Relaxed);
254 current.process.mmap_hint.store(
255 crate::kaslr::mmap_base(),
256 core::sync::atomic::Ordering::Relaxed,
257 );
258 unsafe {
260 let lo = new_fs_base as u32;
261 let hi = (new_fs_base >> 32) as u32;
262 core::arch::asm!(
263 "mov ecx, 0xC0000100", "wrmsr",
265 in("eax") lo,
266 in("edx") hi,
267 options(nostack, preserves_flags),
268 );
269 }
270
271 let old_as = current.process.replace_address_space(new_as_arc.clone());
272
273 unsafe {
274 current.process.address_space_arc().switch_to();
275 }
276
277 frame.iret_rip = load_info.runtime_entry;
278 frame.iret_rsp = sp;
279 frame.iret_rflags = 0x200; frame.rdi = 0;
282 frame.rsi = 0;
283 frame.rdx = 0;
284 frame.rcx = 0;
285 frame.r8 = 0;
286 frame.r9 = 0;
287 frame.r10 = 0;
288 frame.r11 = 0;
289 frame.rbx = 0;
290 frame.rbp = 0;
291 frame.r12 = 0;
292 frame.r13 = 0;
293 frame.r14 = 0;
294 frame.r15 = 0;
295 frame.rax = 0;
296
297 drop(old_as);
299
300 Ok(0)
301}
302
303fn setup_user_stack(
305 new_as: &AddressSpace,
306 argv_ptr: u64,
307 envp_ptr: u64,
308 elf_info: &LoadedElfInfo,
309 exec_path: &[u8],
310 stack_base: u64,
311 stack_top: u64,
312) -> Result<u64, SyscallError> {
313 let args = read_string_array(argv_ptr)?;
314 let envs = read_string_array(envp_ptr)?;
315
316 let mut sp = stack_top;
317 let mut str_ptrs: Vec<u64> = Vec::with_capacity(args.len()); let mut env_ptrs: Vec<u64> = Vec::with_capacity(envs.len()); for env in envs.iter().rev() {
327 let len = (env.len() + 1) as u64;
328 sp = sp
329 .checked_sub(len)
330 .ok_or(SyscallError::ArgumentListTooLong)?;
331 if sp < stack_base {
332 return Err(SyscallError::ArgumentListTooLong);
333 }
334 write_bytes_to_as(new_as, sp, env)?;
335 write_bytes_to_as(new_as, sp + env.len() as u64, &[0])?;
336 env_ptrs.push(sp);
337 }
338 env_ptrs.reverse();
342
343 for arg in args.iter().rev() {
345 let len = (arg.len() + 1) as u64;
346 sp = sp
347 .checked_sub(len)
348 .ok_or(SyscallError::ArgumentListTooLong)?;
349 if sp < stack_base {
350 return Err(SyscallError::ArgumentListTooLong);
351 }
352 write_bytes_to_as(new_as, sp, arg)?;
353 write_bytes_to_as(new_as, sp + arg.len() as u64, &[0])?;
354 str_ptrs.push(sp);
355 }
356 str_ptrs.reverse();
357
358 let mut execfn_ptr = 0u64;
360 if !exec_path.is_empty() {
361 let len = (exec_path.len() + 1) as u64;
362 sp -= len;
363 write_bytes_to_as(new_as, sp, exec_path)?;
364 write_bytes_to_as(new_as, sp + exec_path.len() as u64, &[0])?;
365 execfn_ptr = sp;
366 }
367
368 sp -= 16;
370 let rand_ptr = sp;
371 let seed = generate_aux_random_seed();
372 write_bytes_to_as(new_as, rand_ptr, &seed)?;
373
374 sp &= !0xF;
376
377 let size_ptr = 8u64;
379
380 let mut auxv: Vec<(u64, u64)> = Vec::with_capacity(10);
382 auxv.push((AT_PHDR, elf_info.phdr_vaddr));
383 auxv.push((AT_PHENT, elf_info.phent as u64));
384 auxv.push((AT_PHNUM, elf_info.phnum as u64));
385 auxv.push((AT_PAGESZ, 4096));
386 if let Some(base) = elf_info.interp_base {
387 auxv.push((AT_BASE, base));
388 }
389 auxv.push((AT_ENTRY, elf_info.program_entry));
390 auxv.push((AT_RANDOM, rand_ptr));
391 if execfn_ptr != 0 {
392 auxv.push((AT_EXECFN, execfn_ptr));
393 }
394
395 let stack_words = 1u64
398 + (str_ptrs.len() as u64 + 1)
399 + (env_ptrs.len() as u64 + 1)
400 + ((auxv.len() as u64 + 1) * 2);
401 let align_pad = (0u64.wrapping_sub(stack_words * size_ptr)) & 0xF;
402 sp -= align_pad;
403
404 sp -= size_ptr;
406 write_u64_to_as(new_as, sp, 0)?;
407 sp -= size_ptr;
408 write_u64_to_as(new_as, sp, AT_NULL)?;
409 for &(key, val) in auxv.iter().rev() {
410 sp -= size_ptr;
411 write_u64_to_as(new_as, sp, val)?;
412 sp -= size_ptr;
413 write_u64_to_as(new_as, sp, key)?;
414 }
415
416 sp -= size_ptr;
422 write_u64_to_as(new_as, sp, 0)?; for &ptr in env_ptrs.iter().rev() {
425 sp -= size_ptr;
426 write_u64_to_as(new_as, sp, ptr)?;
427 }
428 sp -= size_ptr;
436 write_u64_to_as(new_as, sp, 0)?; for &ptr in str_ptrs.iter().rev() {
439 sp -= size_ptr;
440 write_u64_to_as(new_as, sp, ptr)?;
441 }
442 sp -= size_ptr;
446 write_u64_to_as(new_as, sp, args.len() as u64)?;
447
448 debug_assert_eq!(sp & 0xF, 0);
449
450 Ok(sp)
451}
452
453fn read_string_array(ptr: u64) -> Result<Vec<Vec<u8>>, SyscallError> {
455 let mut res = Vec::new();
456 if ptr == 0 {
457 return Ok(res);
458 }
459
460 let mut arr_off = 0;
461 loop {
462 let str_ptr = match UserSliceRead::new(ptr + arr_off, 8) {
464 Ok(slice) => match slice.read_u64(0) {
465 Ok(p) => p,
466 Err(_) => return Err(SyscallError::Fault),
467 },
468 Err(_) => return Err(SyscallError::Fault),
469 };
470
471 if str_ptr == 0 {
472 break;
473 }
474 if res.len() > 1024 {
475 return Err(SyscallError::ArgumentListTooLong);
476 }
477
478 let mut s = Vec::new();
479 let mut i = 0;
480 loop {
481 if i > 4096 {
482 return Err(SyscallError::ArgumentListTooLong);
483 }
484 let b = match UserSliceRead::new(str_ptr + i, 1) {
485 Ok(slice) => match slice.read_u8(0) {
486 Ok(byte) => byte,
487 Err(_) => return Err(SyscallError::Fault),
488 },
489 Err(_) => return Err(SyscallError::Fault),
490 };
491 if b == 0 {
492 break;
493 }
494 s.push(b);
495 i += 1;
496 }
497 res.push(s);
498 arr_off += 8;
499 }
500 Ok(res)
501}
502
503fn write_bytes_to_as(as_ref: &AddressSpace, vaddr: u64, data: &[u8]) -> Result<(), SyscallError> {
505 use crate::arch::xshim::VirtAddr;
506 let mut written = 0;
507 while written < data.len() {
518 let curr_vaddr = vaddr + written as u64;
519 let page_offset = (curr_vaddr & 0xFFF) as usize;
520 let chunk_size = core::cmp::min(data.len() - written, 4096 - page_offset);
521
522 let phys = as_ref
525 .translate(VirtAddr::new(curr_vaddr))
526 .ok_or(SyscallError::Fault)?;
527 let virt = crate::memory::phys_to_virt(phys.as_u64()) as *mut u8;
528
529 unsafe {
530 core::ptr::copy_nonoverlapping(data.as_ptr().add(written), virt, chunk_size);
531 }
532 written += chunk_size;
533 }
534 Ok(())
535}
536
537fn write_u64_to_as(as_ref: &AddressSpace, vaddr: u64, val: u64) -> Result<(), SyscallError> {
539 let bytes = val.to_ne_bytes();
540 write_bytes_to_as(as_ref, vaddr, &bytes)
541}
542
543fn generate_aux_random_seed() -> [u8; 16] {
545 let mut seed = [0u8; 16];
546 crate::entropy::fill_random(&mut seed);
547 seed
548}