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
814#[allow(clippy::large_enum_variant)]
819enum ProcessState {
820 Runnable(RunnableProcess),
821 Zombie(ZombieProcess),
822}
823
824impl ProcessState {
825 fn common(&self) -> &Common {
826 match self {
827 ProcessState::Runnable(r) => &r.common,
828 ProcessState::Zombie(z) => &z.common,
829 }
830 }
831
832 fn common_mut(&mut self) -> &mut Common {
833 match self {
834 ProcessState::Runnable(r) => &mut r.common,
835 ProcessState::Zombie(z) => &mut z.common,
836 }
837 }
838
839 fn as_runnable(&self) -> Option<&RunnableProcess> {
840 match self {
841 ProcessState::Runnable(r) => Some(r),
842 ProcessState::Zombie(_) => None,
843 }
844 }
845
846 fn as_runnable_mut(&mut self) -> Option<&mut RunnableProcess> {
847 match self {
848 ProcessState::Runnable(r) => Some(r),
849 ProcessState::Zombie(_) => None,
850 }
851 }
852
853 fn as_zombie(&self) -> Option<&ZombieProcess> {
854 match self {
855 ProcessState::Runnable(_) => None,
856 ProcessState::Zombie(z) => Some(z),
857 }
858 }
859}
860
861impl ExplicitDrop for ProcessState {
862 type ExplicitDropParam = Host;
863 type ExplicitDropResult = ();
864
865 fn explicit_drop(self, host: &Self::ExplicitDropParam) -> Self::ExplicitDropResult {
866 match self {
867 ProcessState::Runnable(r) => r.explicit_drop(host),
868 ProcessState::Zombie(_) => (),
869 }
870 }
871}
872
873pub struct Process {
875 state: RefCell<Option<ProcessState>>,
878}
879
880fn itimer_real_expiration(host: &Host, pid: ProcessId) {
881 let Some(process) = host.process_borrow(pid) else {
882 debug!("Process {:?} no longer exists", pid);
883 return;
884 };
885 let process = process.borrow(host.root());
886 let Some(runnable) = process.as_runnable() else {
887 debug!("Process {:?} no longer running", &*process.name());
888 return;
889 };
890 let timer = runnable.itimer_real.borrow();
891 let expiration_count = timer.expiration_count() as i32;
894 let siginfo_t = siginfo_t::new_for_timer(Signal::SIGALRM, 0, expiration_count);
895 process.signal(host, None, &siginfo_t);
896}
897
898impl Process {
899 fn common(&self) -> Ref<Common> {
900 Ref::map(self.state.borrow(), |state| {
901 state.as_ref().unwrap().common()
902 })
903 }
904
905 fn common_mut(&self) -> RefMut<Common> {
906 RefMut::map(self.state.borrow_mut(), |state| {
907 state.as_mut().unwrap().common_mut()
908 })
909 }
910
911 fn as_runnable(&self) -> Option<Ref<RunnableProcess>> {
912 Ref::filter_map(self.state.borrow(), |state| {
913 state.as_ref().unwrap().as_runnable()
914 })
915 .ok()
916 }
917
918 fn as_runnable_mut(&self) -> Option<RefMut<RunnableProcess>> {
919 RefMut::filter_map(self.state.borrow_mut(), |state| {
920 state.as_mut().unwrap().as_runnable_mut()
921 })
922 .ok()
923 }
924
925 pub fn borrow_as_runnable(&self) -> Option<impl Deref<Target = RunnableProcess> + '_> {
927 self.as_runnable()
928 }
929
930 fn as_zombie(&self) -> Option<Ref<ZombieProcess>> {
931 Ref::filter_map(self.state.borrow(), |state| {
932 state.as_ref().unwrap().as_zombie()
933 })
934 .ok()
935 }
936
937 pub fn borrow_as_zombie(&self) -> Option<impl Deref<Target = ZombieProcess> + '_> {
939 self.as_zombie()
940 }
941
942 pub fn spawn(
945 host: &Host,
946 plugin_name: CString,
947 plugin_path: &CStr,
948 argv: Vec<CString>,
949 envv: Vec<CString>,
950 pause_for_debugging: bool,
951 strace_logging_options: Option<FmtOptions>,
952 expected_final_state: ProcessFinalState,
953 ) -> Result<RootedRc<RootedRefCell<Process>>, Errno> {
954 debug!("starting process '{:?}'", plugin_name);
955
956 let main_thread_id = host.get_new_thread_id();
957 let process_id = ProcessId::from(main_thread_id);
958
959 let desc_table = RootedRc::new(
960 host.root(),
961 RootedRefCell::new(host.root(), DescriptorTable::new()),
962 );
963 let itimer_real = RefCell::new(Timer::new(move |host| {
964 itimer_real_expiration(host, process_id)
965 }));
966
967 let name = make_name(host, plugin_name.to_str().unwrap(), process_id);
968
969 let mut file_basename = PathBuf::new();
970 file_basename.push(host.data_dir_path());
971 file_basename.push(format!(
972 "{exe_name}.{id}",
973 exe_name = plugin_name.to_str().unwrap(),
974 id = u32::from(process_id)
975 ));
976
977 let strace_logging = strace_logging_options.map(|options| {
978 let file =
979 std::fs::File::create(Self::static_output_file_name(&file_basename, "strace"))
980 .unwrap();
981 debug_assert_cloexec(&file);
982 Arc::new(StraceLogging {
983 file: RootedRefCell::new(host.root(), file),
984 options,
985 })
986 });
987
988 let shim_shared_mem = ProcessShmem::new(
989 &host.shim_shmem_lock_borrow().unwrap().root,
990 host.shim_shmem().serialize(),
991 host.id(),
992 strace_logging
993 .as_ref()
994 .map(|x| x.file.borrow(host.root()).as_raw_fd()),
995 );
996 let shim_shared_mem_block = shadow_shmem::allocator::shmalloc(shim_shared_mem);
997
998 let working_dir = utility::pathbuf_to_nul_term_cstring(
999 std::fs::canonicalize(host.data_dir_path()).unwrap(),
1000 );
1001
1002 {
1003 let mut descriptor_table = desc_table.borrow_mut(host.root());
1004 Self::open_stdio_file_helper(
1005 &mut descriptor_table,
1006 libc::STDIN_FILENO.try_into().unwrap(),
1007 "/dev/null".into(),
1008 OFlag::O_RDONLY,
1009 );
1010
1011 let name = Self::static_output_file_name(&file_basename, "stdout");
1012 Self::open_stdio_file_helper(
1013 &mut descriptor_table,
1014 libc::STDOUT_FILENO.try_into().unwrap(),
1015 name,
1016 OFlag::O_WRONLY,
1017 );
1018
1019 let name = Self::static_output_file_name(&file_basename, "stderr");
1020 Self::open_stdio_file_helper(
1021 &mut descriptor_table,
1022 libc::STDERR_FILENO.try_into().unwrap(),
1023 name,
1024 OFlag::O_WRONLY,
1025 );
1026 }
1027
1028 let shimlog_file = Arc::new(
1029 std::fs::File::create(Self::static_output_file_name(&file_basename, "shimlog"))
1030 .unwrap(),
1031 );
1032 debug_assert_cloexec(&shimlog_file);
1033
1034 let mthread = ManagedThread::spawn(
1035 plugin_path,
1036 argv,
1037 envv,
1038 strace_logging
1039 .as_ref()
1040 .map(|s| s.file.borrow(host.root()))
1041 .as_deref(),
1042 &shimlog_file,
1043 host.preload_paths(),
1044 )?;
1045 let native_pid = mthread.native_pid();
1046 let main_thread =
1047 Thread::wrap_mthread(host, mthread, desc_table, process_id, main_thread_id).unwrap();
1048
1049 debug!("process '{:?}' started", plugin_name);
1050
1051 if pause_for_debugging {
1052 log::logger().flush();
1056
1057 let msg = format!(
1064 "\
1065 \n** Pausing with SIGTSTP to enable debugger attachment to managed process\
1066 \n** '{plugin_name:?}' (pid {native_pid:?}).\
1067 \n** If running Shadow under Bash, resume Shadow by pressing Ctrl-Z to background\
1068 \n** this task, and then typing \"fg\".\
1069 \n** If running GDB, resume Shadow by typing \"signal SIGCONT\"."
1070 );
1071 eprintln!("{}", msg);
1072
1073 rustix::process::kill_process(rustix::process::getpid(), rustix::process::Signal::Tstp)
1074 .unwrap();
1075 }
1076
1077 let memory_manager = unsafe { MemoryManager::new(native_pid) };
1078 let threads = RefCell::new(BTreeMap::from([(
1079 main_thread_id,
1080 RootedRc::new(host.root(), RootedRefCell::new(host.root(), main_thread)),
1081 )]));
1082
1083 let common = Common {
1084 id: process_id,
1085 host_id: host.id(),
1086 working_dir,
1087 name,
1088 plugin_name,
1089 parent_pid: Cell::new(ProcessId::INIT),
1090 group_id: Cell::new(ProcessId::INIT),
1091 session_id: Cell::new(ProcessId::INIT),
1092 exit_signal: None,
1095 };
1096 Ok(RootedRc::new(
1097 host.root(),
1098 RootedRefCell::new(
1099 host.root(),
1100 Self {
1101 state: RefCell::new(Some(ProcessState::Runnable(RunnableProcess {
1102 common,
1103 expected_final_state: Some(expected_final_state),
1104 shim_shared_mem_block,
1105 memory_manager: Box::new(RefCell::new(memory_manager)),
1106 itimer_real,
1107 strace_logging,
1108 dumpable: Cell::new(SuidDump::SUID_DUMP_USER),
1109 native_pid,
1110 unsafe_borrow_mut: RefCell::new(None),
1111 unsafe_borrows: RefCell::new(Vec::new()),
1112 threads,
1113 #[cfg(feature = "perf_timers")]
1114 cpu_delay_timer: RefCell::new(PerfTimer::new_stopped()),
1115 #[cfg(feature = "perf_timers")]
1116 total_run_time: Cell::new(Duration::ZERO),
1117 child_process_event_listeners: Default::default(),
1118 shimlog_file,
1119 }))),
1120 },
1121 ),
1122 ))
1123 }
1124
1125 pub fn id(&self) -> ProcessId {
1126 self.common().id
1127 }
1128
1129 pub fn parent_id(&self) -> ProcessId {
1130 self.common().parent_pid.get()
1131 }
1132
1133 pub fn set_parent_id(&self, pid: ProcessId) {
1134 self.common().parent_pid.set(pid)
1135 }
1136
1137 pub fn group_id(&self) -> ProcessId {
1138 self.common().group_id.get()
1139 }
1140
1141 pub fn set_group_id(&self, id: ProcessId) {
1142 self.common().group_id.set(id)
1143 }
1144
1145 pub fn session_id(&self) -> ProcessId {
1146 self.common().session_id.get()
1147 }
1148
1149 pub fn set_session_id(&self, id: ProcessId) {
1150 self.common().session_id.set(id)
1151 }
1152
1153 pub fn host_id(&self) -> HostId {
1154 self.common().host_id
1155 }
1156
1157 pub fn dumpable(&self) -> SuidDump {
1160 self.as_runnable().unwrap().dumpable.get()
1161 }
1162
1163 pub fn set_dumpable(&self, val: SuidDump) {
1166 assert!(val == SuidDump::SUID_DUMP_DISABLE || val == SuidDump::SUID_DUMP_USER);
1167 self.as_runnable().unwrap().dumpable.set(val)
1168 }
1169
1170 #[cfg(feature = "perf_timers")]
1172 pub fn start_cpu_delay_timer(&self) {
1173 self.as_runnable().unwrap().start_cpu_delay_timer()
1174 }
1175
1176 #[cfg(feature = "perf_timers")]
1178 pub fn stop_cpu_delay_timer(&self, host: &Host) -> Duration {
1179 self.as_runnable().unwrap().stop_cpu_delay_timer(host)
1180 }
1181
1182 pub fn thread_group_leader_id(&self) -> ThreadId {
1183 self.common().thread_group_leader_id()
1184 }
1185
1186 pub fn resume(&self, host: &Host, tid: ThreadId) {
1189 trace!("Continuing thread {} in process {}", tid, self.id());
1190
1191 let threadrc = {
1192 let Some(runnable) = self.as_runnable() else {
1193 debug!("Process {} is no longer running", &*self.name());
1194 return;
1195 };
1196 let threads = runnable.threads.borrow();
1197 let Some(thread) = threads.get(&tid) else {
1198 debug!("Thread {} no longer exists", tid);
1199 return;
1200 };
1201 thread.clone(host.root())
1204 };
1205 let threadrc = ExplicitDropper::new(threadrc, |t| {
1206 t.explicit_drop_recursive(host.root(), host);
1207 });
1208 let thread = threadrc.borrow(host.root());
1209
1210 Worker::set_active_thread(&threadrc);
1211
1212 #[cfg(feature = "perf_timers")]
1213 self.start_cpu_delay_timer();
1214
1215 Process::set_shared_time(host);
1216
1217 host.shim_shmem_lock_borrow_mut()
1222 .unwrap()
1223 .unapplied_cpu_latency = SimulationTime::ZERO;
1224
1225 let ctx = ProcessContext::new(host, self);
1226 let res = thread.resume(&ctx);
1227
1228 #[cfg(feature = "perf_timers")]
1229 {
1230 let delay = self.stop_cpu_delay_timer(host);
1231 debug!("process '{}' ran for {:?}", &*self.name(), delay);
1232 }
1233 #[cfg(not(feature = "perf_timers"))]
1234 debug!("process '{}' done continuing", &*self.name());
1235
1236 match res {
1237 crate::host::thread::ResumeResult::Blocked => {
1238 debug!(
1239 "thread {tid} in process '{}' still running, but blocked",
1240 &*self.name()
1241 );
1242 }
1243 crate::host::thread::ResumeResult::ExitedThread(return_code) => {
1244 debug!(
1245 "thread {tid} in process '{}' exited with code {return_code}",
1246 &*self.name(),
1247 );
1248 let (threadrc, last_thread) = {
1249 let runnable = self.as_runnable().unwrap();
1250 let mut threads = runnable.threads.borrow_mut();
1251 let threadrc = threads.remove(&tid).unwrap();
1252 (threadrc, threads.is_empty())
1253 };
1254 self.as_runnable().unwrap().reap_thread(host, threadrc);
1255 if last_thread {
1256 self.handle_process_exit(host, false);
1257 }
1258 }
1259 crate::host::thread::ResumeResult::ExitedProcess => {
1260 debug!(
1261 "Process {} exited while running thread {tid}",
1262 &*self.name(),
1263 );
1264 self.handle_process_exit(host, false);
1265 }
1266 };
1267
1268 Worker::clear_active_thread();
1269 }
1270
1271 pub fn stop(&self, host: &Host) {
1275 {
1277 let Some(runnable) = self.as_runnable() else {
1278 debug!("process {} has already stopped", &*self.name());
1279 return;
1280 };
1281 debug!("terminating process {}", &*self.name());
1282
1283 #[cfg(feature = "perf_timers")]
1284 runnable.start_cpu_delay_timer();
1285
1286 if let Err(err) = rustix::process::kill_process(
1287 runnable.native_pid().into(),
1288 rustix::process::Signal::Kill,
1289 ) {
1290 warn!("kill: {:?}", err);
1291 }
1292
1293 #[cfg(feature = "perf_timers")]
1294 {
1295 let delay = runnable.stop_cpu_delay_timer(host);
1296 debug!("process '{}' stopped in {:?}", &*self.name(), delay);
1297 }
1298 #[cfg(not(feature = "perf_timers"))]
1299 debug!("process '{}' stopped", &*self.name());
1300 }
1301
1302 self.handle_process_exit(host, true);
1304 }
1305
1306 pub fn signal(&self, host: &Host, current_thread: Option<&Thread>, siginfo_t: &siginfo_t) {
1310 match self.state.borrow().as_ref().unwrap() {
1312 ProcessState::Runnable(r) => r.signal(host, current_thread, siginfo_t),
1313 ProcessState::Zombie(_) => {
1314 debug!("Process {} no longer running", &*self.name());
1316 }
1317 }
1318 }
1319
1320 fn open_stdio_file_helper(
1321 descriptor_table: &mut DescriptorTable,
1322 fd: DescriptorHandle,
1323 path: PathBuf,
1324 access_mode: OFlag,
1325 ) {
1326 let stdfile = unsafe { cshadow::regularfile_new() };
1327 let cwd = rustix::process::getcwd(Vec::new()).unwrap();
1328 let path = utility::pathbuf_to_nul_term_cstring(path);
1329 let access_mode = access_mode.bits();
1337 let errorcode = unsafe {
1338 cshadow::regularfile_open(
1339 stdfile,
1340 path.as_ptr(),
1341 access_mode | libc::O_CREAT | libc::O_TRUNC,
1342 libc::S_IRUSR | libc::S_IWUSR | libc::S_IRGRP | libc::S_IROTH,
1343 cwd.as_ptr(),
1344 )
1345 };
1346 if errorcode != 0 {
1347 panic!(
1348 "Opening {}: {:?}",
1349 path.to_str().unwrap(),
1350 linux_api::errno::Errno::try_from(-errorcode).unwrap()
1351 );
1352 }
1353 let desc = unsafe {
1354 Descriptor::from_legacy_file(
1355 stdfile as *mut cshadow::LegacyFile,
1356 linux_api::fcntl::OFlag::empty(),
1357 )
1358 };
1359 let prev = descriptor_table.register_descriptor_with_fd(desc, fd);
1360 assert!(prev.is_none());
1361 trace!(
1362 "Successfully opened fd {} at {}",
1363 fd,
1364 path.to_str().unwrap()
1365 );
1366 }
1367
1368 fn static_output_file_name(file_basename: &Path, extension: &str) -> PathBuf {
1370 let mut path = file_basename.to_owned().into_os_string();
1371 path.push(".");
1372 path.push(extension);
1373 path.into()
1374 }
1375
1376 pub fn name(&self) -> impl Deref<Target = str> + '_ {
1377 Ref::map(self.common(), |c| c.name.to_str().unwrap())
1378 }
1379
1380 pub fn plugin_name(&self) -> impl Deref<Target = str> + '_ {
1381 Ref::map(self.common(), |c| c.plugin_name.to_str().unwrap())
1382 }
1383
1384 #[track_caller]
1386 pub fn memory_borrow_mut(&self) -> impl DerefMut<Target = MemoryManager> + '_ {
1387 std_util::nested_ref::NestedRefMut::map(self.as_runnable().unwrap(), |runnable| {
1388 runnable.memory_manager.borrow_mut()
1389 })
1390 }
1391
1392 #[track_caller]
1394 pub fn memory_borrow(&self) -> impl Deref<Target = MemoryManager> + '_ {
1395 std_util::nested_ref::NestedRef::map(self.as_runnable().unwrap(), |runnable| {
1396 runnable.memory_manager.borrow()
1397 })
1398 }
1399
1400 pub fn strace_logging_options(&self) -> Option<FmtOptions> {
1402 self.as_runnable().unwrap().strace_logging_options()
1403 }
1404
1405 pub fn with_strace_file<T>(&self, f: impl FnOnce(&mut std::fs::File) -> T) -> Option<T> {
1407 self.as_runnable().unwrap().with_strace_file(f)
1408 }
1409
1410 pub fn native_pid(&self) -> Pid {
1412 self.as_runnable().unwrap().native_pid()
1413 }
1414
1415 #[track_caller]
1417 pub fn realtime_timer_borrow(&self) -> impl Deref<Target = Timer> + '_ {
1418 std_util::nested_ref::NestedRef::map(self.as_runnable().unwrap(), |runnable| {
1419 runnable.itimer_real.borrow()
1420 })
1421 }
1422
1423 #[track_caller]
1425 pub fn realtime_timer_borrow_mut(&self) -> impl DerefMut<Target = Timer> + '_ {
1426 std_util::nested_ref::NestedRefMut::map(self.as_runnable().unwrap(), |runnable| {
1427 runnable.itimer_real.borrow_mut()
1428 })
1429 }
1430
1431 #[track_caller]
1433 pub fn first_live_thread_borrow(
1434 &self,
1435 root: &Root,
1436 ) -> Option<impl Deref<Target = RootedRc<RootedRefCell<Thread>>> + '_> {
1437 std_util::nested_ref::NestedRef::filter_map(self.as_runnable()?, |runnable| {
1438 runnable.first_live_thread(root)
1439 })
1440 }
1441
1442 pub fn thread_borrow(
1444 &self,
1445 virtual_tid: ThreadId,
1446 ) -> Option<impl Deref<Target = RootedRc<RootedRefCell<Thread>>> + '_> {
1447 std_util::nested_ref::NestedRef::filter_map(self.as_runnable()?, |runnable| {
1448 runnable.thread(virtual_tid)
1449 })
1450 }
1451
1452 pub fn free_unsafe_borrows_flush(&self) -> Result<(), Errno> {
1454 self.as_runnable().unwrap().free_unsafe_borrows_flush()
1455 }
1456
1457 pub fn free_unsafe_borrows_noflush(&self) {
1459 self.as_runnable().unwrap().free_unsafe_borrows_noflush()
1460 }
1461
1462 pub fn physical_address(&self, vptr: ForeignPtr<()>) -> ManagedPhysicalMemoryAddr {
1463 self.common().physical_address(vptr)
1464 }
1465
1466 pub fn is_running(&self) -> bool {
1467 self.as_runnable().is_some()
1468 }
1469
1470 fn handle_process_exit(&self, host: &Host, killed_by_shadow: bool) {
1472 debug!(
1473 "process '{}' has completed or is otherwise no longer running",
1474 &*self.name()
1475 );
1476
1477 {
1482 let runnable = self.as_runnable().unwrap();
1483 let threads = std::mem::take(&mut *runnable.threads.borrow_mut());
1484 for (_tid, threadrc) in threads.into_iter() {
1485 threadrc.borrow(host.root()).handle_process_exit();
1486 runnable.reap_thread(host, threadrc);
1487 }
1488 }
1489
1490 let mut opt_state = self.state.borrow_mut();
1493
1494 let state = opt_state.take().unwrap();
1495 let ProcessState::Runnable(runnable) = state else {
1496 unreachable!("Tried to handle process exit of non-running process");
1497 };
1498
1499 #[cfg(feature = "perf_timers")]
1500 debug!(
1501 "total runtime for process '{}' was {:?}",
1502 runnable.common.name(),
1503 runnable.total_run_time.get()
1504 );
1505
1506 let wait_res: Option<WaitStatus> =
1507 rustix::process::waitpid(Some(runnable.native_pid().into()), WaitOptions::empty())
1508 .unwrap_or_else(|e| {
1509 panic!("Error waiting for {:?}: {:?}", runnable.native_pid(), e)
1510 });
1511 let wait_status = wait_res.unwrap();
1512 let exit_status = if killed_by_shadow {
1513 if wait_status.terminating_signal()
1514 != Some(Signal::SIGKILL.as_i32().try_into().unwrap())
1515 {
1516 warn!("Unexpected waitstatus after killed by shadow: {wait_status:?}");
1517 }
1518 ExitStatus::StoppedByShadow
1519 } else if let Some(code) = wait_status.exit_status() {
1520 ExitStatus::Normal(code.try_into().unwrap())
1521 } else if let Some(signal) = wait_status.terminating_signal() {
1522 ExitStatus::Signaled(Signal::try_from(i32::try_from(signal).unwrap()).unwrap())
1523 } else {
1524 panic!(
1525 "Unexpected status: {wait_status:?} for pid {:?}",
1526 runnable.native_pid()
1527 );
1528 };
1529
1530 let (main_result_string, log_level) = {
1531 let mut s = format!(
1532 "process '{name}' exited with status {exit_status:?}",
1533 name = runnable.common.name()
1534 );
1535 if let Some(expected_final_state) = runnable.expected_final_state {
1536 let actual_final_state = match exit_status {
1537 ExitStatus::Normal(i) => ProcessFinalState::Exited { exited: i },
1538 ExitStatus::Signaled(s) => ProcessFinalState::Signaled {
1539 signaled: s.try_into().unwrap(),
1543 },
1544 ExitStatus::StoppedByShadow => ProcessFinalState::Running(RunningVal::Running),
1545 };
1546 if expected_final_state == actual_final_state {
1547 (s, log::Level::Debug)
1548 } else {
1549 Worker::increment_plugin_error_count();
1550 write!(s, "; expected end state was {expected_final_state} but was {actual_final_state}").unwrap();
1551 (s, log::Level::Error)
1552 }
1553 } else {
1554 (s, log::Level::Debug)
1555 }
1556 };
1557 log::log!(log_level, "{}", main_result_string);
1558
1559 let zombie = ZombieProcess {
1560 common: runnable.into_common(),
1561 exit_status,
1562 };
1563 zombie.notify_parent_of_exit(host);
1564
1565 *opt_state = Some(ProcessState::Zombie(zombie));
1566 }
1567
1568 pub fn add_thread(&self, host: &Host, thread: RootedRc<RootedRefCell<Thread>>) {
1570 self.as_runnable().unwrap().add_thread(host, thread)
1571 }
1572
1573 fn set_shared_time(host: &Host) {
1576 let mut host_shmem = host.shim_shmem_lock_borrow_mut().unwrap();
1577 host_shmem.max_runahead_time = Worker::max_event_runahead_time(host);
1578 host.shim_shmem()
1579 .sim_time
1580 .store(Worker::current_time().unwrap(), Ordering::Relaxed);
1581 }
1582
1583 pub fn shmem(&self) -> impl Deref<Target = ShMemBlock<'static, ProcessShmem>> + '_ {
1585 Ref::map(self.as_runnable().unwrap(), |r| &r.shim_shared_mem_block)
1586 }
1587
1588 pub fn rusage(&self) -> linux_api::resource::rusage {
1590 warn_once_then_debug!(
1591 "resource usage (rusage) tracking unimplemented; Returning bogus zeroed values"
1592 );
1593 linux_api::resource::rusage {
1600 ru_utime: linux_api::time::kernel_old_timeval {
1601 tv_sec: 0,
1602 tv_usec: 0,
1603 },
1604 ru_stime: linux_api::time::kernel_old_timeval {
1605 tv_sec: 0,
1606 tv_usec: 0,
1607 },
1608 ru_maxrss: 0,
1609 ru_ixrss: 0,
1610 ru_idrss: 0,
1611 ru_isrss: 0,
1612 ru_minflt: 0,
1613 ru_majflt: 0,
1614 ru_nswap: 0,
1615 ru_inblock: 0,
1616 ru_oublock: 0,
1617 ru_msgsnd: 0,
1618 ru_msgrcv: 0,
1619 ru_nsignals: 0,
1620 ru_nvcsw: 0,
1621 ru_nivcsw: 0,
1622 }
1623 }
1624
1625 pub fn exit_signal(&self) -> Option<Signal> {
1627 self.common().exit_signal
1628 }
1629
1630 pub fn current_working_dir(&self) -> impl Deref<Target = CString> + '_ {
1631 Ref::map(self.common(), |common| &common.working_dir)
1632 }
1633
1634 pub fn set_current_working_dir(&self, path: CString) {
1639 self.common_mut().working_dir = path;
1640 }
1641
1642 pub fn update_for_exec(&mut self, host: &Host, tid: ThreadId, mthread: ManagedThread) {
1645 let Some(mut runnable) = self.as_runnable_mut() else {
1646 log::debug!(
1650 "Process {:?} exited before it could complete execve",
1651 self.id()
1652 );
1653 mthread.kill_and_drop();
1654 return;
1655 };
1656 let old_native_pid = std::mem::replace(&mut runnable.native_pid, mthread.native_pid());
1657
1658 rustix::process::kill_process(old_native_pid.into(), rustix::process::Signal::Kill)
1660 .expect("Unable to send kill signal to managed process {old_native_pid:?}");
1661 let wait_res = rustix::process::waitpid(Some(old_native_pid.into()), WaitOptions::empty())
1662 .unwrap()
1663 .unwrap();
1664 assert_eq!(
1665 wait_res.terminating_signal(),
1666 Some(Signal::SIGKILL.as_i32().try_into().unwrap())
1667 );
1668
1669 let execing_thread = runnable.threads.borrow_mut().remove(&tid).unwrap();
1670
1671 for (_tid, thread) in runnable.threads.replace(BTreeMap::new()) {
1673 thread.borrow(host.root()).mthread().handle_process_exit();
1675
1676 thread.explicit_drop_recursive(host.root(), host);
1677 }
1678
1679 {
1681 let unsafe_borrow_mut = runnable.unsafe_borrow_mut.borrow();
1686 let unsafe_borrows = runnable.unsafe_borrows.borrow();
1687 assert!(unsafe_borrow_mut.is_none());
1688 assert!(unsafe_borrows.is_empty());
1689 runnable
1692 .memory_manager
1693 .replace(unsafe { MemoryManager::new(mthread.native_pid()) });
1694 }
1695
1696 let new_tid = runnable.common.thread_group_leader_id();
1697 log::trace!(
1698 "updating for exec; pid:{pid}, tid:{tid:?}, new_tid:{new_tid:?}",
1699 pid = runnable.common.id
1700 );
1701 execing_thread
1702 .borrow_mut(host.root())
1703 .update_for_exec(host, mthread, new_tid);
1704
1705 runnable
1706 .threads
1707 .borrow_mut()
1708 .insert(new_tid, execing_thread);
1709
1710 runnable.common.exit_signal = Some(Signal::SIGCHLD);
1712
1713 let host_shmem_prot = host.shim_shmem_lock_borrow_mut().unwrap();
1721 let mut shmem_prot = runnable
1722 .shim_shared_mem_block
1723 .protected
1724 .borrow_mut(&host_shmem_prot.root);
1725 for signal in Signal::standard_signals() {
1726 let current_action = unsafe { shmem_prot.signal_action(signal) };
1727 if !(current_action.is_default()
1728 || current_action.is_ignore()
1729 || signal == Signal::SIGCHLD && current_action.is_ignore())
1730 {
1731 unsafe {
1732 *shmem_prot.signal_action_mut(signal) = linux_api::signal::sigaction::new_raw(
1733 linux_api::signal::SignalHandler::SigDfl,
1734 SigActionFlags::empty(),
1735 sigset_t::EMPTY,
1736 None,
1737 )
1738 };
1739 }
1740 }
1741 }
1742}
1743
1744impl Drop for Process {
1745 fn drop(&mut self) {
1746 debug_assert!(self.state.borrow().is_none());
1748 }
1749}
1750
1751impl ExplicitDrop for Process {
1752 type ExplicitDropParam = Host;
1753 type ExplicitDropResult = ();
1754
1755 fn explicit_drop(mut self, host: &Self::ExplicitDropParam) -> Self::ExplicitDropResult {
1756 debug_assert!(self.as_zombie().is_some() || std::thread::panicking());
1758
1759 let state = self.state.get_mut().take().unwrap();
1760 state.explicit_drop(host);
1761 }
1762}
1763
1764struct UnsafeBorrow {
1766 _memory: ProcessMemoryRef<'static, u8>,
1769 _manager: Ref<'static, MemoryManager>,
1770}
1771
1772impl UnsafeBorrow {
1773 unsafe fn readable_ptr(
1780 process: &Process,
1781 ptr: ForeignArrayPtr<u8>,
1782 ) -> Result<*const c_void, Errno> {
1783 let runnable = process.as_runnable().unwrap();
1784 let manager = runnable.memory_manager.borrow();
1785 let manager = unsafe {
1789 std::mem::transmute::<Ref<'_, MemoryManager>, Ref<'static, MemoryManager>>(manager)
1790 };
1791 let memory = manager.memory_ref(ptr)?;
1792 let memory = unsafe {
1793 std::mem::transmute::<ProcessMemoryRef<'_, u8>, ProcessMemoryRef<'static, u8>>(memory)
1794 };
1795 let vptr = memory.as_ptr() as *mut c_void;
1796 runnable.unsafe_borrows.borrow_mut().push(Self {
1797 _manager: manager,
1798 _memory: memory,
1799 });
1800 Ok(vptr)
1801 }
1802
1803 unsafe fn readable_string(
1810 process: &Process,
1811 ptr: ForeignArrayPtr<c_char>,
1812 ) -> Result<(*const c_char, libc::size_t), Errno> {
1813 let runnable = process.as_runnable().unwrap();
1814 let manager = runnable.memory_manager.borrow();
1815 let manager = unsafe {
1819 std::mem::transmute::<Ref<'_, MemoryManager>, Ref<'static, MemoryManager>>(manager)
1820 };
1821 let ptr = ptr.cast_u8();
1822 let memory = manager.memory_ref_prefix(ptr)?;
1823 let memory = unsafe {
1824 std::mem::transmute::<ProcessMemoryRef<'_, u8>, ProcessMemoryRef<'static, u8>>(memory)
1825 };
1826 if !memory.contains(&0) {
1827 return Err(Errno::ENAMETOOLONG);
1828 }
1829 assert_eq!(std::mem::size_of::<c_char>(), std::mem::size_of::<u8>());
1830 let ptr = memory.as_ptr() as *const c_char;
1831 let len = memory.len();
1832 runnable.unsafe_borrows.borrow_mut().push(Self {
1833 _manager: manager,
1834 _memory: memory,
1835 });
1836 Ok((ptr, len))
1837 }
1838}
1839
1840unsafe impl Send for UnsafeBorrow {}
1849
1850struct UnsafeBorrowMut {
1852 memory: Option<ProcessMemoryRefMut<'static, u8>>,
1855 _manager: RefMut<'static, MemoryManager>,
1856}
1857
1858impl UnsafeBorrowMut {
1859 unsafe fn writable_ptr(
1866 process: &Process,
1867 ptr: ForeignArrayPtr<u8>,
1868 ) -> Result<*mut c_void, Errno> {
1869 let runnable = process.as_runnable().unwrap();
1870 let manager = runnable.memory_manager.borrow_mut();
1871 let mut manager = unsafe {
1875 std::mem::transmute::<RefMut<'_, MemoryManager>, RefMut<'static, MemoryManager>>(
1876 manager,
1877 )
1878 };
1879 let memory = manager.memory_ref_mut_uninit(ptr)?;
1880 let mut memory = unsafe {
1881 std::mem::transmute::<ProcessMemoryRefMut<'_, u8>, ProcessMemoryRefMut<'static, u8>>(
1882 memory,
1883 )
1884 };
1885 let vptr = memory.as_mut_ptr() as *mut c_void;
1886 let prev = runnable.unsafe_borrow_mut.borrow_mut().replace(Self {
1887 _manager: manager,
1888 memory: Some(memory),
1889 });
1890 assert!(prev.is_none());
1891 Ok(vptr)
1892 }
1893
1894 unsafe fn mutable_ptr(
1901 process: &Process,
1902 ptr: ForeignArrayPtr<u8>,
1903 ) -> Result<*mut c_void, Errno> {
1904 let runnable = process.as_runnable().unwrap();
1905 let manager = runnable.memory_manager.borrow_mut();
1906 let mut manager = unsafe {
1910 std::mem::transmute::<RefMut<'_, MemoryManager>, RefMut<'static, MemoryManager>>(
1911 manager,
1912 )
1913 };
1914 let memory = manager.memory_ref_mut(ptr)?;
1915 let mut memory = unsafe {
1916 std::mem::transmute::<ProcessMemoryRefMut<'_, u8>, ProcessMemoryRefMut<'static, u8>>(
1917 memory,
1918 )
1919 };
1920 let vptr = memory.as_mut_ptr() as *mut c_void;
1921 let prev = runnable.unsafe_borrow_mut.borrow_mut().replace(Self {
1922 _manager: manager,
1923 memory: Some(memory),
1924 });
1925 assert!(prev.is_none());
1926 Ok(vptr)
1927 }
1928
1929 fn flush(mut self) -> Result<(), Errno> {
1931 self.memory.take().unwrap().flush()
1932 }
1933
1934 fn noflush(mut self) {
1936 self.memory.take().unwrap().noflush()
1937 }
1938}
1939
1940unsafe impl Send for UnsafeBorrowMut {}
1948
1949fn make_name(host: &Host, exe_name: &str, id: ProcessId) -> CString {
1950 CString::new(format!(
1951 "{host_name}.{exe_name}.{id}",
1952 host_name = host.name(),
1953 exe_name = exe_name,
1954 id = u32::from(id)
1955 ))
1956 .unwrap()
1957}
1958
1959mod export {
1960 use std::os::raw::c_void;
1961
1962 use libc::size_t;
1963 use log::trace;
1964 use shadow_shim_helper_rs::notnull::*;
1965 use shadow_shim_helper_rs::shim_shmem::export::ShimShmemProcess;
1966 use shadow_shim_helper_rs::syscall_types::UntypedForeignPtr;
1967
1968 use super::*;
1969 use crate::utility::HostTreePointer;
1970
1971 #[unsafe(no_mangle)]
1974 pub extern "C-unwind" fn process_readPtr(
1975 proc: *const Process,
1976 dst: *mut c_void,
1977 src: UntypedForeignPtr,
1978 n: usize,
1979 ) -> i32 {
1980 let proc = unsafe { proc.as_ref().unwrap() };
1981 let src = ForeignArrayPtr::new(src.cast::<u8>(), n);
1982 let dst = unsafe { std::slice::from_raw_parts_mut(notnull_mut_debug(dst) as *mut u8, n) };
1983
1984 match proc.memory_borrow().copy_from_ptr(dst, src) {
1985 Ok(_) => 0,
1986 Err(e) => {
1987 trace!("Couldn't read {:?} into {:?}: {:?}", src, dst, e);
1988 e.to_negated_i32()
1989 }
1990 }
1991 }
1992
1993 #[unsafe(no_mangle)]
1996 pub unsafe extern "C-unwind" fn process_writePtr(
1997 proc: *const Process,
1998 dst: UntypedForeignPtr,
1999 src: *const c_void,
2000 n: usize,
2001 ) -> i32 {
2002 let proc = unsafe { proc.as_ref().unwrap() };
2003 let dst = ForeignArrayPtr::new(dst.cast::<u8>(), n);
2004 let src = unsafe { std::slice::from_raw_parts(notnull_debug(src) as *const u8, n) };
2005 match proc.memory_borrow_mut().copy_to_ptr(dst, src) {
2006 Ok(_) => 0,
2007 Err(e) => {
2008 trace!("Couldn't write {:?} into {:?}: {:?}", src, dst, e);
2009 e.to_negated_i32()
2010 }
2011 }
2012 }
2013
2014 #[unsafe(no_mangle)]
2019 pub unsafe extern "C-unwind" fn process_getReadablePtr(
2020 proc: *const Process,
2021 plugin_src: UntypedForeignPtr,
2022 n: usize,
2023 ) -> *const c_void {
2024 let proc = unsafe { proc.as_ref().unwrap() };
2025 let plugin_src = ForeignArrayPtr::new(plugin_src.cast::<u8>(), n);
2026 unsafe { UnsafeBorrow::readable_ptr(proc, plugin_src).unwrap_or(std::ptr::null()) }
2027 }
2028
2029 #[unsafe(no_mangle)]
2039 pub unsafe extern "C-unwind" fn process_getWriteablePtr(
2040 proc: *const Process,
2041 plugin_src: UntypedForeignPtr,
2042 n: usize,
2043 ) -> *mut c_void {
2044 let proc = unsafe { proc.as_ref().unwrap() };
2045 let plugin_src = ForeignArrayPtr::new(plugin_src.cast::<u8>(), n);
2046 unsafe { UnsafeBorrowMut::writable_ptr(proc, plugin_src).unwrap_or(std::ptr::null_mut()) }
2047 }
2048
2049 #[unsafe(no_mangle)]
2055 pub unsafe extern "C-unwind" fn process_getMutablePtr(
2056 proc: *const Process,
2057 plugin_src: UntypedForeignPtr,
2058 n: usize,
2059 ) -> *mut c_void {
2060 let proc = unsafe { proc.as_ref().unwrap() };
2061 let plugin_src = ForeignArrayPtr::new(plugin_src.cast::<u8>(), n);
2062 unsafe { UnsafeBorrowMut::mutable_ptr(proc, plugin_src).unwrap_or(std::ptr::null_mut()) }
2063 }
2064
2065 #[unsafe(no_mangle)]
2072 pub unsafe extern "C-unwind" fn process_readString(
2073 proc: *const Process,
2074 strbuf: *mut libc::c_char,
2075 ptr: UntypedForeignPtr,
2076 maxlen: libc::size_t,
2077 ) -> libc::ssize_t {
2078 let proc = unsafe { proc.as_ref().unwrap() };
2079 let memory_manager = proc.memory_borrow();
2080 let buf =
2081 unsafe { std::slice::from_raw_parts_mut(notnull_mut_debug(strbuf) as *mut u8, maxlen) };
2082 let cstr = match memory_manager
2083 .copy_str_from_ptr(buf, ForeignArrayPtr::new(ptr.cast::<u8>(), maxlen))
2084 {
2085 Ok(cstr) => cstr,
2086 Err(e) => return e.to_negated_i32() as isize,
2087 };
2088 cstr.to_bytes().len().try_into().unwrap()
2089 }
2090
2091 #[unsafe(no_mangle)]
2098 pub unsafe extern "C-unwind" fn process_getReadableString(
2099 proc: *const Process,
2100 plugin_src: UntypedForeignPtr,
2101 n: usize,
2102 out_str: *mut *const c_char,
2103 out_strlen: *mut size_t,
2104 ) -> i32 {
2105 let proc = unsafe { proc.as_ref().unwrap() };
2106 let ptr = ForeignArrayPtr::new(plugin_src.cast::<c_char>(), n);
2107 match unsafe { UnsafeBorrow::readable_string(proc, ptr) } {
2108 Ok((str, strlen)) => {
2109 assert!(!out_str.is_null());
2110 unsafe { out_str.write(str) };
2111 if !out_strlen.is_null() {
2112 unsafe { out_strlen.write(strlen) };
2113 }
2114 0
2115 }
2116 Err(e) => e.to_negated_i32(),
2117 }
2118 }
2119
2120 #[unsafe(no_mangle)]
2122 pub unsafe extern "C-unwind" fn process_getProcessID(proc: *const Process) -> libc::pid_t {
2123 let proc = unsafe { proc.as_ref().unwrap() };
2124 proc.id().into()
2125 }
2126
2127 #[unsafe(no_mangle)]
2128 pub unsafe extern "C-unwind" fn process_getName(proc: *const Process) -> *const c_char {
2129 let proc = unsafe { proc.as_ref().unwrap() };
2130 proc.common().name.as_ptr()
2131 }
2132
2133 #[unsafe(no_mangle)]
2138 pub unsafe extern "C-unwind" fn process_getSharedMem(
2139 proc: *const Process,
2140 ) -> *const ShimShmemProcess {
2141 let proc = unsafe { proc.as_ref().unwrap() };
2142 std::ptr::from_ref(proc.as_runnable().unwrap().shim_shared_mem_block.deref())
2143 }
2144
2145 #[unsafe(no_mangle)]
2146 pub unsafe extern "C-unwind" fn process_getWorkingDir(proc: *const Process) -> *const c_char {
2147 let proc = unsafe { proc.as_ref().unwrap() };
2148 proc.common().working_dir.as_ptr()
2149 }
2150
2151 #[unsafe(no_mangle)]
2152 pub unsafe extern "C-unwind" fn process_straceLoggingMode(
2153 proc: *const Process,
2154 ) -> StraceFmtMode {
2155 let proc = unsafe { proc.as_ref().unwrap() };
2156 proc.strace_logging_options().into()
2157 }
2158
2159 #[unsafe(no_mangle)]
2160 pub unsafe extern "C-unwind" fn process_getNativePid(proc: *const Process) -> libc::pid_t {
2161 let proc = unsafe { proc.as_ref().unwrap() };
2162 proc.native_pid().as_raw_nonzero().get()
2163 }
2164
2165 #[unsafe(no_mangle)]
2172 pub unsafe extern "C-unwind" fn process_flushPtrs(proc: *const Process) -> i32 {
2173 let proc = unsafe { proc.as_ref().unwrap() };
2174 match proc.free_unsafe_borrows_flush() {
2175 Ok(_) => 0,
2176 Err(e) => e.to_negated_i32(),
2177 }
2178 }
2179
2180 #[unsafe(no_mangle)]
2186 pub unsafe extern "C-unwind" fn process_freePtrsWithoutFlushing(proc: *const Process) {
2187 let proc = unsafe { proc.as_ref().unwrap() };
2188 proc.free_unsafe_borrows_noflush();
2189 }
2190
2191 #[unsafe(no_mangle)]
2192 pub unsafe extern "C-unwind" fn process_getThread(
2193 proc: *const Process,
2194 tid: libc::pid_t,
2195 ) -> *const Thread {
2196 let proc = unsafe { proc.as_ref().unwrap() };
2197 Worker::with_active_host(|host| {
2198 let tid = ThreadId::try_from(tid).unwrap();
2199 let Some(thread) = proc.thread_borrow(tid) else {
2200 return std::ptr::null();
2201 };
2202 let thread = thread.borrow(host.root());
2203 &*thread
2204 })
2205 .unwrap()
2206 }
2207
2208 #[unsafe(no_mangle)]
2210 pub unsafe extern "C-unwind" fn process_firstLiveThread(proc: *const Process) -> *const Thread {
2211 let proc = unsafe { proc.as_ref().unwrap() };
2212 Worker::with_active_host(|host| {
2213 let Some(thread) = proc.first_live_thread_borrow(host.root()) else {
2214 return std::ptr::null();
2215 };
2216 let thread = thread.borrow(host.root());
2217 &*thread
2218 })
2219 .unwrap()
2220 }
2221
2222 #[unsafe(no_mangle)]
2223 pub unsafe extern "C-unwind" fn process_isRunning(proc: *const Process) -> bool {
2224 let proc = unsafe { proc.as_ref().unwrap() };
2225 proc.is_running()
2226 }
2227
2228 #[unsafe(no_mangle)]
2231 pub unsafe extern "C-unwind" fn process_setSharedTime() {
2232 Worker::with_active_host(Process::set_shared_time).unwrap();
2233 }
2234
2235 #[unsafe(no_mangle)]
2236 pub unsafe extern "C-unwind" fn process_getPhysicalAddress(
2237 proc: *const Process,
2238 vptr: UntypedForeignPtr,
2239 ) -> ManagedPhysicalMemoryAddr {
2240 let proc = unsafe { proc.as_ref().unwrap() };
2241 proc.physical_address(vptr)
2242 }
2243
2244 #[unsafe(no_mangle)]
2245 pub unsafe extern "C-unwind" fn process_addChildEventListener(
2246 host: *const Host,
2247 process: *const Process,
2248 listener: *mut cshadow::StatusListener,
2249 ) {
2250 let host = unsafe { host.as_ref().unwrap() };
2251 let process = unsafe { process.as_ref().unwrap() };
2252 let listener = HostTreePointer::new_for_host(host.id(), listener);
2253 process
2254 .borrow_as_runnable()
2255 .unwrap()
2256 .child_process_event_listeners
2257 .borrow_mut()
2258 .add_legacy_listener(listener)
2259 }
2260
2261 #[unsafe(no_mangle)]
2262 pub unsafe extern "C-unwind" fn process_removeChildEventListener(
2263 _host: *const Host,
2264 process: *const Process,
2265 listener: *mut cshadow::StatusListener,
2266 ) {
2267 let process = unsafe { process.as_ref().unwrap() };
2268 process
2269 .borrow_as_runnable()
2270 .unwrap()
2271 .child_process_event_listeners
2272 .borrow_mut()
2273 .remove_legacy_listener(listener)
2274 }
2275}