1use std::cell::{Cell, Ref, RefCell, RefMut};
4use std::collections::BTreeMap;
5use std::ffi::{CStr, CString, c_char, c_void};
6use std::fmt::Write;
7use std::num::TryFromIntError;
8use std::ops::{Deref, DerefMut};
9use std::os::fd::AsRawFd;
10use std::path::{Path, PathBuf};
11use std::sync::Arc;
12use std::sync::atomic::Ordering;
13#[cfg(feature = "perf_timers")]
14use std::time::Duration;
15
16use linux_api::errno::Errno;
17use linux_api::fcntl::OFlag;
18use linux_api::posix_types::Pid;
19use linux_api::sched::{CloneFlags, SuidDump};
20use linux_api::signal::{
21 LinuxDefaultAction, SigActionFlags, Signal, SignalFromI32Error, defaultaction, siginfo_t,
22 sigset_t,
23};
24use log::{debug, trace, warn};
25use rustix::process::{WaitOptions, WaitStatus};
26use shadow_shim_helper_rs::HostId;
27use shadow_shim_helper_rs::explicit_drop::{ExplicitDrop, ExplicitDropper};
28use shadow_shim_helper_rs::rootedcell::Root;
29use shadow_shim_helper_rs::rootedcell::rc::RootedRc;
30use shadow_shim_helper_rs::rootedcell::refcell::RootedRefCell;
31use shadow_shim_helper_rs::shim_shmem::ProcessShmem;
32use shadow_shim_helper_rs::simulation_time::SimulationTime;
33use shadow_shim_helper_rs::syscall_types::{ForeignPtr, ManagedPhysicalMemoryAddr};
34use shadow_shmem::allocator::ShMemBlock;
35
36use super::descriptor::descriptor_table::{DescriptorHandle, DescriptorTable};
37use super::descriptor::listener::StateEventSource;
38use super::descriptor::{FileSignals, FileState};
39use super::host::Host;
40use super::memory_manager::{MemoryManager, ProcessMemoryRef, ProcessMemoryRefMut};
41use super::syscall::formatter::StraceFmtMode;
42use super::syscall::types::ForeignArrayPtr;
43use super::thread::{Thread, ThreadId};
44use super::timer::Timer;
45use crate::core::configuration::{ProcessFinalState, RunningVal};
46use crate::core::work::task::TaskRef;
47use crate::core::worker::Worker;
48use crate::cshadow;
49use crate::host::context::ProcessContext;
50use crate::host::descriptor::Descriptor;
51use crate::host::managed_thread::ManagedThread;
52use crate::host::syscall::formatter::FmtOptions;
53use crate::utility::callback_queue::CallbackQueue;
54#[cfg(feature = "perf_timers")]
55use crate::utility::perf_timer::PerfTimer;
56use crate::utility::{self, debug_assert_cloexec};
57
58#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Ord, PartialOrd)]
60pub struct ProcessId(u32);
61
62impl ProcessId {
63 pub const INIT: Self = ProcessId(1);
67
68 pub fn from_thread_group_leader_tid(thread_group_leader_tid: ThreadId) -> Self {
71 ProcessId::try_from(libc::pid_t::from(thread_group_leader_tid)).unwrap()
72 }
73}
74
75impl std::fmt::Display for ProcessId {
76 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
77 write!(f, "{}", self.0)
78 }
79}
80
81impl TryFrom<u32> for ProcessId {
82 type Error = TryFromIntError;
83
84 fn try_from(val: u32) -> Result<Self, Self::Error> {
85 let _ = libc::pid_t::try_from(val)?;
88 Ok(ProcessId(val))
89 }
90}
91
92impl TryFrom<libc::pid_t> for ProcessId {
93 type Error = TryFromIntError;
94
95 fn try_from(value: libc::pid_t) -> Result<Self, Self::Error> {
96 Ok(ProcessId(value.try_into()?))
97 }
98}
99
100impl From<ProcessId> for u32 {
101 fn from(val: ProcessId) -> Self {
102 val.0
103 }
104}
105
106impl From<ProcessId> for libc::pid_t {
107 fn from(val: ProcessId) -> Self {
108 val.0.try_into().unwrap()
109 }
110}
111
112impl From<ThreadId> for ProcessId {
113 fn from(value: ThreadId) -> Self {
114 ProcessId::try_from(libc::pid_t::from(value)).unwrap()
115 }
116}
117
118#[derive(Debug, Copy, Clone, Eq, PartialEq)]
119pub enum ExitStatus {
120 Normal(i32),
121 Signaled(Signal),
122 StoppedByShadow,
131}
132
133#[derive(Debug)]
134struct StraceLogging {
135 file: RootedRefCell<std::fs::File>,
136 options: FmtOptions,
137}
138
139struct Common {
141 id: ProcessId,
142 host_id: HostId,
143
144 parent_pid: Cell<ProcessId>,
147
148 group_id: Cell<ProcessId>,
150
151 session_id: Cell<ProcessId>,
153
154 exit_signal: Option<Signal>,
156
157 name: CString,
159
160 plugin_name: CString,
162
163 working_dir: CString,
167}
168
169impl Common {
170 fn id(&self) -> ProcessId {
171 self.id
172 }
173
174 fn physical_address(&self, vptr: ForeignPtr<()>) -> ManagedPhysicalMemoryAddr {
175 const PADDR_BITS: i32 = 64;
196 const VADDR_BITS: i32 = 48;
197 const PID_BITS: i32 = 16;
198 assert_eq!(PADDR_BITS, PID_BITS + VADDR_BITS);
199
200 let high_part: u64 = u64::from(u32::from(self.id())) << VADDR_BITS;
201 assert_eq!(
202 ProcessId::try_from((high_part >> VADDR_BITS) as u32),
203 Ok(self.id())
204 );
205
206 let low_part = u64::from(vptr);
207 assert_eq!(low_part >> VADDR_BITS, 0);
208
209 ManagedPhysicalMemoryAddr::from(high_part | low_part)
210 }
211
212 fn name(&self) -> &str {
213 self.name.to_str().unwrap()
214 }
215
216 pub fn thread_group_leader_id(&self) -> ThreadId {
217 ThreadId::from(self.id())
219 }
220}
221
222pub struct RunnableProcess {
224 common: Common,
225
226 expected_final_state: Option<ProcessFinalState>,
233
234 shim_shared_mem_block: ShMemBlock<'static, ProcessShmem>,
236
237 strace_logging: Option<Arc<StraceLogging>>,
239
240 shimlog_file: Arc<std::fs::File>,
247
248 dumpable: Cell<SuidDump>,
251
252 native_pid: Pid,
253
254 #[cfg(feature = "perf_timers")]
256 cpu_delay_timer: RefCell<PerfTimer>,
257 #[cfg(feature = "perf_timers")]
258 total_run_time: Cell<Duration>,
259
260 itimer_real: RefCell<Timer>,
261
262 threads: RefCell<BTreeMap<ThreadId, RootedRc<RootedRefCell<Thread>>>>,
267
268 unsafe_borrow_mut: RefCell<Option<UnsafeBorrowMut>>,
275 unsafe_borrows: RefCell<Vec<UnsafeBorrow>>,
276
277 memory_manager: Box<RefCell<MemoryManager>>,
284
285 child_process_event_listeners: RefCell<StateEventSource>,
288}
289
290impl RunnableProcess {
291 pub fn spawn_mthread_for_exec(
298 &self,
299 host: &Host,
300 plugin_path: &CStr,
301 argv: Vec<CString>,
302 envv: Vec<CString>,
303 ) -> Result<ManagedThread, Errno> {
304 ManagedThread::spawn(
305 plugin_path,
306 argv,
307 envv,
308 self.strace_logging
309 .as_ref()
310 .map(|s| s.file.borrow(host.root()))
311 .as_deref(),
312 &self.shimlog_file,
313 host.preload_paths(),
314 )
315 }
316
317 fn reap_thread(&self, host: &Host, threadrc: RootedRc<RootedRefCell<Thread>>) {
319 let threadrc = ExplicitDropper::new(threadrc, |t| {
320 t.explicit_drop_recursive(host.root(), host);
321 });
322 let thread = threadrc.borrow(host.root());
323
324 assert!(!thread.is_running());
325
326 let clear_child_tid_pvp = thread.get_tid_address();
331 if !clear_child_tid_pvp.is_null() && !self.threads.borrow().is_empty() {
332 self.memory_manager
333 .borrow_mut()
334 .write(clear_child_tid_pvp, &0)
335 .unwrap();
336
337 let futexes = host.futextable_borrow();
339 let addr = self
340 .common
341 .physical_address(clear_child_tid_pvp.cast::<()>());
342
343 if let Some(futex) = futexes.get(addr) {
344 futex.wake(1);
345 }
346 }
347 }
348
349 pub fn free_unsafe_borrows_flush(&self) -> Result<(), Errno> {
355 self.unsafe_borrows.borrow_mut().clear();
356
357 let unsafe_borrow_mut = self.unsafe_borrow_mut.borrow_mut().take();
358 if let Some(borrow) = unsafe_borrow_mut {
359 borrow.flush()
360 } else {
361 Ok(())
362 }
363 }
364
365 pub fn free_unsafe_borrows_noflush(&self) {
370 self.unsafe_borrows.borrow_mut().clear();
371
372 let unsafe_borrow_mut = self.unsafe_borrow_mut.borrow_mut().take();
373 if let Some(borrow) = unsafe_borrow_mut {
374 borrow.noflush();
375 }
376 }
377
378 #[track_caller]
379 pub fn memory_borrow(&self) -> impl Deref<Target = MemoryManager> + '_ {
380 self.memory_manager.borrow()
381 }
382
383 #[track_caller]
384 pub fn memory_borrow_mut(&self) -> impl DerefMut<Target = MemoryManager> + '_ {
385 self.memory_manager.borrow_mut()
386 }
387
388 pub fn strace_logging_options(&self) -> Option<FmtOptions> {
389 self.strace_logging.as_ref().map(|x| x.options)
390 }
391
392 pub fn with_strace_file<T>(&self, f: impl FnOnce(&mut std::fs::File) -> T) -> Option<T> {
394 Worker::with_active_host(|host| {
396 let strace_logging = self.strace_logging.as_ref()?;
397 let mut file = strace_logging.file.borrow_mut(host.root());
398 Some(f(&mut file))
399 })
400 .unwrap()
401 }
402
403 pub fn native_pid(&self) -> Pid {
404 self.native_pid
405 }
406
407 #[track_caller]
408 fn first_live_thread(&self, root: &Root) -> Option<Ref<RootedRc<RootedRefCell<Thread>>>> {
409 Ref::filter_map(self.threads.borrow(), |threads| {
410 threads.values().next().inspect(|thread| {
411 assert!(thread.borrow(root).is_running());
413 })
414 })
415 .ok()
416 }
417
418 #[track_caller]
421 pub fn first_live_thread_borrow(
422 &self,
423 root: &Root,
424 ) -> Option<impl Deref<Target = RootedRc<RootedRefCell<Thread>>> + '_> {
425 self.first_live_thread(root)
426 }
427
428 #[track_caller]
429 fn thread(&self, virtual_tid: ThreadId) -> Option<Ref<RootedRc<RootedRefCell<Thread>>>> {
430 Ref::filter_map(self.threads.borrow(), |threads| threads.get(&virtual_tid)).ok()
431 }
432
433 #[track_caller]
434 pub fn thread_borrow(
435 &self,
436 virtual_tid: ThreadId,
437 ) -> Option<impl Deref<Target = RootedRc<RootedRefCell<Thread>>> + '_> {
438 self.thread(virtual_tid)
439 }
440
441 fn into_common(self) -> Common {
444 assert!(self.unsafe_borrow_mut.take().is_none());
448 assert!(self.unsafe_borrows.take().is_empty());
449
450 self.common
451 }
452
453 #[cfg(feature = "perf_timers")]
456 pub fn start_cpu_delay_timer(&self) {
457 self.cpu_delay_timer.borrow_mut().start()
458 }
459
460 #[cfg(feature = "perf_timers")]
463 pub fn stop_cpu_delay_timer(&self, host: &Host) -> Duration {
464 let mut timer = self.cpu_delay_timer.borrow_mut();
465 timer.stop();
466 let total_elapsed = timer.elapsed();
467 let prev_total = self.total_run_time.replace(total_elapsed);
468 let delta = total_elapsed - prev_total;
469
470 host.cpu_borrow_mut().add_delay(delta);
471
472 delta
473 }
474
475 fn interrupt_with_signal(&self, host: &Host, signal: Signal) {
476 let threads = self.threads.borrow();
477 for thread in threads.values() {
478 let thread = thread.borrow(host.root());
479 {
480 let thread_shmem = thread.shmem();
481 let host_lock = host.shim_shmem_lock_borrow().unwrap();
482 let thread_shmem_protected = thread_shmem.protected.borrow(&host_lock.root);
483 let blocked_signals = thread_shmem_protected.blocked_signals;
484 if blocked_signals.has(signal) {
485 continue;
486 }
487 }
488 let Some(mut cond) = thread.syscall_condition_mut() else {
489 warn!("thread {:?} has no syscall_condition. How?", thread.id());
495 continue;
496 };
497 cond.wakeup_for_signal(host, signal);
498 break;
499 }
500 }
501
502 pub fn signal(&self, host: &Host, current_thread: Option<&Thread>, siginfo_t: &siginfo_t) {
511 let signal = match siginfo_t.signal() {
512 Ok(s) => s,
513 Err(SignalFromI32Error(0)) => return,
514 Err(SignalFromI32Error(n)) => panic!("Bad signo {n}"),
515 };
516
517 {
519 let host_shmem = host.shim_shmem_lock_borrow().unwrap();
520 let mut process_shmem_protected = self
521 .shim_shared_mem_block
522 .protected
523 .borrow_mut(&host_shmem.root);
524 let action = unsafe { process_shmem_protected.signal_action(signal) };
526 match unsafe { action.handler() } {
527 linux_api::signal::SignalHandler::Handler(_) => (),
528 linux_api::signal::SignalHandler::Action(_) => (),
529 linux_api::signal::SignalHandler::SigIgn => return,
530 linux_api::signal::SignalHandler::SigDfl => {
531 if defaultaction(signal) == LinuxDefaultAction::IGN {
532 return;
533 }
534 }
535 }
536
537 if process_shmem_protected.pending_signals.has(signal) {
538 return;
543 }
544 process_shmem_protected.pending_signals.add(signal);
545 process_shmem_protected.set_pending_standard_siginfo(signal, siginfo_t);
546 }
547
548 if let Some(thread) = current_thread {
549 if thread.process_id() == self.common.id() {
550 let host_shmem = host.shim_shmem_lock_borrow().unwrap();
551 let threadmem = thread.shmem();
552 let threadprotmem = threadmem.protected.borrow(&host_shmem.root);
553 if !threadprotmem.blocked_signals.has(signal) {
554 return;
557 }
558 }
559 }
560
561 self.interrupt_with_signal(host, signal);
562 }
563
564 pub fn add_thread(&self, host: &Host, thread: RootedRc<RootedRefCell<Thread>>) {
567 let pid = self.common.id();
568 let tid = thread.borrow(host.root()).id();
569 self.threads.borrow_mut().insert(tid, thread);
570
571 let task = TaskRef::new(move |host| {
575 host.resume(pid, tid);
576 });
577 host.schedule_task_with_delay(task, SimulationTime::ZERO);
578 }
579
580 pub fn new_forked_process(
582 &self,
583 host: &Host,
584 flags: CloneFlags,
585 exit_signal: Option<Signal>,
586 new_thread_group_leader: RootedRc<RootedRefCell<Thread>>,
587 ) -> RootedRc<RootedRefCell<Process>> {
588 let new_tgl_tid;
589 let native_pid;
590 {
591 let new_tgl = new_thread_group_leader.borrow(host.root());
592 new_tgl_tid = new_tgl.id();
593 native_pid = new_tgl.native_pid();
594 }
595 let pid = ProcessId::from_thread_group_leader_tid(new_tgl_tid);
596 assert_eq!(
597 pid,
598 new_thread_group_leader.borrow(host.root()).process_id()
599 );
600 let plugin_name = self.common.plugin_name.clone();
601 let name = make_name(host, plugin_name.to_str().unwrap(), pid);
602
603 let parent_pid = if flags.contains(CloneFlags::CLONE_PARENT) {
604 self.common.parent_pid.get()
605 } else {
606 self.common.id
607 };
608
609 let process_group_id = self.common.group_id.get();
611
612 let session_id = self.common.session_id.get();
614
615 let common = Common {
616 id: pid,
617 host_id: host.id(),
618 name,
619 plugin_name,
620 working_dir: self.common.working_dir.clone(),
621 parent_pid: Cell::new(parent_pid),
622 group_id: Cell::new(process_group_id),
623 session_id: Cell::new(session_id),
624 exit_signal,
625 };
626
627 let strace_logging = self.strace_logging.as_ref().cloned();
630
631 let itimer_real = RefCell::new(Timer::new(move |host| itimer_real_expiration(host, pid)));
635
636 let threads = RefCell::new(BTreeMap::from([(new_tgl_tid, new_thread_group_leader)]));
637
638 let shim_shared_mem = ProcessShmem::new(
639 &host.shim_shmem_lock_borrow().unwrap().root,
640 host.shim_shmem().serialize(),
641 host.id(),
642 strace_logging
643 .as_ref()
644 .map(|x| x.file.borrow(host.root()).as_raw_fd()),
645 );
646 let shim_shared_mem_block = shadow_shmem::allocator::shmalloc(shim_shared_mem);
647
648 let runnable_process = RunnableProcess {
649 common,
650 expected_final_state: None,
651 shim_shared_mem_block,
652 strace_logging,
653 dumpable: self.dumpable.clone(),
654 native_pid,
655 #[cfg(feature = "perf_timers")]
656 cpu_delay_timer: RefCell::new(PerfTimer::new_stopped()),
657 #[cfg(feature = "perf_timers")]
658 total_run_time: Cell::new(Duration::ZERO),
659 itimer_real,
660 threads,
661 unsafe_borrow_mut: RefCell::new(None),
662 unsafe_borrows: RefCell::new(Vec::new()),
663 memory_manager: Box::new(RefCell::new(unsafe { MemoryManager::new(native_pid) })),
664 child_process_event_listeners: Default::default(),
665 shimlog_file: self.shimlog_file.clone(),
666 };
667 let child_process = Process {
668 state: RefCell::new(Some(ProcessState::Runnable(runnable_process))),
669 };
670 RootedRc::new(host.root(), RootedRefCell::new(host.root(), child_process))
671 }
672
673 pub fn shmem(&self) -> impl Deref<Target = ShMemBlock<'static, ProcessShmem>> + '_ {
675 &self.shim_shared_mem_block
676 }
677}
678
679impl ExplicitDrop for RunnableProcess {
680 type ExplicitDropParam = Host;
681 type ExplicitDropResult = ();
682
683 fn explicit_drop(mut self, host: &Self::ExplicitDropParam) -> Self::ExplicitDropResult {
684 let threads = std::mem::take(self.threads.get_mut());
685 for thread in threads.into_values() {
686 thread.explicit_drop_recursive(host.root(), host);
687 }
688 }
689}
690
691pub struct ZombieProcess {
693 common: Common,
694
695 exit_status: ExitStatus,
696}
697
698impl ZombieProcess {
699 pub fn exit_status(&self) -> ExitStatus {
700 self.exit_status
701 }
702
703 pub fn reaper<'host>(
705 &self,
706 host: &'host Host,
707 ) -> Option<impl Deref<Target = RootedRc<RootedRefCell<Process>>> + 'host> {
708 let parent_pid = self.common.parent_pid.get();
709 if parent_pid == ProcessId::INIT {
710 return None;
711 }
712 let parentrc = host.process_borrow(parent_pid)?;
713
714 if let Some(exit_signal) = self.common.exit_signal {
727 let parent = parentrc.borrow(host.root());
728 let parent_shmem = parent.shmem();
729 let host_shmem_lock = host.shim_shmem_lock_borrow().unwrap();
730 let parent_shmem_protected = parent_shmem.protected.borrow(&host_shmem_lock.root);
731 let action = unsafe { parent_shmem_protected.signal_action(exit_signal) };
733 if action.is_ignore() {
734 return None;
735 }
736 }
737
738 Some(parentrc)
739 }
740
741 fn notify_parent_of_exit(&self, host: &Host) {
742 let Some(exit_signal) = self.common.exit_signal else {
743 trace!("Not notifying parent of exit: no signal specified");
744 return;
745 };
746 let parent_pid = self.common.parent_pid.get();
747 if parent_pid == ProcessId::INIT {
748 trace!("Not notifying parent of exit: parent is 'init'");
749 return;
750 }
751 let Some(parent_rc) = host.process_borrow(parent_pid) else {
752 trace!("Not notifying parent of exit: parent {parent_pid:?} not found");
753 return;
754 };
755 let parent = parent_rc.borrow(host.root());
756 let siginfo = self.exit_siginfo(exit_signal);
757
758 let Some(parent_runnable) = parent.as_runnable() else {
759 trace!("Not notifying parent of exit: {parent_pid:?} not running");
760 debug_panic!("Non-running parent process shouldn't be possible.");
761 #[allow(unreachable_code)]
762 {
763 return;
764 }
765 };
766 parent_runnable.signal(host, None, &siginfo);
767 CallbackQueue::queue_and_run_with_legacy(|q| {
768 let mut parent_child_listeners =
769 parent_runnable.child_process_event_listeners.borrow_mut();
770 parent_child_listeners.notify_listeners(
771 FileState::CHILD_EVENT,
772 FileState::CHILD_EVENT,
773 FileSignals::empty(),
774 q,
775 );
776 });
777 }
778
779 pub fn exit_siginfo(&self, exit_signal: Signal) -> siginfo_t {
785 match self.exit_status {
786 ExitStatus::Normal(exit_code) => siginfo_t::new_for_sigchld_exited(
787 exit_signal,
788 self.common.id.into(),
789 0,
790 exit_code,
791 0,
792 0,
793 ),
794 ExitStatus::Signaled(fatal_signal) => {
795 siginfo_t::new_for_sigchld_killed(
800 exit_signal,
801 self.common.id.into(),
802 0,
803 fatal_signal,
804 0,
805 0,
806 )
807 }
808
809 ExitStatus::StoppedByShadow => unreachable!(),
810 }
811 }
812}
813
814enum ProcessState {
816 Runnable(RunnableProcess),
817 Zombie(ZombieProcess),
818}
819
820impl ProcessState {
821 fn common(&self) -> &Common {
822 match self {
823 ProcessState::Runnable(r) => &r.common,
824 ProcessState::Zombie(z) => &z.common,
825 }
826 }
827
828 fn common_mut(&mut self) -> &mut Common {
829 match self {
830 ProcessState::Runnable(r) => &mut r.common,
831 ProcessState::Zombie(z) => &mut z.common,
832 }
833 }
834
835 fn as_runnable(&self) -> Option<&RunnableProcess> {
836 match self {
837 ProcessState::Runnable(r) => Some(r),
838 ProcessState::Zombie(_) => None,
839 }
840 }
841
842 fn as_runnable_mut(&mut self) -> Option<&mut RunnableProcess> {
843 match self {
844 ProcessState::Runnable(r) => Some(r),
845 ProcessState::Zombie(_) => None,
846 }
847 }
848
849 fn as_zombie(&self) -> Option<&ZombieProcess> {
850 match self {
851 ProcessState::Runnable(_) => None,
852 ProcessState::Zombie(z) => Some(z),
853 }
854 }
855}
856
857impl ExplicitDrop for ProcessState {
858 type ExplicitDropParam = Host;
859 type ExplicitDropResult = ();
860
861 fn explicit_drop(self, host: &Self::ExplicitDropParam) -> Self::ExplicitDropResult {
862 match self {
863 ProcessState::Runnable(r) => r.explicit_drop(host),
864 ProcessState::Zombie(_) => (),
865 }
866 }
867}
868
869pub struct Process {
871 state: RefCell<Option<ProcessState>>,
874}
875
876fn itimer_real_expiration(host: &Host, pid: ProcessId) {
877 let Some(process) = host.process_borrow(pid) else {
878 debug!("Process {:?} no longer exists", pid);
879 return;
880 };
881 let process = process.borrow(host.root());
882 let Some(runnable) = process.as_runnable() else {
883 debug!("Process {:?} no longer running", &*process.name());
884 return;
885 };
886 let timer = runnable.itimer_real.borrow();
887 let expiration_count = timer.expiration_count() as i32;
890 let siginfo_t = siginfo_t::new_for_timer(Signal::SIGALRM, 0, expiration_count);
891 process.signal(host, None, &siginfo_t);
892}
893
894impl Process {
895 fn common(&self) -> Ref<Common> {
896 Ref::map(self.state.borrow(), |state| {
897 state.as_ref().unwrap().common()
898 })
899 }
900
901 fn common_mut(&self) -> RefMut<Common> {
902 RefMut::map(self.state.borrow_mut(), |state| {
903 state.as_mut().unwrap().common_mut()
904 })
905 }
906
907 fn as_runnable(&self) -> Option<Ref<RunnableProcess>> {
908 Ref::filter_map(self.state.borrow(), |state| {
909 state.as_ref().unwrap().as_runnable()
910 })
911 .ok()
912 }
913
914 fn as_runnable_mut(&self) -> Option<RefMut<RunnableProcess>> {
915 RefMut::filter_map(self.state.borrow_mut(), |state| {
916 state.as_mut().unwrap().as_runnable_mut()
917 })
918 .ok()
919 }
920
921 pub fn borrow_as_runnable(&self) -> Option<impl Deref<Target = RunnableProcess> + '_> {
923 self.as_runnable()
924 }
925
926 fn as_zombie(&self) -> Option<Ref<ZombieProcess>> {
927 Ref::filter_map(self.state.borrow(), |state| {
928 state.as_ref().unwrap().as_zombie()
929 })
930 .ok()
931 }
932
933 pub fn borrow_as_zombie(&self) -> Option<impl Deref<Target = ZombieProcess> + '_> {
935 self.as_zombie()
936 }
937
938 pub fn spawn(
941 host: &Host,
942 plugin_name: CString,
943 plugin_path: &CStr,
944 argv: Vec<CString>,
945 envv: Vec<CString>,
946 pause_for_debugging: bool,
947 strace_logging_options: Option<FmtOptions>,
948 expected_final_state: ProcessFinalState,
949 ) -> Result<RootedRc<RootedRefCell<Process>>, Errno> {
950 debug!("starting process '{:?}'", plugin_name);
951
952 let main_thread_id = host.get_new_thread_id();
953 let process_id = ProcessId::from(main_thread_id);
954
955 let desc_table = RootedRc::new(
956 host.root(),
957 RootedRefCell::new(host.root(), DescriptorTable::new()),
958 );
959 let itimer_real = RefCell::new(Timer::new(move |host| {
960 itimer_real_expiration(host, process_id)
961 }));
962
963 let name = make_name(host, plugin_name.to_str().unwrap(), process_id);
964
965 let mut file_basename = PathBuf::new();
966 file_basename.push(host.data_dir_path());
967 file_basename.push(format!(
968 "{exe_name}.{id}",
969 exe_name = plugin_name.to_str().unwrap(),
970 id = u32::from(process_id)
971 ));
972
973 let strace_logging = strace_logging_options.map(|options| {
974 let file =
975 std::fs::File::create(Self::static_output_file_name(&file_basename, "strace"))
976 .unwrap();
977 debug_assert_cloexec(&file);
978 Arc::new(StraceLogging {
979 file: RootedRefCell::new(host.root(), file),
980 options,
981 })
982 });
983
984 let shim_shared_mem = ProcessShmem::new(
985 &host.shim_shmem_lock_borrow().unwrap().root,
986 host.shim_shmem().serialize(),
987 host.id(),
988 strace_logging
989 .as_ref()
990 .map(|x| x.file.borrow(host.root()).as_raw_fd()),
991 );
992 let shim_shared_mem_block = shadow_shmem::allocator::shmalloc(shim_shared_mem);
993
994 let working_dir = utility::pathbuf_to_nul_term_cstring(
995 std::fs::canonicalize(host.data_dir_path()).unwrap(),
996 );
997
998 {
999 let mut descriptor_table = desc_table.borrow_mut(host.root());
1000 Self::open_stdio_file_helper(
1001 &mut descriptor_table,
1002 libc::STDIN_FILENO.try_into().unwrap(),
1003 "/dev/null".into(),
1004 OFlag::O_RDONLY,
1005 );
1006
1007 let name = Self::static_output_file_name(&file_basename, "stdout");
1008 Self::open_stdio_file_helper(
1009 &mut descriptor_table,
1010 libc::STDOUT_FILENO.try_into().unwrap(),
1011 name,
1012 OFlag::O_WRONLY,
1013 );
1014
1015 let name = Self::static_output_file_name(&file_basename, "stderr");
1016 Self::open_stdio_file_helper(
1017 &mut descriptor_table,
1018 libc::STDERR_FILENO.try_into().unwrap(),
1019 name,
1020 OFlag::O_WRONLY,
1021 );
1022 }
1023
1024 let shimlog_file = Arc::new(
1025 std::fs::File::create(Self::static_output_file_name(&file_basename, "shimlog"))
1026 .unwrap(),
1027 );
1028 debug_assert_cloexec(&shimlog_file);
1029
1030 let mthread = ManagedThread::spawn(
1031 plugin_path,
1032 argv,
1033 envv,
1034 strace_logging
1035 .as_ref()
1036 .map(|s| s.file.borrow(host.root()))
1037 .as_deref(),
1038 &shimlog_file,
1039 host.preload_paths(),
1040 )?;
1041 let native_pid = mthread.native_pid();
1042 let main_thread =
1043 Thread::wrap_mthread(host, mthread, desc_table, process_id, main_thread_id).unwrap();
1044
1045 debug!("process '{:?}' started", plugin_name);
1046
1047 if pause_for_debugging {
1048 log::logger().flush();
1052
1053 let msg = format!(
1060 "\
1061 \n** Pausing with SIGTSTP to enable debugger attachment to managed process\
1062 \n** '{plugin_name:?}' (pid {native_pid:?}).\
1063 \n** If running Shadow under Bash, resume Shadow by pressing Ctrl-Z to background\
1064 \n** this task, and then typing \"fg\".\
1065 \n** If running GDB, resume Shadow by typing \"signal SIGCONT\"."
1066 );
1067 eprintln!("{}", msg);
1068
1069 rustix::process::kill_process(rustix::process::getpid(), rustix::process::Signal::Tstp)
1070 .unwrap();
1071 }
1072
1073 let memory_manager = unsafe { MemoryManager::new(native_pid) };
1074 let threads = RefCell::new(BTreeMap::from([(
1075 main_thread_id,
1076 RootedRc::new(host.root(), RootedRefCell::new(host.root(), main_thread)),
1077 )]));
1078
1079 let common = Common {
1080 id: process_id,
1081 host_id: host.id(),
1082 working_dir,
1083 name,
1084 plugin_name,
1085 parent_pid: Cell::new(ProcessId::INIT),
1086 group_id: Cell::new(ProcessId::INIT),
1087 session_id: Cell::new(ProcessId::INIT),
1088 exit_signal: None,
1091 };
1092 Ok(RootedRc::new(
1093 host.root(),
1094 RootedRefCell::new(
1095 host.root(),
1096 Self {
1097 state: RefCell::new(Some(ProcessState::Runnable(RunnableProcess {
1098 common,
1099 expected_final_state: Some(expected_final_state),
1100 shim_shared_mem_block,
1101 memory_manager: Box::new(RefCell::new(memory_manager)),
1102 itimer_real,
1103 strace_logging,
1104 dumpable: Cell::new(SuidDump::SUID_DUMP_USER),
1105 native_pid,
1106 unsafe_borrow_mut: RefCell::new(None),
1107 unsafe_borrows: RefCell::new(Vec::new()),
1108 threads,
1109 #[cfg(feature = "perf_timers")]
1110 cpu_delay_timer: RefCell::new(PerfTimer::new_stopped()),
1111 #[cfg(feature = "perf_timers")]
1112 total_run_time: Cell::new(Duration::ZERO),
1113 child_process_event_listeners: Default::default(),
1114 shimlog_file,
1115 }))),
1116 },
1117 ),
1118 ))
1119 }
1120
1121 pub fn id(&self) -> ProcessId {
1122 self.common().id
1123 }
1124
1125 pub fn parent_id(&self) -> ProcessId {
1126 self.common().parent_pid.get()
1127 }
1128
1129 pub fn set_parent_id(&self, pid: ProcessId) {
1130 self.common().parent_pid.set(pid)
1131 }
1132
1133 pub fn group_id(&self) -> ProcessId {
1134 self.common().group_id.get()
1135 }
1136
1137 pub fn set_group_id(&self, id: ProcessId) {
1138 self.common().group_id.set(id)
1139 }
1140
1141 pub fn session_id(&self) -> ProcessId {
1142 self.common().session_id.get()
1143 }
1144
1145 pub fn set_session_id(&self, id: ProcessId) {
1146 self.common().session_id.set(id)
1147 }
1148
1149 pub fn host_id(&self) -> HostId {
1150 self.common().host_id
1151 }
1152
1153 pub fn dumpable(&self) -> SuidDump {
1156 self.as_runnable().unwrap().dumpable.get()
1157 }
1158
1159 pub fn set_dumpable(&self, val: SuidDump) {
1162 assert!(val == SuidDump::SUID_DUMP_DISABLE || val == SuidDump::SUID_DUMP_USER);
1163 self.as_runnable().unwrap().dumpable.set(val)
1164 }
1165
1166 #[cfg(feature = "perf_timers")]
1168 pub fn start_cpu_delay_timer(&self) {
1169 self.as_runnable().unwrap().start_cpu_delay_timer()
1170 }
1171
1172 #[cfg(feature = "perf_timers")]
1174 pub fn stop_cpu_delay_timer(&self, host: &Host) -> Duration {
1175 self.as_runnable().unwrap().stop_cpu_delay_timer(host)
1176 }
1177
1178 pub fn thread_group_leader_id(&self) -> ThreadId {
1179 self.common().thread_group_leader_id()
1180 }
1181
1182 pub fn resume(&self, host: &Host, tid: ThreadId) {
1185 trace!("Continuing thread {} in process {}", tid, self.id());
1186
1187 let threadrc = {
1188 let Some(runnable) = self.as_runnable() else {
1189 debug!("Process {} is no longer running", &*self.name());
1190 return;
1191 };
1192 let threads = runnable.threads.borrow();
1193 let Some(thread) = threads.get(&tid) else {
1194 debug!("Thread {} no longer exists", tid);
1195 return;
1196 };
1197 thread.clone(host.root())
1200 };
1201 let threadrc = ExplicitDropper::new(threadrc, |t| {
1202 t.explicit_drop_recursive(host.root(), host);
1203 });
1204 let thread = threadrc.borrow(host.root());
1205
1206 Worker::set_active_thread(&threadrc);
1207
1208 #[cfg(feature = "perf_timers")]
1209 self.start_cpu_delay_timer();
1210
1211 Process::set_shared_time(host);
1212
1213 host.shim_shmem_lock_borrow_mut()
1218 .unwrap()
1219 .unapplied_cpu_latency = SimulationTime::ZERO;
1220
1221 let ctx = ProcessContext::new(host, self);
1222 let res = thread.resume(&ctx);
1223
1224 #[cfg(feature = "perf_timers")]
1225 {
1226 let delay = self.stop_cpu_delay_timer(host);
1227 debug!("process '{}' ran for {:?}", &*self.name(), delay);
1228 }
1229 #[cfg(not(feature = "perf_timers"))]
1230 debug!("process '{}' done continuing", &*self.name());
1231
1232 match res {
1233 crate::host::thread::ResumeResult::Blocked => {
1234 debug!(
1235 "thread {tid} in process '{}' still running, but blocked",
1236 &*self.name()
1237 );
1238 }
1239 crate::host::thread::ResumeResult::ExitedThread(return_code) => {
1240 debug!(
1241 "thread {tid} in process '{}' exited with code {return_code}",
1242 &*self.name(),
1243 );
1244 let (threadrc, last_thread) = {
1245 let runnable = self.as_runnable().unwrap();
1246 let mut threads = runnable.threads.borrow_mut();
1247 let threadrc = threads.remove(&tid).unwrap();
1248 (threadrc, threads.is_empty())
1249 };
1250 self.as_runnable().unwrap().reap_thread(host, threadrc);
1251 if last_thread {
1252 self.handle_process_exit(host, false);
1253 }
1254 }
1255 crate::host::thread::ResumeResult::ExitedProcess => {
1256 debug!(
1257 "Process {} exited while running thread {tid}",
1258 &*self.name(),
1259 );
1260 self.handle_process_exit(host, false);
1261 }
1262 };
1263
1264 Worker::clear_active_thread();
1265 }
1266
1267 pub fn stop(&self, host: &Host) {
1271 {
1273 let Some(runnable) = self.as_runnable() else {
1274 debug!("process {} has already stopped", &*self.name());
1275 return;
1276 };
1277 debug!("terminating process {}", &*self.name());
1278
1279 #[cfg(feature = "perf_timers")]
1280 runnable.start_cpu_delay_timer();
1281
1282 if let Err(err) = rustix::process::kill_process(
1283 runnable.native_pid().into(),
1284 rustix::process::Signal::Kill,
1285 ) {
1286 warn!("kill: {:?}", err);
1287 }
1288
1289 #[cfg(feature = "perf_timers")]
1290 {
1291 let delay = runnable.stop_cpu_delay_timer(host);
1292 debug!("process '{}' stopped in {:?}", &*self.name(), delay);
1293 }
1294 #[cfg(not(feature = "perf_timers"))]
1295 debug!("process '{}' stopped", &*self.name());
1296 }
1297
1298 self.handle_process_exit(host, true);
1300 }
1301
1302 pub fn signal(&self, host: &Host, current_thread: Option<&Thread>, siginfo_t: &siginfo_t) {
1306 match self.state.borrow().as_ref().unwrap() {
1308 ProcessState::Runnable(r) => r.signal(host, current_thread, siginfo_t),
1309 ProcessState::Zombie(_) => {
1310 debug!("Process {} no longer running", &*self.name());
1312 }
1313 }
1314 }
1315
1316 fn open_stdio_file_helper(
1317 descriptor_table: &mut DescriptorTable,
1318 fd: DescriptorHandle,
1319 path: PathBuf,
1320 access_mode: OFlag,
1321 ) {
1322 let stdfile = unsafe { cshadow::regularfile_new() };
1323 let cwd = rustix::process::getcwd(Vec::new()).unwrap();
1324 let path = utility::pathbuf_to_nul_term_cstring(path);
1325 let access_mode = access_mode.bits();
1333 let errorcode = unsafe {
1334 cshadow::regularfile_open(
1335 stdfile,
1336 path.as_ptr(),
1337 access_mode | libc::O_CREAT | libc::O_TRUNC,
1338 libc::S_IRUSR | libc::S_IWUSR | libc::S_IRGRP | libc::S_IROTH,
1339 cwd.as_ptr(),
1340 )
1341 };
1342 if errorcode != 0 {
1343 panic!(
1344 "Opening {}: {:?}",
1345 path.to_str().unwrap(),
1346 linux_api::errno::Errno::try_from(-errorcode).unwrap()
1347 );
1348 }
1349 let desc = unsafe {
1350 Descriptor::from_legacy_file(
1351 stdfile as *mut cshadow::LegacyFile,
1352 linux_api::fcntl::OFlag::empty(),
1353 )
1354 };
1355 let prev = descriptor_table.register_descriptor_with_fd(desc, fd);
1356 assert!(prev.is_none());
1357 trace!(
1358 "Successfully opened fd {} at {}",
1359 fd,
1360 path.to_str().unwrap()
1361 );
1362 }
1363
1364 fn static_output_file_name(file_basename: &Path, extension: &str) -> PathBuf {
1366 let mut path = file_basename.to_owned().into_os_string();
1367 path.push(".");
1368 path.push(extension);
1369 path.into()
1370 }
1371
1372 pub fn name(&self) -> impl Deref<Target = str> + '_ {
1373 Ref::map(self.common(), |c| c.name.to_str().unwrap())
1374 }
1375
1376 pub fn plugin_name(&self) -> impl Deref<Target = str> + '_ {
1377 Ref::map(self.common(), |c| c.plugin_name.to_str().unwrap())
1378 }
1379
1380 #[track_caller]
1382 pub fn memory_borrow_mut(&self) -> impl DerefMut<Target = MemoryManager> + '_ {
1383 std_util::nested_ref::NestedRefMut::map(self.as_runnable().unwrap(), |runnable| {
1384 runnable.memory_manager.borrow_mut()
1385 })
1386 }
1387
1388 #[track_caller]
1390 pub fn memory_borrow(&self) -> impl Deref<Target = MemoryManager> + '_ {
1391 std_util::nested_ref::NestedRef::map(self.as_runnable().unwrap(), |runnable| {
1392 runnable.memory_manager.borrow()
1393 })
1394 }
1395
1396 pub fn strace_logging_options(&self) -> Option<FmtOptions> {
1398 self.as_runnable().unwrap().strace_logging_options()
1399 }
1400
1401 pub fn with_strace_file<T>(&self, f: impl FnOnce(&mut std::fs::File) -> T) -> Option<T> {
1403 self.as_runnable().unwrap().with_strace_file(f)
1404 }
1405
1406 pub fn native_pid(&self) -> Pid {
1408 self.as_runnable().unwrap().native_pid()
1409 }
1410
1411 #[track_caller]
1413 pub fn realtime_timer_borrow(&self) -> impl Deref<Target = Timer> + '_ {
1414 std_util::nested_ref::NestedRef::map(self.as_runnable().unwrap(), |runnable| {
1415 runnable.itimer_real.borrow()
1416 })
1417 }
1418
1419 #[track_caller]
1421 pub fn realtime_timer_borrow_mut(&self) -> impl DerefMut<Target = Timer> + '_ {
1422 std_util::nested_ref::NestedRefMut::map(self.as_runnable().unwrap(), |runnable| {
1423 runnable.itimer_real.borrow_mut()
1424 })
1425 }
1426
1427 #[track_caller]
1429 pub fn first_live_thread_borrow(
1430 &self,
1431 root: &Root,
1432 ) -> Option<impl Deref<Target = RootedRc<RootedRefCell<Thread>>> + '_> {
1433 std_util::nested_ref::NestedRef::filter_map(self.as_runnable()?, |runnable| {
1434 runnable.first_live_thread(root)
1435 })
1436 }
1437
1438 pub fn thread_borrow(
1440 &self,
1441 virtual_tid: ThreadId,
1442 ) -> Option<impl Deref<Target = RootedRc<RootedRefCell<Thread>>> + '_> {
1443 std_util::nested_ref::NestedRef::filter_map(self.as_runnable()?, |runnable| {
1444 runnable.thread(virtual_tid)
1445 })
1446 }
1447
1448 pub fn free_unsafe_borrows_flush(&self) -> Result<(), Errno> {
1450 self.as_runnable().unwrap().free_unsafe_borrows_flush()
1451 }
1452
1453 pub fn free_unsafe_borrows_noflush(&self) {
1455 self.as_runnable().unwrap().free_unsafe_borrows_noflush()
1456 }
1457
1458 pub fn physical_address(&self, vptr: ForeignPtr<()>) -> ManagedPhysicalMemoryAddr {
1459 self.common().physical_address(vptr)
1460 }
1461
1462 pub fn is_running(&self) -> bool {
1463 self.as_runnable().is_some()
1464 }
1465
1466 fn handle_process_exit(&self, host: &Host, killed_by_shadow: bool) {
1468 debug!(
1469 "process '{}' has completed or is otherwise no longer running",
1470 &*self.name()
1471 );
1472
1473 {
1478 let runnable = self.as_runnable().unwrap();
1479 let threads = std::mem::take(&mut *runnable.threads.borrow_mut());
1480 for (_tid, threadrc) in threads.into_iter() {
1481 threadrc.borrow(host.root()).handle_process_exit();
1482 runnable.reap_thread(host, threadrc);
1483 }
1484 }
1485
1486 let mut opt_state = self.state.borrow_mut();
1489
1490 let state = opt_state.take().unwrap();
1491 let ProcessState::Runnable(runnable) = state else {
1492 unreachable!("Tried to handle process exit of non-running process");
1493 };
1494
1495 #[cfg(feature = "perf_timers")]
1496 debug!(
1497 "total runtime for process '{}' was {:?}",
1498 runnable.common.name(),
1499 runnable.total_run_time.get()
1500 );
1501
1502 let wait_res: Option<WaitStatus> =
1503 rustix::process::waitpid(Some(runnable.native_pid().into()), WaitOptions::empty())
1504 .unwrap_or_else(|e| {
1505 panic!("Error waiting for {:?}: {:?}", runnable.native_pid(), e)
1506 });
1507 let wait_status = wait_res.unwrap();
1508 let exit_status = if killed_by_shadow {
1509 if wait_status.terminating_signal()
1510 != Some(Signal::SIGKILL.as_i32().try_into().unwrap())
1511 {
1512 warn!("Unexpected waitstatus after killed by shadow: {wait_status:?}");
1513 }
1514 ExitStatus::StoppedByShadow
1515 } else if let Some(code) = wait_status.exit_status() {
1516 ExitStatus::Normal(code.try_into().unwrap())
1517 } else if let Some(signal) = wait_status.terminating_signal() {
1518 ExitStatus::Signaled(Signal::try_from(i32::try_from(signal).unwrap()).unwrap())
1519 } else {
1520 panic!(
1521 "Unexpected status: {wait_status:?} for pid {:?}",
1522 runnable.native_pid()
1523 );
1524 };
1525
1526 let (main_result_string, log_level) = {
1527 let mut s = format!(
1528 "process '{name}' exited with status {exit_status:?}",
1529 name = runnable.common.name()
1530 );
1531 if let Some(expected_final_state) = runnable.expected_final_state {
1532 let actual_final_state = match exit_status {
1533 ExitStatus::Normal(i) => ProcessFinalState::Exited { exited: i },
1534 ExitStatus::Signaled(s) => ProcessFinalState::Signaled {
1535 signaled: s.try_into().unwrap(),
1539 },
1540 ExitStatus::StoppedByShadow => ProcessFinalState::Running(RunningVal::Running),
1541 };
1542 if expected_final_state == actual_final_state {
1543 (s, log::Level::Debug)
1544 } else {
1545 Worker::increment_plugin_error_count();
1546 write!(s, "; expected end state was {expected_final_state} but was {actual_final_state}").unwrap();
1547 (s, log::Level::Error)
1548 }
1549 } else {
1550 (s, log::Level::Debug)
1551 }
1552 };
1553 log::log!(log_level, "{}", main_result_string);
1554
1555 let zombie = ZombieProcess {
1556 common: runnable.into_common(),
1557 exit_status,
1558 };
1559 zombie.notify_parent_of_exit(host);
1560
1561 *opt_state = Some(ProcessState::Zombie(zombie));
1562 }
1563
1564 pub fn add_thread(&self, host: &Host, thread: RootedRc<RootedRefCell<Thread>>) {
1566 self.as_runnable().unwrap().add_thread(host, thread)
1567 }
1568
1569 fn set_shared_time(host: &Host) {
1572 let mut host_shmem = host.shim_shmem_lock_borrow_mut().unwrap();
1573 host_shmem.max_runahead_time = Worker::max_event_runahead_time(host);
1574 host.shim_shmem()
1575 .sim_time
1576 .store(Worker::current_time().unwrap(), Ordering::Relaxed);
1577 }
1578
1579 pub fn shmem(&self) -> impl Deref<Target = ShMemBlock<'static, ProcessShmem>> + '_ {
1581 Ref::map(self.as_runnable().unwrap(), |r| &r.shim_shared_mem_block)
1582 }
1583
1584 pub fn rusage(&self) -> linux_api::resource::rusage {
1586 warn_once_then_debug!(
1587 "resource usage (rusage) tracking unimplemented; Returning bogus zeroed values"
1588 );
1589 linux_api::resource::rusage {
1596 ru_utime: linux_api::time::kernel_old_timeval {
1597 tv_sec: 0,
1598 tv_usec: 0,
1599 },
1600 ru_stime: linux_api::time::kernel_old_timeval {
1601 tv_sec: 0,
1602 tv_usec: 0,
1603 },
1604 ru_maxrss: 0,
1605 ru_ixrss: 0,
1606 ru_idrss: 0,
1607 ru_isrss: 0,
1608 ru_minflt: 0,
1609 ru_majflt: 0,
1610 ru_nswap: 0,
1611 ru_inblock: 0,
1612 ru_oublock: 0,
1613 ru_msgsnd: 0,
1614 ru_msgrcv: 0,
1615 ru_nsignals: 0,
1616 ru_nvcsw: 0,
1617 ru_nivcsw: 0,
1618 }
1619 }
1620
1621 pub fn exit_signal(&self) -> Option<Signal> {
1623 self.common().exit_signal
1624 }
1625
1626 pub fn current_working_dir(&self) -> impl Deref<Target = CString> + '_ {
1627 Ref::map(self.common(), |common| &common.working_dir)
1628 }
1629
1630 pub fn set_current_working_dir(&self, path: CString) {
1635 self.common_mut().working_dir = path;
1636 }
1637
1638 pub fn update_for_exec(&mut self, host: &Host, tid: ThreadId, mthread: ManagedThread) {
1641 let Some(mut runnable) = self.as_runnable_mut() else {
1642 log::debug!(
1646 "Process {:?} exited before it could complete execve",
1647 self.id()
1648 );
1649 mthread.kill_and_drop();
1650 return;
1651 };
1652 let old_native_pid = std::mem::replace(&mut runnable.native_pid, mthread.native_pid());
1653
1654 rustix::process::kill_process(old_native_pid.into(), rustix::process::Signal::Kill)
1656 .expect("Unable to send kill signal to managed process {old_native_pid:?}");
1657 let wait_res = rustix::process::waitpid(Some(old_native_pid.into()), WaitOptions::empty())
1658 .unwrap()
1659 .unwrap();
1660 assert_eq!(
1661 wait_res.terminating_signal(),
1662 Some(Signal::SIGKILL.as_i32().try_into().unwrap())
1663 );
1664
1665 let execing_thread = runnable.threads.borrow_mut().remove(&tid).unwrap();
1666
1667 for (_tid, thread) in runnable.threads.replace(BTreeMap::new()) {
1669 thread.borrow(host.root()).mthread().handle_process_exit();
1671
1672 thread.explicit_drop_recursive(host.root(), host);
1673 }
1674
1675 {
1677 let unsafe_borrow_mut = runnable.unsafe_borrow_mut.borrow();
1682 let unsafe_borrows = runnable.unsafe_borrows.borrow();
1683 assert!(unsafe_borrow_mut.is_none());
1684 assert!(unsafe_borrows.is_empty());
1685 runnable
1688 .memory_manager
1689 .replace(unsafe { MemoryManager::new(mthread.native_pid()) });
1690 }
1691
1692 let new_tid = runnable.common.thread_group_leader_id();
1693 log::trace!(
1694 "updating for exec; pid:{pid}, tid:{tid:?}, new_tid:{new_tid:?}",
1695 pid = runnable.common.id
1696 );
1697 execing_thread
1698 .borrow_mut(host.root())
1699 .update_for_exec(host, mthread, new_tid);
1700
1701 runnable
1702 .threads
1703 .borrow_mut()
1704 .insert(new_tid, execing_thread);
1705
1706 runnable.common.exit_signal = Some(Signal::SIGCHLD);
1708
1709 let host_shmem_prot = host.shim_shmem_lock_borrow_mut().unwrap();
1717 let mut shmem_prot = runnable
1718 .shim_shared_mem_block
1719 .protected
1720 .borrow_mut(&host_shmem_prot.root);
1721 for signal in Signal::standard_signals() {
1722 let current_action = unsafe { shmem_prot.signal_action(signal) };
1723 if !(current_action.is_default()
1724 || current_action.is_ignore()
1725 || signal == Signal::SIGCHLD && current_action.is_ignore())
1726 {
1727 unsafe {
1728 *shmem_prot.signal_action_mut(signal) = linux_api::signal::sigaction::new_raw(
1729 linux_api::signal::SignalHandler::SigDfl,
1730 SigActionFlags::empty(),
1731 sigset_t::EMPTY,
1732 None,
1733 )
1734 };
1735 }
1736 }
1737 }
1738}
1739
1740impl Drop for Process {
1741 fn drop(&mut self) {
1742 debug_assert!(self.state.borrow().is_none());
1744 }
1745}
1746
1747impl ExplicitDrop for Process {
1748 type ExplicitDropParam = Host;
1749 type ExplicitDropResult = ();
1750
1751 fn explicit_drop(mut self, host: &Self::ExplicitDropParam) -> Self::ExplicitDropResult {
1752 debug_assert!(self.as_zombie().is_some() || std::thread::panicking());
1754
1755 let state = self.state.get_mut().take().unwrap();
1756 state.explicit_drop(host);
1757 }
1758}
1759
1760struct UnsafeBorrow {
1762 _memory: ProcessMemoryRef<'static, u8>,
1765 _manager: Ref<'static, MemoryManager>,
1766}
1767
1768impl UnsafeBorrow {
1769 unsafe fn readable_ptr(
1776 process: &Process,
1777 ptr: ForeignArrayPtr<u8>,
1778 ) -> Result<*const c_void, Errno> {
1779 let runnable = process.as_runnable().unwrap();
1780 let manager = runnable.memory_manager.borrow();
1781 let manager = unsafe {
1785 std::mem::transmute::<Ref<'_, MemoryManager>, Ref<'static, MemoryManager>>(manager)
1786 };
1787 let memory = manager.memory_ref(ptr)?;
1788 let memory = unsafe {
1789 std::mem::transmute::<ProcessMemoryRef<'_, u8>, ProcessMemoryRef<'static, u8>>(memory)
1790 };
1791 let vptr = memory.as_ptr() as *mut c_void;
1792 runnable.unsafe_borrows.borrow_mut().push(Self {
1793 _manager: manager,
1794 _memory: memory,
1795 });
1796 Ok(vptr)
1797 }
1798
1799 unsafe fn readable_string(
1806 process: &Process,
1807 ptr: ForeignArrayPtr<c_char>,
1808 ) -> Result<(*const c_char, libc::size_t), Errno> {
1809 let runnable = process.as_runnable().unwrap();
1810 let manager = runnable.memory_manager.borrow();
1811 let manager = unsafe {
1815 std::mem::transmute::<Ref<'_, MemoryManager>, Ref<'static, MemoryManager>>(manager)
1816 };
1817 let ptr = ptr.cast_u8();
1818 let memory = manager.memory_ref_prefix(ptr)?;
1819 let memory = unsafe {
1820 std::mem::transmute::<ProcessMemoryRef<'_, u8>, ProcessMemoryRef<'static, u8>>(memory)
1821 };
1822 if !memory.contains(&0) {
1823 return Err(Errno::ENAMETOOLONG);
1824 }
1825 assert_eq!(std::mem::size_of::<c_char>(), std::mem::size_of::<u8>());
1826 let ptr = memory.as_ptr() as *const c_char;
1827 let len = memory.len();
1828 runnable.unsafe_borrows.borrow_mut().push(Self {
1829 _manager: manager,
1830 _memory: memory,
1831 });
1832 Ok((ptr, len))
1833 }
1834}
1835
1836unsafe impl Send for UnsafeBorrow {}
1845
1846struct UnsafeBorrowMut {
1848 memory: Option<ProcessMemoryRefMut<'static, u8>>,
1851 _manager: RefMut<'static, MemoryManager>,
1852}
1853
1854impl UnsafeBorrowMut {
1855 unsafe fn writable_ptr(
1862 process: &Process,
1863 ptr: ForeignArrayPtr<u8>,
1864 ) -> Result<*mut c_void, Errno> {
1865 let runnable = process.as_runnable().unwrap();
1866 let manager = runnable.memory_manager.borrow_mut();
1867 let mut manager = unsafe {
1871 std::mem::transmute::<RefMut<'_, MemoryManager>, RefMut<'static, MemoryManager>>(
1872 manager,
1873 )
1874 };
1875 let memory = manager.memory_ref_mut_uninit(ptr)?;
1876 let mut memory = unsafe {
1877 std::mem::transmute::<ProcessMemoryRefMut<'_, u8>, ProcessMemoryRefMut<'static, u8>>(
1878 memory,
1879 )
1880 };
1881 let vptr = memory.as_mut_ptr() as *mut c_void;
1882 let prev = runnable.unsafe_borrow_mut.borrow_mut().replace(Self {
1883 _manager: manager,
1884 memory: Some(memory),
1885 });
1886 assert!(prev.is_none());
1887 Ok(vptr)
1888 }
1889
1890 unsafe fn mutable_ptr(
1897 process: &Process,
1898 ptr: ForeignArrayPtr<u8>,
1899 ) -> Result<*mut c_void, Errno> {
1900 let runnable = process.as_runnable().unwrap();
1901 let manager = runnable.memory_manager.borrow_mut();
1902 let mut manager = unsafe {
1906 std::mem::transmute::<RefMut<'_, MemoryManager>, RefMut<'static, MemoryManager>>(
1907 manager,
1908 )
1909 };
1910 let memory = manager.memory_ref_mut(ptr)?;
1911 let mut memory = unsafe {
1912 std::mem::transmute::<ProcessMemoryRefMut<'_, u8>, ProcessMemoryRefMut<'static, u8>>(
1913 memory,
1914 )
1915 };
1916 let vptr = memory.as_mut_ptr() as *mut c_void;
1917 let prev = runnable.unsafe_borrow_mut.borrow_mut().replace(Self {
1918 _manager: manager,
1919 memory: Some(memory),
1920 });
1921 assert!(prev.is_none());
1922 Ok(vptr)
1923 }
1924
1925 fn flush(mut self) -> Result<(), Errno> {
1927 self.memory.take().unwrap().flush()
1928 }
1929
1930 fn noflush(mut self) {
1932 self.memory.take().unwrap().noflush()
1933 }
1934}
1935
1936unsafe impl Send for UnsafeBorrowMut {}
1944
1945fn make_name(host: &Host, exe_name: &str, id: ProcessId) -> CString {
1946 CString::new(format!(
1947 "{host_name}.{exe_name}.{id}",
1948 host_name = host.name(),
1949 exe_name = exe_name,
1950 id = u32::from(id)
1951 ))
1952 .unwrap()
1953}
1954
1955mod export {
1956 use std::os::raw::c_void;
1957
1958 use libc::size_t;
1959 use log::trace;
1960 use shadow_shim_helper_rs::notnull::*;
1961 use shadow_shim_helper_rs::shim_shmem::export::ShimShmemProcess;
1962 use shadow_shim_helper_rs::syscall_types::UntypedForeignPtr;
1963
1964 use super::*;
1965 use crate::utility::HostTreePointer;
1966
1967 #[unsafe(no_mangle)]
1970 pub extern "C-unwind" fn process_readPtr(
1971 proc: *const Process,
1972 dst: *mut c_void,
1973 src: UntypedForeignPtr,
1974 n: usize,
1975 ) -> i32 {
1976 let proc = unsafe { proc.as_ref().unwrap() };
1977 let src = ForeignArrayPtr::new(src.cast::<u8>(), n);
1978 let dst = unsafe { std::slice::from_raw_parts_mut(notnull_mut_debug(dst) as *mut u8, n) };
1979
1980 match proc.memory_borrow().copy_from_ptr(dst, src) {
1981 Ok(_) => 0,
1982 Err(e) => {
1983 trace!("Couldn't read {:?} into {:?}: {:?}", src, dst, e);
1984 e.to_negated_i32()
1985 }
1986 }
1987 }
1988
1989 #[unsafe(no_mangle)]
1992 pub unsafe extern "C-unwind" fn process_writePtr(
1993 proc: *const Process,
1994 dst: UntypedForeignPtr,
1995 src: *const c_void,
1996 n: usize,
1997 ) -> i32 {
1998 let proc = unsafe { proc.as_ref().unwrap() };
1999 let dst = ForeignArrayPtr::new(dst.cast::<u8>(), n);
2000 let src = unsafe { std::slice::from_raw_parts(notnull_debug(src) as *const u8, n) };
2001 match proc.memory_borrow_mut().copy_to_ptr(dst, src) {
2002 Ok(_) => 0,
2003 Err(e) => {
2004 trace!("Couldn't write {:?} into {:?}: {:?}", src, dst, e);
2005 e.to_negated_i32()
2006 }
2007 }
2008 }
2009
2010 #[unsafe(no_mangle)]
2015 pub unsafe extern "C-unwind" fn process_getReadablePtr(
2016 proc: *const Process,
2017 plugin_src: UntypedForeignPtr,
2018 n: usize,
2019 ) -> *const c_void {
2020 let proc = unsafe { proc.as_ref().unwrap() };
2021 let plugin_src = ForeignArrayPtr::new(plugin_src.cast::<u8>(), n);
2022 unsafe { UnsafeBorrow::readable_ptr(proc, plugin_src).unwrap_or(std::ptr::null()) }
2023 }
2024
2025 #[unsafe(no_mangle)]
2035 pub unsafe extern "C-unwind" fn process_getWriteablePtr(
2036 proc: *const Process,
2037 plugin_src: UntypedForeignPtr,
2038 n: usize,
2039 ) -> *mut c_void {
2040 let proc = unsafe { proc.as_ref().unwrap() };
2041 let plugin_src = ForeignArrayPtr::new(plugin_src.cast::<u8>(), n);
2042 unsafe { UnsafeBorrowMut::writable_ptr(proc, plugin_src).unwrap_or(std::ptr::null_mut()) }
2043 }
2044
2045 #[unsafe(no_mangle)]
2051 pub unsafe extern "C-unwind" fn process_getMutablePtr(
2052 proc: *const Process,
2053 plugin_src: UntypedForeignPtr,
2054 n: usize,
2055 ) -> *mut c_void {
2056 let proc = unsafe { proc.as_ref().unwrap() };
2057 let plugin_src = ForeignArrayPtr::new(plugin_src.cast::<u8>(), n);
2058 unsafe { UnsafeBorrowMut::mutable_ptr(proc, plugin_src).unwrap_or(std::ptr::null_mut()) }
2059 }
2060
2061 #[unsafe(no_mangle)]
2068 pub unsafe extern "C-unwind" fn process_readString(
2069 proc: *const Process,
2070 strbuf: *mut libc::c_char,
2071 ptr: UntypedForeignPtr,
2072 maxlen: libc::size_t,
2073 ) -> libc::ssize_t {
2074 let proc = unsafe { proc.as_ref().unwrap() };
2075 let memory_manager = proc.memory_borrow();
2076 let buf =
2077 unsafe { std::slice::from_raw_parts_mut(notnull_mut_debug(strbuf) as *mut u8, maxlen) };
2078 let cstr = match memory_manager
2079 .copy_str_from_ptr(buf, ForeignArrayPtr::new(ptr.cast::<u8>(), maxlen))
2080 {
2081 Ok(cstr) => cstr,
2082 Err(e) => return e.to_negated_i32() as isize,
2083 };
2084 cstr.to_bytes().len().try_into().unwrap()
2085 }
2086
2087 #[unsafe(no_mangle)]
2094 pub unsafe extern "C-unwind" fn process_getReadableString(
2095 proc: *const Process,
2096 plugin_src: UntypedForeignPtr,
2097 n: usize,
2098 out_str: *mut *const c_char,
2099 out_strlen: *mut size_t,
2100 ) -> i32 {
2101 let proc = unsafe { proc.as_ref().unwrap() };
2102 let ptr = ForeignArrayPtr::new(plugin_src.cast::<c_char>(), n);
2103 match unsafe { UnsafeBorrow::readable_string(proc, ptr) } {
2104 Ok((str, strlen)) => {
2105 assert!(!out_str.is_null());
2106 unsafe { out_str.write(str) };
2107 if !out_strlen.is_null() {
2108 unsafe { out_strlen.write(strlen) };
2109 }
2110 0
2111 }
2112 Err(e) => e.to_negated_i32(),
2113 }
2114 }
2115
2116 #[unsafe(no_mangle)]
2118 pub unsafe extern "C-unwind" fn process_getProcessID(proc: *const Process) -> libc::pid_t {
2119 let proc = unsafe { proc.as_ref().unwrap() };
2120 proc.id().into()
2121 }
2122
2123 #[unsafe(no_mangle)]
2124 pub unsafe extern "C-unwind" fn process_getName(proc: *const Process) -> *const c_char {
2125 let proc = unsafe { proc.as_ref().unwrap() };
2126 proc.common().name.as_ptr()
2127 }
2128
2129 #[unsafe(no_mangle)]
2134 pub unsafe extern "C-unwind" fn process_getSharedMem(
2135 proc: *const Process,
2136 ) -> *const ShimShmemProcess {
2137 let proc = unsafe { proc.as_ref().unwrap() };
2138 std::ptr::from_ref(proc.as_runnable().unwrap().shim_shared_mem_block.deref())
2139 }
2140
2141 #[unsafe(no_mangle)]
2142 pub unsafe extern "C-unwind" fn process_getWorkingDir(proc: *const Process) -> *const c_char {
2143 let proc = unsafe { proc.as_ref().unwrap() };
2144 proc.common().working_dir.as_ptr()
2145 }
2146
2147 #[unsafe(no_mangle)]
2148 pub unsafe extern "C-unwind" fn process_straceLoggingMode(
2149 proc: *const Process,
2150 ) -> StraceFmtMode {
2151 let proc = unsafe { proc.as_ref().unwrap() };
2152 proc.strace_logging_options().into()
2153 }
2154
2155 #[unsafe(no_mangle)]
2156 pub unsafe extern "C-unwind" fn process_getNativePid(proc: *const Process) -> libc::pid_t {
2157 let proc = unsafe { proc.as_ref().unwrap() };
2158 proc.native_pid().as_raw_nonzero().get()
2159 }
2160
2161 #[unsafe(no_mangle)]
2168 pub unsafe extern "C-unwind" fn process_flushPtrs(proc: *const Process) -> i32 {
2169 let proc = unsafe { proc.as_ref().unwrap() };
2170 match proc.free_unsafe_borrows_flush() {
2171 Ok(_) => 0,
2172 Err(e) => e.to_negated_i32(),
2173 }
2174 }
2175
2176 #[unsafe(no_mangle)]
2182 pub unsafe extern "C-unwind" fn process_freePtrsWithoutFlushing(proc: *const Process) {
2183 let proc = unsafe { proc.as_ref().unwrap() };
2184 proc.free_unsafe_borrows_noflush();
2185 }
2186
2187 #[unsafe(no_mangle)]
2188 pub unsafe extern "C-unwind" fn process_getThread(
2189 proc: *const Process,
2190 tid: libc::pid_t,
2191 ) -> *const Thread {
2192 let proc = unsafe { proc.as_ref().unwrap() };
2193 Worker::with_active_host(|host| {
2194 let tid = ThreadId::try_from(tid).unwrap();
2195 let Some(thread) = proc.thread_borrow(tid) else {
2196 return std::ptr::null();
2197 };
2198 let thread = thread.borrow(host.root());
2199 &*thread
2200 })
2201 .unwrap()
2202 }
2203
2204 #[unsafe(no_mangle)]
2206 pub unsafe extern "C-unwind" fn process_firstLiveThread(proc: *const Process) -> *const Thread {
2207 let proc = unsafe { proc.as_ref().unwrap() };
2208 Worker::with_active_host(|host| {
2209 let Some(thread) = proc.first_live_thread_borrow(host.root()) else {
2210 return std::ptr::null();
2211 };
2212 let thread = thread.borrow(host.root());
2213 &*thread
2214 })
2215 .unwrap()
2216 }
2217
2218 #[unsafe(no_mangle)]
2219 pub unsafe extern "C-unwind" fn process_isRunning(proc: *const Process) -> bool {
2220 let proc = unsafe { proc.as_ref().unwrap() };
2221 proc.is_running()
2222 }
2223
2224 #[unsafe(no_mangle)]
2227 pub unsafe extern "C-unwind" fn process_setSharedTime() {
2228 Worker::with_active_host(Process::set_shared_time).unwrap();
2229 }
2230
2231 #[unsafe(no_mangle)]
2232 pub unsafe extern "C-unwind" fn process_getPhysicalAddress(
2233 proc: *const Process,
2234 vptr: UntypedForeignPtr,
2235 ) -> ManagedPhysicalMemoryAddr {
2236 let proc = unsafe { proc.as_ref().unwrap() };
2237 proc.physical_address(vptr)
2238 }
2239
2240 #[unsafe(no_mangle)]
2241 pub unsafe extern "C-unwind" fn process_addChildEventListener(
2242 host: *const Host,
2243 process: *const Process,
2244 listener: *mut cshadow::StatusListener,
2245 ) {
2246 let host = unsafe { host.as_ref().unwrap() };
2247 let process = unsafe { process.as_ref().unwrap() };
2248 let listener = HostTreePointer::new_for_host(host.id(), listener);
2249 process
2250 .borrow_as_runnable()
2251 .unwrap()
2252 .child_process_event_listeners
2253 .borrow_mut()
2254 .add_legacy_listener(listener)
2255 }
2256
2257 #[unsafe(no_mangle)]
2258 pub unsafe extern "C-unwind" fn process_removeChildEventListener(
2259 _host: *const Host,
2260 process: *const Process,
2261 listener: *mut cshadow::StatusListener,
2262 ) {
2263 let process = unsafe { process.as_ref().unwrap() };
2264 process
2265 .borrow_as_runnable()
2266 .unwrap()
2267 .child_process_event_listeners
2268 .borrow_mut()
2269 .remove_legacy_listener(listener)
2270 }
2271}