1use std::ffi::{CStr, CString};
2use std::os::unix::ffi::OsStringExt;
3use std::sync::Arc;
4
5use atomic_refcell::AtomicRefCell;
6use linux_api::errno::Errno;
7use linux_api::fcntl::{DescriptorFlags, OFlag};
8use linux_api::posix_types::{kernel_off_t, kernel_pid_t};
9use log::*;
10use shadow_shim_helper_rs::emulated_time::EmulatedTime;
11use shadow_shim_helper_rs::rootedcell::refcell::RootedRefCell;
12use shadow_shim_helper_rs::simulation_time::SimulationTime;
13use shadow_shim_helper_rs::syscall_types::ForeignPtr;
14
15use crate::core::work::task::TaskRef;
16use crate::core::worker::Worker;
17use crate::cshadow as c;
18use crate::host::descriptor::descriptor_table::DescriptorHandle;
19use crate::host::descriptor::shared_buf::SharedBuf;
20use crate::host::descriptor::{
21 CompatFile, Descriptor, DropPosixRecordLocks, File, FileMode, FileStatus, OpenFile, pipe,
22};
23use crate::host::process::{Process, ProcessId};
24use crate::host::syscall::handler::{SyscallContext, SyscallHandler};
25use crate::host::syscall::io::{IoVec, read_cstring_vec};
26use crate::host::syscall::type_formatting::{SyscallBufferArg, SyscallStringArg};
27use crate::host::syscall::types::{ForeignArrayPtr, SyscallError};
28use crate::utility::callback_queue::CallbackQueue;
29use crate::utility::u8_to_i8_slice;
30
31impl SyscallHandler {
32 log_syscall!(
33 close,
34 std::ffi::c_int,
35 std::ffi::c_int,
36 );
37 pub fn close(ctx: &mut SyscallContext, fd: std::ffi::c_int) -> Result<(), SyscallError> {
38 trace!("Trying to close fd {fd}");
39
40 let fd = fd.try_into().or(Err(linux_api::errno::Errno::EBADF))?;
41
42 let desc = ctx
46 .objs
47 .thread
48 .descriptor_table_borrow_mut(ctx.objs.host)
49 .deregister_descriptor(fd)
50 .ok_or(linux_api::errno::Errno::EBADF)?;
51
52 let drop_locks = DropPosixRecordLocks::ForPid(ctx.objs.process.id());
55 CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
56 desc.close(ctx.objs.host, drop_locks, cb_queue)
57 })
58 .unwrap_or(Ok(()))
59 }
60
61 log_syscall!(
62 dup,
63 std::ffi::c_int,
64 std::ffi::c_int,
65 );
66 pub fn dup(
67 ctx: &mut SyscallContext,
68 fd: std::ffi::c_int,
69 ) -> Result<DescriptorHandle, SyscallError> {
70 let mut desc_table = ctx.objs.thread.descriptor_table_borrow_mut(ctx.objs.host);
72 let desc = Self::get_descriptor(&desc_table, fd)?;
73
74 let new_desc = desc.dup(DescriptorFlags::empty());
76
77 Ok(desc_table
78 .register_descriptor(new_desc)
79 .or(Err(Errno::ENFILE))?)
80 }
81
82 log_syscall!(
83 dup2,
84 std::ffi::c_int,
85 std::ffi::c_int,
86 std::ffi::c_int,
87 );
88 pub fn dup2(
89 ctx: &mut SyscallContext,
90 old_fd: std::ffi::c_int,
91 new_fd: std::ffi::c_int,
92 ) -> Result<DescriptorHandle, SyscallError> {
93 let old_fd = DescriptorHandle::try_from(old_fd).or(Err(Errno::EBADF))?;
94 let new_fd = DescriptorHandle::try_from(new_fd).or(Err(Errno::EBADF))?;
95
96 let mut desc_table = ctx.objs.thread.descriptor_table_borrow_mut(ctx.objs.host);
98 let desc = Self::get_descriptor(&desc_table, old_fd)?;
99
100 if old_fd == new_fd {
103 return Ok(new_fd);
104 }
105
106 let new_desc = desc.dup(DescriptorFlags::empty());
108 let replaced_desc = desc_table.register_descriptor_with_fd(new_desc, new_fd);
109
110 if let Some(replaced_desc) = replaced_desc {
112 let drop_locks = DropPosixRecordLocks::ForPid(ctx.objs.process.id());
113 CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
116 replaced_desc.close(ctx.objs.host, drop_locks, cb_queue)
117 });
118 }
119
120 Ok(new_fd)
122 }
123
124 log_syscall!(
125 dup3,
126 std::ffi::c_int,
127 std::ffi::c_int,
128 std::ffi::c_int,
129 linux_api::fcntl::OFlag,
130 );
131 pub fn dup3(
132 ctx: &mut SyscallContext,
133 old_fd: std::ffi::c_int,
134 new_fd: std::ffi::c_int,
135 flags: std::ffi::c_int,
136 ) -> Result<DescriptorHandle, SyscallError> {
137 let mut desc_table = ctx.objs.thread.descriptor_table_borrow_mut(ctx.objs.host);
139 let desc = Self::get_descriptor(&desc_table, old_fd)?;
140
141 if old_fd == new_fd {
143 return Err(linux_api::errno::Errno::EINVAL.into());
144 }
145
146 let new_fd = new_fd.try_into().or(Err(linux_api::errno::Errno::EBADF))?;
147
148 let Some(flags) = OFlag::from_bits(flags) else {
149 debug!("Invalid flags: {flags}");
150 return Err(linux_api::errno::Errno::EINVAL.into());
151 };
152
153 let mut descriptor_flags = DescriptorFlags::empty();
154
155 for flag in flags {
157 match flag {
158 OFlag::O_CLOEXEC => descriptor_flags.insert(DescriptorFlags::FD_CLOEXEC),
159 x if x == OFlag::empty() => {
160 }
162 _ => {
163 debug!("Invalid flags for dup3: {flags:?}");
164 return Err(linux_api::errno::Errno::EINVAL.into());
165 }
166 }
167 }
168
169 let new_desc = desc.dup(descriptor_flags);
171 let replaced_desc = desc_table.register_descriptor_with_fd(new_desc, new_fd);
172
173 if let Some(replaced_desc) = replaced_desc {
175 let drop_locks = DropPosixRecordLocks::ForPid(ctx.objs.process.id());
176 CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
179 replaced_desc.close(ctx.objs.host, drop_locks, cb_queue)
180 });
181 }
182
183 Ok(new_fd)
185 }
186
187 log_syscall!(
188 read,
189 isize,
190 std::ffi::c_int,
191 *const std::ffi::c_void,
192 usize,
193 );
194 pub fn read(
195 ctx: &mut SyscallContext,
196 fd: std::ffi::c_int,
197 buf_ptr: ForeignPtr<u8>,
198 buf_size: usize,
199 ) -> Result<isize, SyscallError> {
200 let file = ctx
203 .objs
204 .thread
205 .syscall_condition()
206 .and_then(|x| x.active_file().cloned());
208
209 let file = match file {
210 Some(x) => x,
212 None => {
214 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
215 match Self::get_descriptor(&desc_table, fd)?.file() {
216 CompatFile::New(file) => file.clone(),
217 CompatFile::Legacy(_) => {
219 drop(desc_table);
220 return Self::legacy_syscall(c::syscallhandler_read, ctx);
221 }
222 }
223 }
224 };
225
226 let mut result = Self::read_helper(ctx, file.inner_file(), buf_ptr, buf_size, None);
227
228 if let Some(err) = result.as_mut().err()
230 && let Some(cond) = err.blocked_condition()
231 {
232 cond.set_active_file(file);
233 }
234
235 let bytes_read = result?;
236 Ok(bytes_read)
237 }
238
239 log_syscall!(
240 pread64,
241 isize,
242 std::ffi::c_int,
243 *const std::ffi::c_void,
244 usize,
245 kernel_off_t,
246 );
247 pub fn pread64(
248 ctx: &mut SyscallContext,
249 fd: std::ffi::c_int,
250 buf_ptr: ForeignPtr<u8>,
251 buf_size: usize,
252 offset: kernel_off_t,
253 ) -> Result<isize, SyscallError> {
254 let file = ctx
257 .objs
258 .thread
259 .syscall_condition()
260 .and_then(|x| x.active_file().cloned());
262
263 let file = match file {
264 Some(x) => x,
266 None => {
268 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
269 match Self::get_descriptor(&desc_table, fd)?.file() {
270 CompatFile::New(file) => file.clone(),
271 CompatFile::Legacy(_) => {
273 drop(desc_table);
274 return Self::legacy_syscall(c::syscallhandler_pread64, ctx);
275 }
276 }
277 }
278 };
279
280 let mut result = Self::read_helper(ctx, file.inner_file(), buf_ptr, buf_size, Some(offset));
281
282 if let Some(err) = result.as_mut().err()
284 && let Some(cond) = err.blocked_condition()
285 {
286 cond.set_active_file(file);
287 }
288
289 let bytes_read = result?;
290 Ok(bytes_read)
291 }
292
293 fn read_helper(
294 ctx: &mut SyscallContext,
295 file: &File,
296 buf_ptr: ForeignPtr<u8>,
297 buf_size: usize,
298 offset: Option<kernel_off_t>,
299 ) -> Result<isize, SyscallError> {
300 let iov = IoVec {
301 base: buf_ptr,
302 len: buf_size,
303 };
304 Self::readv_helper(ctx, file, &[iov], offset, 0)
305 }
306
307 log_syscall!(
308 write,
309 isize,
310 std::ffi::c_int,
311 SyscallBufferArg<2>,
312 usize,
313 );
314 pub fn write(
315 ctx: &mut SyscallContext,
316 fd: std::ffi::c_int,
317 buf_ptr: ForeignPtr<u8>,
318 buf_size: usize,
319 ) -> Result<isize, SyscallError> {
320 let file = ctx
323 .objs
324 .thread
325 .syscall_condition()
326 .and_then(|x| x.active_file().cloned());
328
329 let file = match file {
330 Some(x) => x,
332 None => {
334 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
335 match Self::get_descriptor(&desc_table, fd)?.file() {
336 CompatFile::New(file) => file.clone(),
337 CompatFile::Legacy(_) => {
339 drop(desc_table);
340 return Self::legacy_syscall(c::syscallhandler_write, ctx);
341 }
342 }
343 }
344 };
345
346 let mut result = Self::write_helper(ctx, file.inner_file(), buf_ptr, buf_size, None);
347
348 if let Some(err) = result.as_mut().err()
350 && let Some(cond) = err.blocked_condition()
351 {
352 cond.set_active_file(file);
353 }
354
355 let bytes_written = result?;
356 Ok(bytes_written)
357 }
358
359 log_syscall!(
360 pwrite64,
361 isize,
362 std::ffi::c_int,
363 SyscallBufferArg<2>,
364 usize,
365 kernel_off_t,
366 );
367 pub fn pwrite64(
368 ctx: &mut SyscallContext,
369 fd: std::ffi::c_int,
370 buf_ptr: ForeignPtr<u8>,
371 buf_size: usize,
372 offset: kernel_off_t,
373 ) -> Result<isize, SyscallError> {
374 let file = ctx
377 .objs
378 .thread
379 .syscall_condition()
380 .and_then(|x| x.active_file().cloned());
382
383 let file = match file {
384 Some(x) => x,
386 None => {
388 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
389 match Self::get_descriptor(&desc_table, fd)?.file() {
390 CompatFile::New(file) => file.clone(),
391 CompatFile::Legacy(_) => {
393 drop(desc_table);
394 return Self::legacy_syscall(c::syscallhandler_pwrite64, ctx);
395 }
396 }
397 }
398 };
399
400 let mut result =
401 Self::write_helper(ctx, file.inner_file(), buf_ptr, buf_size, Some(offset));
402
403 if let Some(err) = result.as_mut().err()
405 && let Some(cond) = err.blocked_condition()
406 {
407 cond.set_active_file(file);
408 }
409
410 let bytes_written = result?;
411 Ok(bytes_written)
412 }
413
414 fn write_helper(
415 ctx: &mut SyscallContext,
416 file: &File,
417 buf_ptr: ForeignPtr<u8>,
418 buf_size: usize,
419 offset: Option<kernel_off_t>,
420 ) -> Result<isize, SyscallError> {
421 let iov = IoVec {
422 base: buf_ptr,
423 len: buf_size,
424 };
425 Self::writev_helper(ctx, file, &[iov], offset, 0)
426 }
427
428 log_syscall!(
429 pipe,
430 std::ffi::c_int,
431 [std::ffi::c_int; 2],
432 );
433 pub fn pipe(
434 ctx: &mut SyscallContext,
435 fd_ptr: ForeignPtr<[std::ffi::c_int; 2]>,
436 ) -> Result<(), SyscallError> {
437 Self::pipe_helper(ctx, fd_ptr, 0)
438 }
439
440 log_syscall!(
441 pipe2,
442 std::ffi::c_int,
443 [std::ffi::c_int; 2],
444 linux_api::fcntl::OFlag,
445 );
446 pub fn pipe2(
447 ctx: &mut SyscallContext,
448 fd_ptr: ForeignPtr<[std::ffi::c_int; 2]>,
449 flags: std::ffi::c_int,
450 ) -> Result<(), SyscallError> {
451 Self::pipe_helper(ctx, fd_ptr, flags)
452 }
453
454 fn pipe_helper(
455 ctx: &mut SyscallContext,
456 fd_ptr: ForeignPtr<[std::ffi::c_int; 2]>,
457 flags: i32,
458 ) -> Result<(), SyscallError> {
459 if fd_ptr.is_null() {
461 return Err(linux_api::errno::Errno::EFAULT.into());
462 }
463
464 let Some(flags) = OFlag::from_bits(flags) else {
465 debug!("Invalid flags: {flags}");
466 return Err(Errno::EINVAL.into());
467 };
468
469 let mut file_flags = FileStatus::empty();
470 let mut descriptor_flags = DescriptorFlags::empty();
471
472 for flag in flags.iter() {
473 match flag {
474 OFlag::O_NONBLOCK => file_flags.insert(FileStatus::O_NONBLOCK),
475 OFlag::O_DIRECT => file_flags.insert(FileStatus::O_DIRECT),
476 OFlag::O_CLOEXEC => descriptor_flags.insert(DescriptorFlags::FD_CLOEXEC),
477 x if x == OFlag::empty() => {
478 }
480 unhandled => {
481 warn!("Ignoring pipe flag {unhandled:?}");
483 }
484 }
485 }
486
487 let buffer = SharedBuf::new(c::CONFIG_PIPE_BUFFER_SIZE.try_into().unwrap());
489 let buffer = Arc::new(AtomicRefCell::new(buffer));
490
491 let reader = pipe::Pipe::new(FileMode::READ, file_flags);
493 let reader = Arc::new(AtomicRefCell::new(reader));
494
495 let writer = pipe::Pipe::new(FileMode::WRITE, file_flags);
497 let writer = Arc::new(AtomicRefCell::new(writer));
498
499 CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
501 pipe::Pipe::connect_to_buffer(&reader, Arc::clone(&buffer), cb_queue);
502 pipe::Pipe::connect_to_buffer(&writer, Arc::clone(&buffer), cb_queue);
503 });
504
505 let mut reader_desc = Descriptor::new(CompatFile::New(OpenFile::new(File::Pipe(reader))));
507 let mut writer_desc = Descriptor::new(CompatFile::New(OpenFile::new(File::Pipe(writer))));
508
509 reader_desc.set_flags(descriptor_flags);
511 writer_desc.set_flags(descriptor_flags);
512
513 let mut dt = ctx.objs.thread.descriptor_table_borrow_mut(ctx.objs.host);
515 let read_fd = dt.register_descriptor(reader_desc).unwrap();
518 let write_fd = dt.register_descriptor(writer_desc).unwrap();
519
520 let fds = [i32::from(read_fd), i32::from(write_fd)];
522 let write_res = ctx.objs.process.memory_borrow_mut().write(fd_ptr, &fds);
523
524 match write_res {
526 Ok(_) => Ok(()),
527 Err(e) => {
528 let dont_drop_locks = DropPosixRecordLocks::False;
531 CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
532 dt.deregister_descriptor(read_fd).unwrap().close(
534 ctx.objs.host,
535 dont_drop_locks,
536 cb_queue,
537 );
538 dt.deregister_descriptor(write_fd).unwrap().close(
539 ctx.objs.host,
540 dont_drop_locks,
541 cb_queue,
542 );
543 });
544 Err(e.into())
545 }
546 }
547 }
548
549 log_syscall!(getpid, linux_api::posix_types::kernel_pid_t);
550 pub fn getpid(ctx: &mut SyscallContext) -> Result<kernel_pid_t, SyscallError> {
551 Ok(ctx.objs.process.id().into())
552 }
553
554 log_syscall!(getppid, linux_api::posix_types::kernel_pid_t);
555 pub fn getppid(ctx: &mut SyscallContext) -> Result<kernel_pid_t, SyscallError> {
556 Ok(ctx.objs.process.parent_id().into())
557 }
558
559 log_syscall!(getpgrp, kernel_pid_t);
560 pub fn getpgrp(ctx: &mut SyscallContext) -> Result<kernel_pid_t, SyscallError> {
561 Ok(ctx.objs.process.group_id().into())
562 }
563
564 log_syscall!(
565 getpgid,
566 kernel_pid_t,
567 kernel_pid_t,
568 );
569 pub fn getpgid(
570 ctx: &mut SyscallContext,
571 pid: kernel_pid_t,
572 ) -> Result<kernel_pid_t, SyscallError> {
573 if pid == 0 || pid == kernel_pid_t::from(ctx.objs.process.id()) {
574 return Ok(ctx.objs.process.group_id().into());
575 }
576 let pid = ProcessId::try_from(pid).map_err(|_| Errno::EINVAL)?;
577 let Some(process) = ctx.objs.host.process_borrow(pid) else {
578 return Err(Errno::ESRCH.into());
579 };
580 let process = process.borrow(ctx.objs.host.root());
581 Ok(process.group_id().into())
582 }
583
584 log_syscall!(
585 setpgid,
586 std::ffi::c_int,
587 kernel_pid_t,
588 kernel_pid_t,
589 );
590 pub fn setpgid(
591 ctx: &mut SyscallContext,
592 pid: kernel_pid_t,
593 pgid: kernel_pid_t,
594 ) -> Result<(), SyscallError> {
595 let _processrc_borrow;
596 let _process_borrow;
597 let process: &Process;
598 if pid == 0 || pid == kernel_pid_t::from(ctx.objs.process.id()) {
599 _processrc_borrow = None;
600 _process_borrow = None;
601 process = ctx.objs.process;
602 } else {
603 let pid = ProcessId::try_from(pid).map_err(|_| Errno::EINVAL)?;
604 let Some(pbrc) = ctx.objs.host.process_borrow(pid) else {
605 return Err(Errno::ESRCH.into());
606 };
607 _processrc_borrow = Some(pbrc);
608 _process_borrow = Some(
609 _processrc_borrow
610 .as_ref()
611 .unwrap()
612 .borrow(ctx.objs.host.root()),
613 );
614 process = _process_borrow.as_ref().unwrap();
615 }
616 let pgid = if pgid == 0 {
617 None
618 } else {
619 Some(ProcessId::try_from(pgid).map_err(|_| Errno::EINVAL)?)
620 };
621 if process.id() != ctx.objs.process.id() && process.parent_id() != ctx.objs.process.id() {
622 return Err(Errno::ESRCH.into());
625 }
626 if let Some(pgid) = pgid
627 && ctx.objs.host.process_session_id_of_group_id(pgid) != Some(process.session_id())
628 {
629 return Err(Errno::EPERM.into());
632 }
633 if process.session_id() != ctx.objs.process.session_id() {
634 return Err(Errno::EPERM.into());
638 }
639 if process.session_id() == process.id() {
640 return Err(Errno::EPERM.into());
642 }
643 if let Some(pgid) = pgid {
648 if ctx.objs.host.process_session_id_of_group_id(pgid) != Some(process.session_id()) {
649 return Err(Errno::EPERM.into());
652 }
653 process.set_group_id(pgid);
654 } else {
655 process.set_group_id(process.id());
658 }
659 Ok(())
660 }
661
662 log_syscall!(
663 getsid,
664 kernel_pid_t,
665 kernel_pid_t,
666 );
667 pub fn getsid(
668 ctx: &mut SyscallContext,
669 pid: kernel_pid_t,
670 ) -> Result<kernel_pid_t, SyscallError> {
671 if pid == 0 {
672 return Ok(ctx.objs.process.session_id().into());
673 }
674 let Ok(pid) = ProcessId::try_from(pid) else {
675 return Err(Errno::EINVAL.into());
676 };
677 let Some(processrc) = ctx.objs.host.process_borrow(pid) else {
678 return Err(Errno::ESRCH.into());
679 };
680 let process = processrc.borrow(ctx.objs.host.root());
681 Ok(process.session_id().into())
688 }
689
690 log_syscall!(setsid, kernel_pid_t);
691 pub fn setsid(ctx: &mut SyscallContext) -> Result<kernel_pid_t, SyscallError> {
692 let pid = ctx.objs.process.id();
693 if ctx.objs.host.process_session_id_of_group_id(pid).is_some() {
694 return Err(Errno::EPERM.into());
698 }
699
700 ctx.objs.process.set_session_id(pid);
703
704 ctx.objs.process.set_group_id(pid);
708
709 Ok(pid.into())
710 }
711
712 fn execve_common(
713 ctx: &mut SyscallContext,
714 base_dir: &CStr,
715 path: &CStr,
716 argv_ptr_ptr: ForeignPtr<ForeignPtr<std::ffi::c_char>>,
717 envv_ptr_ptr: ForeignPtr<ForeignPtr<std::ffi::c_char>>,
718 _flags: std::ffi::c_int,
719 ) -> Result<(), SyscallError> {
720 if path.is_empty() {
721 return Err(Errno::ENOENT.into());
723 }
724
725 let path_bytes_with_nul = path.to_bytes_with_nul();
726
727 let _abs_path_storage: Option<CString>;
728 let abs_path: &CStr;
729 if path_bytes_with_nul[0] != b'/' {
730 let base_dir_bytes = base_dir.to_bytes();
731
732 let mut tmp = Vec::with_capacity(
735 base_dir_bytes.len() + path_bytes_with_nul.len() + 1,
736 );
737 tmp.extend(base_dir_bytes);
738 tmp.push(b'/');
739 tmp.extend(path_bytes_with_nul);
740
741 _abs_path_storage = Some(CString::from_vec_with_nul(tmp).unwrap());
742 abs_path = _abs_path_storage.as_ref().unwrap();
743 } else {
744 _abs_path_storage = None;
745 abs_path = path;
746 }
747
748 let argv;
760 let envv;
761 {
762 let mem = ctx.objs.process.memory_borrow();
763 argv = read_cstring_vec(&mem, argv_ptr_ptr)?;
764 envv = read_cstring_vec(&mem, envv_ptr_ptr)?;
765 }
766
767 let mthread = ctx
768 .objs
769 .process
770 .borrow_as_runnable()
771 .unwrap()
772 .spawn_mthread_for_exec(ctx.objs.host, abs_path, argv, envv)?;
773
774 {
804 let pid = ctx.objs.process.id();
805 let tid = ctx.objs.thread.id();
806
807 let mthread = RootedRefCell::new(ctx.objs.host.root(), Some(mthread));
814 ctx.objs.host.schedule_task_with_delay(
815 TaskRef::new(move |host| {
816 let mthread = mthread.borrow_mut(host.root()).take().unwrap();
820 let new_tglid = {
823 let Some(processrc) = host.process_borrow(pid) else {
824 log::debug!("Process {pid:?} disappeared before exec could complete");
828 mthread.kill_and_drop();
829 return;
830 };
831 Worker::set_active_process(&processrc);
832 let mut process = processrc.borrow_mut(host.root());
833 process.update_for_exec(host, tid, mthread);
834 Worker::clear_active_process();
835 process.thread_group_leader_id()
836 };
837 host.resume(pid, new_tglid);
838 }),
839 SimulationTime::ZERO,
840 );
841 }
842
843 Err(SyscallError::new_blocked_until(EmulatedTime::MAX, false))
844 }
845
846 log_syscall!(
847 execve,
848 i32,
849 SyscallStringArg,
850 *const std::ffi::c_void,
851 *const std::ffi::c_void,
852 );
853 pub fn execve(
854 ctx: &mut SyscallContext,
855 pathname: ForeignPtr<std::ffi::c_char>,
856 argv: ForeignPtr<ForeignPtr<std::ffi::c_char>>,
857 envp: ForeignPtr<ForeignPtr<std::ffi::c_char>>,
858 ) -> Result<i64, SyscallError> {
859 let mut path_buf = [0u8; linux_api::limits::PATH_MAX];
860 let path_buf_capacity = path_buf.len();
861 let path = ctx.objs.process.memory_borrow().copy_str_from_ptr(
862 &mut path_buf,
863 ForeignArrayPtr::new(pathname.cast::<u8>(), path_buf_capacity),
864 )?;
865
866 Self::execve_common(
867 ctx,
868 &ctx.objs.process.current_working_dir(),
869 path,
870 argv,
871 envp,
872 0,
873 )
874 .map(|_| 0)
875 }
876
877 log_syscall!(
878 execveat,
879 i32,
880 std::ffi::c_int,
881 SyscallStringArg,
882 *const std::ffi::c_void,
883 *const std::ffi::c_void,
884 std::ffi::c_int,
885 );
886 pub fn execveat(
887 _ctx: &mut SyscallContext,
888 _dirfd: std::ffi::c_int,
889 _pathname: ForeignPtr<std::ffi::c_char>,
890 _argv: ForeignPtr<ForeignPtr<std::ffi::c_char>>,
891 _envp: ForeignPtr<ForeignPtr<std::ffi::c_char>>,
892 _flags: std::ffi::c_int,
893 ) -> Result<i64, SyscallError> {
894 Err(Errno::ENOSYS.into())
897 }
898
899 log_syscall!(
900 exit_group,
901 std::ffi::c_int,
902 std::ffi::c_int,
903 );
904 pub fn exit_group(
905 _ctx: &mut SyscallContext,
906 error_code: std::ffi::c_int,
907 ) -> Result<(), SyscallError> {
908 log::trace!("Exit group with exit code {error_code}");
909 Err(SyscallError::Native)
910 }
911
912 log_syscall!(
913 set_tid_address,
914 linux_api::posix_types::kernel_pid_t,
915 *const std::ffi::c_int,
916 );
917 pub fn set_tid_address(
918 ctx: &mut SyscallContext,
919 tid_ptr: ForeignPtr<std::ffi::c_int>,
920 ) -> Result<kernel_pid_t, SyscallError> {
921 ctx.objs
922 .thread
923 .set_tid_address(tid_ptr.cast::<libc::pid_t>());
924 Ok(ctx.objs.thread.id().into())
925 }
926
927 log_syscall!(
928 uname,
929 std::ffi::c_int,
930 *const std::ffi::c_void,
931 );
932 pub fn uname(
933 ctx: &mut SyscallContext,
934 name_ptr: ForeignPtr<linux_api::utsname::new_utsname>,
935 ) -> Result<(), SyscallError> {
936 let mut name: linux_api::utsname::new_utsname = shadow_pod::zeroed();
946
947 let nodename = u8_to_i8_slice(ctx.objs.host.info().name.as_bytes());
948
949 let sysname = u8_to_i8_slice(&b"Linux"[..]);
951 let release = u8_to_i8_slice(&b"6.1.0-25-amd64"[..]);
952 let version = u8_to_i8_slice(&b"#1 SMP PREEMPT_DYNAMIC Debian 6.1.106-3 (2024-08-26)"[..]);
953 let machine = u8_to_i8_slice(&b"x86_64"[..]);
954
955 name.sysname[..sysname.len()].copy_from_slice(sysname);
956 name.nodename[..nodename.len()].copy_from_slice(nodename);
957 name.release[..release.len()].copy_from_slice(release);
958 name.version[..version.len()].copy_from_slice(version);
959 name.machine[..machine.len()].copy_from_slice(machine);
960
961 ctx.objs
962 .process
963 .memory_borrow_mut()
964 .write(name_ptr, &name)?;
965
966 Ok(())
967 }
968
969 log_syscall!(
970 chdir,
971 std::ffi::c_int,
972 SyscallStringArg,
973 );
974 pub fn chdir(
975 ctx: &mut SyscallContext,
976 path: ForeignPtr<std::ffi::c_char>,
977 ) -> Result<(), SyscallError> {
978 let (process, thread) = ctx.objs.split_thread();
982 thread.native_chdir(&process, path)?;
983
984 let procpath = format!("/proc/{}/cwd", thread.native_tid().as_raw_nonzero().get());
996 let newcwd = std::fs::read_link(&procpath)
997 .unwrap_or_else(|e| panic!("Couldn't find new cwd {procpath}: {e:?}"));
998 let mut newcwd = newcwd.into_os_string().into_vec();
999 newcwd.push(0);
1000 let newcwd = CString::from_vec_with_nul(newcwd).unwrap();
1001 process.process.set_current_working_dir(newcwd);
1002 Ok(())
1003 }
1004
1005 log_syscall!(
1006 unlink,
1007 std::ffi::c_int,
1008 SyscallStringArg,
1009 );
1010 pub fn unlink(
1011 _ctx: &mut SyscallContext,
1012 _path: ForeignPtr<std::ffi::c_char>,
1013 ) -> Result<(), SyscallError> {
1014 Err(SyscallError::Native)
1015 }
1016}