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            && let Some(cond) = err.blocked_condition()
225        {
226            cond.set_active_file(file);
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            && let Some(cond) = err.blocked_condition()
279        {
280            cond.set_active_file(file);
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            && let Some(cond) = err.blocked_condition()
345        {
346            cond.set_active_file(file);
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            && let Some(cond) = err.blocked_condition()
400        {
401            cond.set_active_file(file);
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            && ctx.objs.host.process_session_id_of_group_id(pgid) != Some(process.session_id())
615        {
616            return Err(Errno::EPERM.into());
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}