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::pipe;
20use crate::host::descriptor::shared_buf::SharedBuf;
21use crate::host::descriptor::{CompatFile, Descriptor, File, FileMode, FileStatus, OpenFile};
22use crate::host::process::{Process, ProcessId};
23use crate::host::syscall::handler::{SyscallContext, SyscallHandler};
24use crate::host::syscall::io::{IoVec, read_cstring_vec};
25use crate::host::syscall::type_formatting::{SyscallBufferArg, SyscallStringArg};
26use crate::host::syscall::types::{ForeignArrayPtr, SyscallError};
27use crate::utility::callback_queue::CallbackQueue;
28use crate::utility::u8_to_i8_slice;
29
30impl SyscallHandler {
31 log_syscall!(
32 close,
33 std::ffi::c_int,
34 std::ffi::c_int,
35 );
36 pub fn close(ctx: &mut SyscallContext, fd: std::ffi::c_int) -> Result<(), SyscallError> {
37 trace!("Trying to close fd {}", fd);
38
39 let fd = fd.try_into().or(Err(linux_api::errno::Errno::EBADF))?;
40
41 let desc = ctx
45 .objs
46 .thread
47 .descriptor_table_borrow_mut(ctx.objs.host)
48 .deregister_descriptor(fd)
49 .ok_or(linux_api::errno::Errno::EBADF)?;
50
51 CallbackQueue::queue_and_run_with_legacy(|cb_queue| desc.close(ctx.objs.host, cb_queue))
54 .unwrap_or(Ok(()))
55 }
56
57 log_syscall!(
58 dup,
59 std::ffi::c_int,
60 std::ffi::c_int,
61 );
62 pub fn dup(
63 ctx: &mut SyscallContext,
64 fd: std::ffi::c_int,
65 ) -> Result<DescriptorHandle, SyscallError> {
66 let mut desc_table = ctx.objs.thread.descriptor_table_borrow_mut(ctx.objs.host);
68 let desc = Self::get_descriptor(&desc_table, fd)?;
69
70 let new_desc = desc.dup(DescriptorFlags::empty());
72
73 Ok(desc_table
74 .register_descriptor(new_desc)
75 .or(Err(Errno::ENFILE))?)
76 }
77
78 log_syscall!(
79 dup2,
80 std::ffi::c_int,
81 std::ffi::c_int,
82 std::ffi::c_int,
83 );
84 pub fn dup2(
85 ctx: &mut SyscallContext,
86 old_fd: std::ffi::c_int,
87 new_fd: std::ffi::c_int,
88 ) -> Result<DescriptorHandle, SyscallError> {
89 let old_fd = DescriptorHandle::try_from(old_fd).or(Err(Errno::EBADF))?;
90 let new_fd = DescriptorHandle::try_from(new_fd).or(Err(Errno::EBADF))?;
91
92 let mut desc_table = ctx.objs.thread.descriptor_table_borrow_mut(ctx.objs.host);
94 let desc = Self::get_descriptor(&desc_table, old_fd)?;
95
96 if old_fd == new_fd {
99 return Ok(new_fd);
100 }
101
102 let new_desc = desc.dup(DescriptorFlags::empty());
104 let replaced_desc = desc_table.register_descriptor_with_fd(new_desc, new_fd);
105
106 if let Some(replaced_desc) = replaced_desc {
108 CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
111 replaced_desc.close(ctx.objs.host, cb_queue)
112 });
113 }
114
115 Ok(new_fd)
117 }
118
119 log_syscall!(
120 dup3,
121 std::ffi::c_int,
122 std::ffi::c_int,
123 std::ffi::c_int,
124 linux_api::fcntl::OFlag,
125 );
126 pub fn dup3(
127 ctx: &mut SyscallContext,
128 old_fd: std::ffi::c_int,
129 new_fd: std::ffi::c_int,
130 flags: std::ffi::c_int,
131 ) -> Result<DescriptorHandle, SyscallError> {
132 let mut desc_table = ctx.objs.thread.descriptor_table_borrow_mut(ctx.objs.host);
134 let desc = Self::get_descriptor(&desc_table, old_fd)?;
135
136 if old_fd == new_fd {
138 return Err(linux_api::errno::Errno::EINVAL.into());
139 }
140
141 let new_fd = new_fd.try_into().or(Err(linux_api::errno::Errno::EBADF))?;
142
143 let Some(flags) = OFlag::from_bits(flags) else {
144 debug!("Invalid flags: {flags}");
145 return Err(linux_api::errno::Errno::EINVAL.into());
146 };
147
148 let mut descriptor_flags = DescriptorFlags::empty();
149
150 for flag in flags {
152 match flag {
153 OFlag::O_CLOEXEC => descriptor_flags.insert(DescriptorFlags::FD_CLOEXEC),
154 x if x == OFlag::empty() => {
155 }
157 _ => {
158 debug!("Invalid flags for dup3: {flags:?}");
159 return Err(linux_api::errno::Errno::EINVAL.into());
160 }
161 }
162 }
163
164 let new_desc = desc.dup(descriptor_flags);
166 let replaced_desc = desc_table.register_descriptor_with_fd(new_desc, new_fd);
167
168 if let Some(replaced_desc) = replaced_desc {
170 CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
173 replaced_desc.close(ctx.objs.host, cb_queue)
174 });
175 }
176
177 Ok(new_fd)
179 }
180
181 log_syscall!(
182 read,
183 isize,
184 std::ffi::c_int,
185 *const std::ffi::c_void,
186 usize,
187 );
188 pub fn read(
189 ctx: &mut SyscallContext,
190 fd: std::ffi::c_int,
191 buf_ptr: ForeignPtr<u8>,
192 buf_size: usize,
193 ) -> Result<isize, SyscallError> {
194 let file = ctx
197 .objs
198 .thread
199 .syscall_condition()
200 .and_then(|x| x.active_file().cloned());
202
203 let file = match file {
204 Some(x) => x,
206 None => {
208 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
209 match Self::get_descriptor(&desc_table, fd)?.file() {
210 CompatFile::New(file) => file.clone(),
211 CompatFile::Legacy(_) => {
213 drop(desc_table);
214 return Self::legacy_syscall(c::syscallhandler_read, ctx);
215 }
216 }
217 }
218 };
219
220 let mut result = Self::read_helper(ctx, file.inner_file(), buf_ptr, buf_size, None);
221
222 if let Some(err) = result.as_mut().err() {
224 if let Some(cond) = err.blocked_condition() {
225 cond.set_active_file(file);
226 }
227 }
228
229 let bytes_read = result?;
230 Ok(bytes_read)
231 }
232
233 log_syscall!(
234 pread64,
235 isize,
236 std::ffi::c_int,
237 *const std::ffi::c_void,
238 usize,
239 kernel_off_t,
240 );
241 pub fn pread64(
242 ctx: &mut SyscallContext,
243 fd: std::ffi::c_int,
244 buf_ptr: ForeignPtr<u8>,
245 buf_size: usize,
246 offset: kernel_off_t,
247 ) -> Result<isize, SyscallError> {
248 let file = ctx
251 .objs
252 .thread
253 .syscall_condition()
254 .and_then(|x| x.active_file().cloned());
256
257 let file = match file {
258 Some(x) => x,
260 None => {
262 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
263 match Self::get_descriptor(&desc_table, fd)?.file() {
264 CompatFile::New(file) => file.clone(),
265 CompatFile::Legacy(_) => {
267 drop(desc_table);
268 return Self::legacy_syscall(c::syscallhandler_pread64, ctx);
269 }
270 }
271 }
272 };
273
274 let mut result = Self::read_helper(ctx, file.inner_file(), buf_ptr, buf_size, Some(offset));
275
276 if let Some(err) = result.as_mut().err() {
278 if let Some(cond) = err.blocked_condition() {
279 cond.set_active_file(file);
280 }
281 }
282
283 let bytes_read = result?;
284 Ok(bytes_read)
285 }
286
287 fn read_helper(
288 ctx: &mut SyscallContext,
289 file: &File,
290 buf_ptr: ForeignPtr<u8>,
291 buf_size: usize,
292 offset: Option<kernel_off_t>,
293 ) -> Result<isize, SyscallError> {
294 let iov = IoVec {
295 base: buf_ptr,
296 len: buf_size,
297 };
298 Self::readv_helper(ctx, file, &[iov], offset, 0)
299 }
300
301 log_syscall!(
302 write,
303 isize,
304 std::ffi::c_int,
305 SyscallBufferArg<2>,
306 usize,
307 );
308 pub fn write(
309 ctx: &mut SyscallContext,
310 fd: std::ffi::c_int,
311 buf_ptr: ForeignPtr<u8>,
312 buf_size: usize,
313 ) -> Result<isize, SyscallError> {
314 let file = ctx
317 .objs
318 .thread
319 .syscall_condition()
320 .and_then(|x| x.active_file().cloned());
322
323 let file = match file {
324 Some(x) => x,
326 None => {
328 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
329 match Self::get_descriptor(&desc_table, fd)?.file() {
330 CompatFile::New(file) => file.clone(),
331 CompatFile::Legacy(_) => {
333 drop(desc_table);
334 return Self::legacy_syscall(c::syscallhandler_write, ctx);
335 }
336 }
337 }
338 };
339
340 let mut result = Self::write_helper(ctx, file.inner_file(), buf_ptr, buf_size, None);
341
342 if let Some(err) = result.as_mut().err() {
344 if let Some(cond) = err.blocked_condition() {
345 cond.set_active_file(file);
346 }
347 }
348
349 let bytes_written = result?;
350 Ok(bytes_written)
351 }
352
353 log_syscall!(
354 pwrite64,
355 isize,
356 std::ffi::c_int,
357 SyscallBufferArg<2>,
358 usize,
359 kernel_off_t,
360 );
361 pub fn pwrite64(
362 ctx: &mut SyscallContext,
363 fd: std::ffi::c_int,
364 buf_ptr: ForeignPtr<u8>,
365 buf_size: usize,
366 offset: kernel_off_t,
367 ) -> Result<isize, SyscallError> {
368 let file = ctx
371 .objs
372 .thread
373 .syscall_condition()
374 .and_then(|x| x.active_file().cloned());
376
377 let file = match file {
378 Some(x) => x,
380 None => {
382 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
383 match Self::get_descriptor(&desc_table, fd)?.file() {
384 CompatFile::New(file) => file.clone(),
385 CompatFile::Legacy(_) => {
387 drop(desc_table);
388 return Self::legacy_syscall(c::syscallhandler_pwrite64, ctx);
389 }
390 }
391 }
392 };
393
394 let mut result =
395 Self::write_helper(ctx, file.inner_file(), buf_ptr, buf_size, Some(offset));
396
397 if let Some(err) = result.as_mut().err() {
399 if let Some(cond) = err.blocked_condition() {
400 cond.set_active_file(file);
401 }
402 }
403
404 let bytes_written = result?;
405 Ok(bytes_written)
406 }
407
408 fn write_helper(
409 ctx: &mut SyscallContext,
410 file: &File,
411 buf_ptr: ForeignPtr<u8>,
412 buf_size: usize,
413 offset: Option<kernel_off_t>,
414 ) -> Result<isize, SyscallError> {
415 let iov = IoVec {
416 base: buf_ptr,
417 len: buf_size,
418 };
419 Self::writev_helper(ctx, file, &[iov], offset, 0)
420 }
421
422 log_syscall!(
423 pipe,
424 std::ffi::c_int,
425 [std::ffi::c_int; 2],
426 );
427 pub fn pipe(
428 ctx: &mut SyscallContext,
429 fd_ptr: ForeignPtr<[std::ffi::c_int; 2]>,
430 ) -> Result<(), SyscallError> {
431 Self::pipe_helper(ctx, fd_ptr, 0)
432 }
433
434 log_syscall!(
435 pipe2,
436 std::ffi::c_int,
437 [std::ffi::c_int; 2],
438 linux_api::fcntl::OFlag,
439 );
440 pub fn pipe2(
441 ctx: &mut SyscallContext,
442 fd_ptr: ForeignPtr<[std::ffi::c_int; 2]>,
443 flags: std::ffi::c_int,
444 ) -> Result<(), SyscallError> {
445 Self::pipe_helper(ctx, fd_ptr, flags)
446 }
447
448 fn pipe_helper(
449 ctx: &mut SyscallContext,
450 fd_ptr: ForeignPtr<[std::ffi::c_int; 2]>,
451 flags: i32,
452 ) -> Result<(), SyscallError> {
453 if fd_ptr.is_null() {
455 return Err(linux_api::errno::Errno::EFAULT.into());
456 }
457
458 let Some(flags) = OFlag::from_bits(flags) else {
459 debug!("Invalid flags: {flags}");
460 return Err(Errno::EINVAL.into());
461 };
462
463 let mut file_flags = FileStatus::empty();
464 let mut descriptor_flags = DescriptorFlags::empty();
465
466 for flag in flags.iter() {
467 match flag {
468 OFlag::O_NONBLOCK => file_flags.insert(FileStatus::NONBLOCK),
469 OFlag::O_DIRECT => file_flags.insert(FileStatus::DIRECT),
470 OFlag::O_CLOEXEC => descriptor_flags.insert(DescriptorFlags::FD_CLOEXEC),
471 x if x == OFlag::empty() => {
472 }
474 unhandled => {
475 warn!("Ignoring pipe flag {unhandled:?}");
477 }
478 }
479 }
480
481 let buffer = SharedBuf::new(c::CONFIG_PIPE_BUFFER_SIZE.try_into().unwrap());
483 let buffer = Arc::new(AtomicRefCell::new(buffer));
484
485 let reader = pipe::Pipe::new(FileMode::READ, file_flags);
487 let reader = Arc::new(AtomicRefCell::new(reader));
488
489 let writer = pipe::Pipe::new(FileMode::WRITE, file_flags);
491 let writer = Arc::new(AtomicRefCell::new(writer));
492
493 CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
495 pipe::Pipe::connect_to_buffer(&reader, Arc::clone(&buffer), cb_queue);
496 pipe::Pipe::connect_to_buffer(&writer, Arc::clone(&buffer), cb_queue);
497 });
498
499 let mut reader_desc = Descriptor::new(CompatFile::New(OpenFile::new(File::Pipe(reader))));
501 let mut writer_desc = Descriptor::new(CompatFile::New(OpenFile::new(File::Pipe(writer))));
502
503 reader_desc.set_flags(descriptor_flags);
505 writer_desc.set_flags(descriptor_flags);
506
507 let mut dt = ctx.objs.thread.descriptor_table_borrow_mut(ctx.objs.host);
509 let read_fd = dt.register_descriptor(reader_desc).unwrap();
512 let write_fd = dt.register_descriptor(writer_desc).unwrap();
513
514 let fds = [i32::from(read_fd), i32::from(write_fd)];
516 let write_res = ctx.objs.process.memory_borrow_mut().write(fd_ptr, &fds);
517
518 match write_res {
520 Ok(_) => Ok(()),
521 Err(e) => {
522 CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
523 dt.deregister_descriptor(read_fd)
525 .unwrap()
526 .close(ctx.objs.host, cb_queue);
527 dt.deregister_descriptor(write_fd)
528 .unwrap()
529 .close(ctx.objs.host, cb_queue);
530 });
531 Err(e.into())
532 }
533 }
534 }
535
536 log_syscall!(getpid, linux_api::posix_types::kernel_pid_t);
537 pub fn getpid(ctx: &mut SyscallContext) -> Result<kernel_pid_t, SyscallError> {
538 Ok(ctx.objs.process.id().into())
539 }
540
541 log_syscall!(getppid, linux_api::posix_types::kernel_pid_t);
542 pub fn getppid(ctx: &mut SyscallContext) -> Result<kernel_pid_t, SyscallError> {
543 Ok(ctx.objs.process.parent_id().into())
544 }
545
546 log_syscall!(getpgrp, kernel_pid_t);
547 pub fn getpgrp(ctx: &mut SyscallContext) -> Result<kernel_pid_t, SyscallError> {
548 Ok(ctx.objs.process.group_id().into())
549 }
550
551 log_syscall!(
552 getpgid,
553 kernel_pid_t,
554 kernel_pid_t,
555 );
556 pub fn getpgid(
557 ctx: &mut SyscallContext,
558 pid: kernel_pid_t,
559 ) -> Result<kernel_pid_t, SyscallError> {
560 if pid == 0 || pid == kernel_pid_t::from(ctx.objs.process.id()) {
561 return Ok(ctx.objs.process.group_id().into());
562 }
563 let pid = ProcessId::try_from(pid).map_err(|_| Errno::EINVAL)?;
564 let Some(process) = ctx.objs.host.process_borrow(pid) else {
565 return Err(Errno::ESRCH.into());
566 };
567 let process = process.borrow(ctx.objs.host.root());
568 Ok(process.group_id().into())
569 }
570
571 log_syscall!(
572 setpgid,
573 std::ffi::c_int,
574 kernel_pid_t,
575 kernel_pid_t,
576 );
577 pub fn setpgid(
578 ctx: &mut SyscallContext,
579 pid: kernel_pid_t,
580 pgid: kernel_pid_t,
581 ) -> Result<(), SyscallError> {
582 let _processrc_borrow;
583 let _process_borrow;
584 let process: &Process;
585 if pid == 0 || pid == kernel_pid_t::from(ctx.objs.process.id()) {
586 _processrc_borrow = None;
587 _process_borrow = None;
588 process = ctx.objs.process;
589 } else {
590 let pid = ProcessId::try_from(pid).map_err(|_| Errno::EINVAL)?;
591 let Some(pbrc) = ctx.objs.host.process_borrow(pid) else {
592 return Err(Errno::ESRCH.into());
593 };
594 _processrc_borrow = Some(pbrc);
595 _process_borrow = Some(
596 _processrc_borrow
597 .as_ref()
598 .unwrap()
599 .borrow(ctx.objs.host.root()),
600 );
601 process = _process_borrow.as_ref().unwrap();
602 }
603 let pgid = if pgid == 0 {
604 None
605 } else {
606 Some(ProcessId::try_from(pgid).map_err(|_| Errno::EINVAL)?)
607 };
608 if process.id() != ctx.objs.process.id() && process.parent_id() != ctx.objs.process.id() {
609 return Err(Errno::ESRCH.into());
612 }
613 if let Some(pgid) = pgid {
614 if ctx.objs.host.process_session_id_of_group_id(pgid) != Some(process.session_id()) {
615 return Err(Errno::EPERM.into());
618 }
619 }
620 if process.session_id() != ctx.objs.process.session_id() {
621 return Err(Errno::EPERM.into());
625 }
626 if process.session_id() == process.id() {
627 return Err(Errno::EPERM.into());
629 }
630 if let Some(pgid) = pgid {
635 if ctx.objs.host.process_session_id_of_group_id(pgid) != Some(process.session_id()) {
636 return Err(Errno::EPERM.into());
639 }
640 process.set_group_id(pgid);
641 } else {
642 process.set_group_id(process.id());
645 }
646 Ok(())
647 }
648
649 log_syscall!(
650 getsid,
651 kernel_pid_t,
652 kernel_pid_t,
653 );
654 pub fn getsid(
655 ctx: &mut SyscallContext,
656 pid: kernel_pid_t,
657 ) -> Result<kernel_pid_t, SyscallError> {
658 if pid == 0 {
659 return Ok(ctx.objs.process.session_id().into());
660 }
661 let Ok(pid) = ProcessId::try_from(pid) else {
662 return Err(Errno::EINVAL.into());
663 };
664 let Some(processrc) = ctx.objs.host.process_borrow(pid) else {
665 return Err(Errno::ESRCH.into());
666 };
667 let process = processrc.borrow(ctx.objs.host.root());
668 Ok(process.session_id().into())
675 }
676
677 log_syscall!(setsid, kernel_pid_t);
678 pub fn setsid(ctx: &mut SyscallContext) -> Result<kernel_pid_t, SyscallError> {
679 let pid = ctx.objs.process.id();
680 if ctx.objs.host.process_session_id_of_group_id(pid).is_some() {
681 return Err(Errno::EPERM.into());
685 }
686
687 ctx.objs.process.set_session_id(pid);
690
691 ctx.objs.process.set_group_id(pid);
695
696 Ok(pid.into())
697 }
698
699 fn execve_common(
700 ctx: &mut SyscallContext,
701 base_dir: &CStr,
702 path: &CStr,
703 argv_ptr_ptr: ForeignPtr<ForeignPtr<std::ffi::c_char>>,
704 envv_ptr_ptr: ForeignPtr<ForeignPtr<std::ffi::c_char>>,
705 _flags: std::ffi::c_int,
706 ) -> Result<(), SyscallError> {
707 if path.is_empty() {
708 return Err(Errno::ENOENT.into());
710 }
711
712 let path_bytes_with_nul = path.to_bytes_with_nul();
713
714 let _abs_path_storage: Option<CString>;
715 let abs_path: &CStr;
716 if path_bytes_with_nul[0] != b'/' {
717 let base_dir_bytes = base_dir.to_bytes();
718
719 let mut tmp = Vec::with_capacity(
722 base_dir_bytes.len() + path_bytes_with_nul.len() + 1,
723 );
724 tmp.extend(base_dir_bytes);
725 tmp.push(b'/');
726 tmp.extend(path_bytes_with_nul);
727
728 _abs_path_storage = Some(CString::from_vec_with_nul(tmp).unwrap());
729 abs_path = _abs_path_storage.as_ref().unwrap();
730 } else {
731 _abs_path_storage = None;
732 abs_path = path;
733 }
734
735 let argv;
747 let envv;
748 {
749 let mem = ctx.objs.process.memory_borrow();
750 argv = read_cstring_vec(&mem, argv_ptr_ptr)?;
751 envv = read_cstring_vec(&mem, envv_ptr_ptr)?;
752 }
753
754 let mthread = ctx
755 .objs
756 .process
757 .borrow_as_runnable()
758 .unwrap()
759 .spawn_mthread_for_exec(ctx.objs.host, abs_path, argv, envv)?;
760
761 {
791 let pid = ctx.objs.process.id();
792 let tid = ctx.objs.thread.id();
793
794 let mthread = RootedRefCell::new(ctx.objs.host.root(), Some(mthread));
801 ctx.objs.host.schedule_task_with_delay(
802 TaskRef::new(move |host| {
803 let mthread = mthread.borrow_mut(host.root()).take().unwrap();
807 let new_tglid = {
810 let Some(processrc) = host.process_borrow(pid) else {
811 log::debug!("Process {pid:?} disappeared before exec could complete");
815 mthread.kill_and_drop();
816 return;
817 };
818 Worker::set_active_process(&processrc);
819 let mut process = processrc.borrow_mut(host.root());
820 process.update_for_exec(host, tid, mthread);
821 Worker::clear_active_process();
822 process.thread_group_leader_id()
823 };
824 host.resume(pid, new_tglid);
825 }),
826 SimulationTime::ZERO,
827 );
828 }
829
830 Err(SyscallError::new_blocked_until(EmulatedTime::MAX, false))
831 }
832
833 log_syscall!(
834 execve,
835 i32,
836 SyscallStringArg,
837 *const std::ffi::c_void,
838 *const std::ffi::c_void,
839 );
840 pub fn execve(
841 ctx: &mut SyscallContext,
842 pathname: ForeignPtr<std::ffi::c_char>,
843 argv: ForeignPtr<ForeignPtr<std::ffi::c_char>>,
844 envp: ForeignPtr<ForeignPtr<std::ffi::c_char>>,
845 ) -> Result<i64, SyscallError> {
846 let mut path_buf = [0u8; linux_api::limits::PATH_MAX];
847 let path_buf_capacity = path_buf.len();
848 let path = ctx.objs.process.memory_borrow().copy_str_from_ptr(
849 &mut path_buf,
850 ForeignArrayPtr::new(pathname.cast::<u8>(), path_buf_capacity),
851 )?;
852
853 Self::execve_common(
854 ctx,
855 &ctx.objs.process.current_working_dir(),
856 path,
857 argv,
858 envp,
859 0,
860 )
861 .map(|_| 0)
862 }
863
864 log_syscall!(
865 execveat,
866 i32,
867 std::ffi::c_int,
868 SyscallStringArg,
869 *const std::ffi::c_void,
870 *const std::ffi::c_void,
871 std::ffi::c_int,
872 );
873 pub fn execveat(
874 _ctx: &mut SyscallContext,
875 _dirfd: std::ffi::c_int,
876 _pathname: ForeignPtr<std::ffi::c_char>,
877 _argv: ForeignPtr<ForeignPtr<std::ffi::c_char>>,
878 _envp: ForeignPtr<ForeignPtr<std::ffi::c_char>>,
879 _flags: std::ffi::c_int,
880 ) -> Result<i64, SyscallError> {
881 Err(Errno::ENOSYS.into())
884 }
885
886 log_syscall!(
887 exit_group,
888 std::ffi::c_int,
889 std::ffi::c_int,
890 );
891 pub fn exit_group(
892 _ctx: &mut SyscallContext,
893 error_code: std::ffi::c_int,
894 ) -> Result<(), SyscallError> {
895 log::trace!("Exit group with exit code {error_code}");
896 Err(SyscallError::Native)
897 }
898
899 log_syscall!(
900 set_tid_address,
901 linux_api::posix_types::kernel_pid_t,
902 *const std::ffi::c_int,
903 );
904 pub fn set_tid_address(
905 ctx: &mut SyscallContext,
906 tid_ptr: ForeignPtr<std::ffi::c_int>,
907 ) -> Result<kernel_pid_t, SyscallError> {
908 ctx.objs
909 .thread
910 .set_tid_address(tid_ptr.cast::<libc::pid_t>());
911 Ok(ctx.objs.thread.id().into())
912 }
913
914 log_syscall!(
915 uname,
916 std::ffi::c_int,
917 *const std::ffi::c_void,
918 );
919 pub fn uname(
920 ctx: &mut SyscallContext,
921 name_ptr: ForeignPtr<linux_api::utsname::new_utsname>,
922 ) -> Result<(), SyscallError> {
923 let mut name: linux_api::utsname::new_utsname = shadow_pod::zeroed();
933
934 let nodename = u8_to_i8_slice(ctx.objs.host.info().name.as_bytes());
935
936 let sysname = u8_to_i8_slice(&b"Linux"[..]);
938 let release = u8_to_i8_slice(&b"6.1.0-25-amd64"[..]);
939 let version = u8_to_i8_slice(&b"#1 SMP PREEMPT_DYNAMIC Debian 6.1.106-3 (2024-08-26)"[..]);
940 let machine = u8_to_i8_slice(&b"x86_64"[..]);
941
942 name.sysname[..sysname.len()].copy_from_slice(sysname);
943 name.nodename[..nodename.len()].copy_from_slice(nodename);
944 name.release[..release.len()].copy_from_slice(release);
945 name.version[..version.len()].copy_from_slice(version);
946 name.machine[..machine.len()].copy_from_slice(machine);
947
948 ctx.objs
949 .process
950 .memory_borrow_mut()
951 .write(name_ptr, &name)?;
952
953 Ok(())
954 }
955
956 log_syscall!(
957 chdir,
958 std::ffi::c_int,
959 SyscallStringArg,
960 );
961 pub fn chdir(
962 ctx: &mut SyscallContext,
963 path: ForeignPtr<std::ffi::c_char>,
964 ) -> Result<(), SyscallError> {
965 let (process, thread) = ctx.objs.split_thread();
969 thread.native_chdir(&process, path)?;
970
971 let procpath = format!("/proc/{}/cwd", thread.native_tid().as_raw_nonzero().get());
983 let newcwd = std::fs::read_link(&procpath)
984 .unwrap_or_else(|e| panic!("Couldn't find new cwd {procpath}: {e:?}"));
985 let mut newcwd = newcwd.into_os_string().into_vec();
986 newcwd.push(0);
987 let newcwd = CString::from_vec_with_nul(newcwd).unwrap();
988 process.process.set_current_working_dir(newcwd);
989 Ok(())
990 }
991}