1use crate::device::terminal::{Terminal, TerminalController};
6use crate::mutable_state::{state_accessor, state_implementation};
7use crate::ptrace::{
8 AtomicStopState, PtraceAllowedPtracers, PtraceEvent, PtraceOptions, PtraceStatus, PtraceTracer,
9 StopState, ZombiePtracees, ptrace_detach,
10};
11use crate::security;
12use crate::signals::syscalls::WaitingOptions;
13use crate::signals::{
14 DeliveryAction, IntoSignalInfoOptions, QueuedSignals, SignalActions, SignalDetail, SignalInfo,
15 UncheckedSignalInfo, action_for_signal, send_standard_signal,
16};
17use crate::task::memory_attribution::MemoryAttributionLifecycleEvent;
18use crate::task::{
19 ControllingTerminal, CurrentTask, ExitStatus, Kernel, Pid, PidTable, PidTableGuard,
20 ProcessGroup, Session, SessionDisassociation, Task, TaskMutableState, TaskPersistentInfo,
21 TypedWaitQueue, WaitResult, ZombieProcess, ZombieState,
22};
23use crate::time::{IntervalTimerHandle, TimerTable};
24use itertools::Itertools;
25use macro_rules_attribute::apply;
26use starnix_lifecycle::{AtomicCounter, DropNotifier};
27use starnix_logging::{log_debug, log_error, log_info, log_warn, track_stub};
28use starnix_sync::{
29 LockDepMutex, LockDepRwLock, ThreadGroupLimits, ThreadGroupMutableStateLock,
30 ThreadGroupPendingSignalsLock, ThreadGroupPtraceesLock, allow_subclass, ordered_write_lock,
31};
32use starnix_task_command::TaskCommand;
33use starnix_types::ownership::{OwnedRef, Releasable};
34use starnix_types::stats::TaskTimeStats;
35use starnix_types::time::{itimerspec_from_itimerval, timeval_from_duration};
36use starnix_uapi::auth::{CAP_SYS_ADMIN, CAP_SYS_RESOURCE};
37use starnix_uapi::errors::Errno;
38use starnix_uapi::personality::PersonalityFlags;
39use starnix_uapi::resource_limits::{Resource, ResourceLimits};
40use starnix_uapi::signals::{
41 SIGCHLD, SIGCONT, SIGHUP, SIGKILL, SIGTERM, SIGTTOU, SigSet, Signal, UncheckedSignal,
42};
43use starnix_uapi::user_address::UserAddress;
44use starnix_uapi::{
45 ITIMER_PROF, ITIMER_REAL, ITIMER_VIRTUAL, SA_NOCLDWAIT, SI_TKILL, SI_USER, SIG_IGN, errno,
46 error, itimerval, pid_t, rlimit, tid_t,
47};
48use std::collections::{BTreeMap, HashSet};
49use std::fmt;
50use std::sync::atomic::{AtomicBool, Ordering};
51use std::sync::{Arc, Weak};
52use zx::{Koid, Status};
53
54#[derive(Debug)]
55pub struct ZirconProcess {
56 process: zx::Process,
57 koid: Result<Koid, Status>,
58}
59
60impl ZirconProcess {
61 pub fn new(process: zx::Process) -> Self {
62 let koid = process.koid();
63 Self { process, koid }
64 }
65
66 pub fn koid(&self) -> Result<Koid, Status> {
67 self.koid
68 }
69}
70
71impl std::ops::Deref for ZirconProcess {
72 type Target = zx::Process;
73 fn deref(&self) -> &Self::Target {
74 &self.process
75 }
76}
77
78#[repr(u64)]
80pub enum ThreadGroupLifecycleWaitValue {
81 ChildStatus,
83 Stopped,
85}
86
87impl Into<u64> for ThreadGroupLifecycleWaitValue {
88 fn into(self) -> u64 {
89 self as u64
90 }
91}
92
93#[derive(Clone, Debug)]
96pub struct DeferredZombiePTracer {
97 pub tracer_pid: Pid,
99 pub tracee_tid: Pid,
101 pub tracee_pgid: Pid,
103 pub tracee_pid: Pid,
105}
106
107impl DeferredZombiePTracer {
108 fn new(tracer: &ThreadGroup, tracee: &Task, tracee_pgid: Pid) -> Self {
109 Self {
110 tracer_pid: tracer.leader.clone(),
111 tracee_tid: tracee.tid.clone(),
112 tracee_pgid,
113 tracee_pid: tracee.pid.clone(),
114 }
115 }
116}
117
118pub struct ThreadGroupMutableState {
120 pub parent: Option<ThreadGroupParent>,
125
126 pub exit_signal: Option<Signal>,
128
129 tasks: HashSet<TaskPersistentInfo>,
136
137 pub children: BTreeMap<pid_t, Weak<ThreadGroup>>,
144
145 pub zombie_children: Vec<OwnedRef<ZombieProcess>>,
147
148 pub zombie_ptracees: ZombiePtracees,
150
151 pub deferred_zombie_ptracers: Vec<DeferredZombiePTracer>,
154
155 pub lifecycle_waiters: TypedWaitQueue<ThreadGroupLifecycleWaitValue>,
157
158 pub is_child_subreaper: bool,
161
162 pub process_group: Arc<ProcessGroup>,
164
165 pub did_exec: bool,
166
167 pub last_signal: Option<SignalInfo>,
171
172 run_state: ThreadGroupRunState,
176
177 pub children_time_stats: TaskTimeStats,
179
180 pub personality: PersonalityFlags,
182
183 pub allowed_ptracers: PtraceAllowedPtracers,
185
186 exit_notifier: Option<futures::channel::oneshot::Sender<()>>,
188
189 pub notifier: Option<std::sync::mpsc::Sender<MemoryAttributionLifecycleEvent>>,
191}
192
193pub struct ThreadGroup {
217 pub weak_self: Weak<ThreadGroup>,
220
221 pub kernel: Arc<Kernel>,
223
224 pub process: ZirconProcess,
233
234 pub root_vmar: zx::Vmar,
236
237 pub leader: Pid,
241
242 pub signal_actions: Arc<SignalActions>,
244
245 pub timers: TimerTable,
247
248 pub drop_notifier: DropNotifier,
250
251 stop_state: AtomicStopState,
255
256 mutable_state: LockDepRwLock<ThreadGroupMutableState, ThreadGroupMutableStateLock>,
258
259 pub limits: LockDepMutex<ResourceLimits, ThreadGroupLimits>,
263
264 pub next_seccomp_filter_id: AtomicCounter<u64>,
269
270 pub ptracees: LockDepMutex<HashSet<TaskPersistentInfo>, ThreadGroupPtraceesLock>,
272
273 pub pending_signals: LockDepMutex<QueuedSignals, ThreadGroupPendingSignalsLock>,
275
276 pub has_pending_signals: AtomicBool,
279
280 pub start_time: zx::MonotonicInstant,
282
283 log_syscalls_as_info: AtomicBool,
285}
286
287impl fmt::Debug for ThreadGroup {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 write!(
290 f,
291 "{}({})",
292 self.process.get_name().unwrap_or(zx::Name::new_lossy("<unknown>")),
293 self.leader
294 )
295 }
296}
297
298impl ThreadGroup {
299 pub fn sync_syscall_log_level(&self) {
300 let command = self.read().leader_command();
301 let filters = self.kernel.syscall_log_filters.lock();
302 let should_log = filters.iter().any(|f| f.matches(&command));
303 let prev_should_log = self.log_syscalls_as_info.swap(should_log, Ordering::Relaxed);
304 let change_str = match (should_log, prev_should_log) {
305 (true, false) => Some("Enabled"),
306 (false, true) => Some("Disabled"),
307 _ => None,
308 };
309 if let Some(change_str) = change_str {
310 log_info!(
311 "{change_str} info syscall logs for thread group {} (command: {command})",
312 self.leader
313 );
314 }
315 }
316
317 #[inline]
318 pub fn syscall_log_level(&self) -> starnix_logging::Level {
319 if self.log_syscalls_as_info.load(Ordering::Relaxed) {
320 starnix_logging::Level::Info
321 } else {
322 starnix_logging::Level::Trace
323 }
324 }
325}
326
327impl PartialEq for ThreadGroup {
328 fn eq(&self, other: &Self) -> bool {
329 self.leader == other.leader
330 }
331}
332
333impl Drop for ThreadGroup {
334 fn drop(&mut self) {
335 let state = self.mutable_state.get_mut();
336 assert!(state.tasks.is_empty());
337 assert!(state.children.is_empty());
338 assert!(state.zombie_children.is_empty());
339 assert!(state.zombie_ptracees.is_empty());
340 #[cfg(any(test, debug_assertions))]
341 assert!(
342 state
343 .parent
344 .as_ref()
345 .and_then(|p| p.0.upgrade().as_ref().map(|p| p
346 .read()
347 .children
348 .get(&self.leader.id)
349 .is_none()))
350 .unwrap_or(true)
351 );
352 }
353}
354
355pub struct ThreadGroupParent(Weak<ThreadGroup>);
358
359impl ThreadGroupParent {
360 pub fn new(t: Weak<ThreadGroup>) -> Self {
361 debug_assert!(t.upgrade().is_some());
362 Self(t)
363 }
364
365 pub fn upgrade(&self) -> Arc<ThreadGroup> {
366 self.0.upgrade().expect("ThreadGroupParent references must always be valid")
367 }
368}
369
370impl Clone for ThreadGroupParent {
371 fn clone(&self) -> Self {
372 Self(self.0.clone())
373 }
374}
375
376#[derive(Debug, Clone)]
379pub enum ProcessSelector {
380 Any,
382 Pid(Pid),
384 Pgid(Pid),
386}
387
388impl ProcessSelector {
389 pub fn match_tid(&self, tid: &Pid) -> bool {
390 match self {
391 ProcessSelector::Pid(pid) => {
392 if pid == tid {
393 true
394 } else if let Ok(task_ref) = tid.get_task() {
395 &task_ref.pid == pid
396 } else {
397 false
398 }
399 }
400 ProcessSelector::Any => true,
401 ProcessSelector::Pgid(pgid) => {
402 if let Ok(task_ref) = tid.get_task() {
403 &task_ref.thread_group().read().process_group.leader == pgid
404 } else {
405 false
406 }
407 }
408 }
409 }
410}
411
412#[derive(Clone, Debug, Default, PartialEq, Eq)]
413enum ThreadGroupRunState {
414 #[default]
415 Running,
416 Exiting(ExitStatus),
417 Exited(ExitStatus),
418}
419
420impl ThreadGroup {
421 pub fn new(
423 kernel: Arc<Kernel>,
424 process: zx::Process,
425 root_vmar: zx::Vmar,
426 parent: Option<ThreadGroupWriteGuard<'_>>,
427 leader: Pid,
428 exit_signal: Option<Signal>,
429 process_group: Arc<ProcessGroup>,
430 signal_actions: Arc<SignalActions>,
431 ) -> Arc<ThreadGroup> {
432 debug_assert!(!process.is_invalid());
433 debug_assert!(!root_vmar.is_invalid());
434 Self::new_internal(
435 kernel,
436 process,
437 root_vmar,
438 parent,
439 leader,
440 exit_signal,
441 process_group,
442 signal_actions,
443 )
444 }
445
446 pub fn for_system(
448 kernel: Arc<Kernel>,
449 leader: Pid,
450 process_group: Arc<ProcessGroup>,
451 ) -> Arc<ThreadGroup> {
452 Self::new_internal(
453 kernel,
454 zx::Process::invalid(),
455 zx::Vmar::invalid(),
456 None,
457 leader,
458 Some(SIGCHLD),
459 process_group,
460 SignalActions::default(),
461 )
462 }
463
464 pub fn for_test(
472 kernel: Arc<Kernel>,
473 process: zx::Process,
474 parent: ThreadGroupWriteGuard<'_>,
475 leader: Pid,
476 process_group: Arc<ProcessGroup>,
477 ) -> Arc<ThreadGroup> {
478 Self::new_internal(
479 kernel,
480 process,
481 zx::Vmar::invalid(),
482 Some(parent),
483 leader,
484 Some(SIGCHLD),
485 process_group,
486 SignalActions::default(),
487 )
488 }
489
490 fn new_internal(
491 kernel: Arc<Kernel>,
492 process: zx::Process,
493 root_vmar: zx::Vmar,
494 parent: Option<ThreadGroupWriteGuard<'_>>,
495 leader: Pid,
496 exit_signal: Option<Signal>,
497 process_group: Arc<ProcessGroup>,
498 signal_actions: Arc<SignalActions>,
499 ) -> Arc<ThreadGroup> {
500 Arc::new_cyclic(|weak_self| {
501 let process = ZirconProcess::new(process);
502 let mut thread_group = ThreadGroup {
503 weak_self: weak_self.clone(),
504 kernel,
505 process,
506 root_vmar,
507 leader,
508 signal_actions,
509 timers: Default::default(),
510 drop_notifier: Default::default(),
511 limits: LockDepMutex::new(
514 parent
515 .as_ref()
516 .map(|p| p.base.limits.lock().clone())
517 .unwrap_or(Default::default()),
518 ),
519 next_seccomp_filter_id: Default::default(),
520 ptracees: Default::default(),
521 stop_state: AtomicStopState::new(StopState::Awake),
522 pending_signals: Default::default(),
523 has_pending_signals: Default::default(),
524 start_time: zx::MonotonicInstant::get(),
525 mutable_state: ThreadGroupMutableState {
526 parent: parent
527 .as_ref()
528 .map(|p| ThreadGroupParent::new(p.base.weak_self.clone())),
529 exit_signal,
530 tasks: HashSet::new(),
531 children: BTreeMap::new(),
532 zombie_children: vec![],
533 zombie_ptracees: ZombiePtracees::new(),
534 deferred_zombie_ptracers: vec![],
535 lifecycle_waiters: TypedWaitQueue::<ThreadGroupLifecycleWaitValue>::default(),
536 is_child_subreaper: false,
537 process_group: Arc::clone(&process_group),
538 did_exec: false,
539 last_signal: None,
540 run_state: Default::default(),
541 children_time_stats: Default::default(),
542 personality: parent
543 .as_ref()
544 .map(|p| p.personality)
545 .unwrap_or(Default::default()),
546 allowed_ptracers: PtraceAllowedPtracers::None,
547 exit_notifier: None,
548 notifier: None,
549 }
550 .into(),
551 log_syscalls_as_info: AtomicBool::new(false),
552 };
553
554 if let Some(mut parent) = parent {
555 thread_group.next_seccomp_filter_id.reset(parent.base.next_seccomp_filter_id.get());
556 parent.children.insert(thread_group.leader.id, weak_self.clone());
557 process_group.insert(&thread_group);
558 };
559 thread_group
560 })
561 }
562
563 state_accessor!(ThreadGroup, mutable_state);
564
565 pub fn load_stopped(&self) -> StopState {
566 self.stop_state.load(Ordering::Relaxed)
567 }
568
569 pub fn kill(&self, exit_status: ExitStatus, mut current_task: Option<&mut CurrentTask>) {
578 if let Some(ref mut current_task) = current_task {
579 current_task
580 .ptrace_event(PtraceOptions::TRACEEXIT, exit_status.signal_info_status() as u64);
581 }
582 let mut pids = self.kernel.pids.lock();
583 let mut state = self.write();
584 if !state.is_running() {
585 return;
586 }
587
588 state.run_state = ThreadGroupRunState::Exiting(exit_status.clone());
589
590 let zombie_notifications = state.zombie_ptracees.detach_all(&mut pids);
592
593 let tasks = state.tasks();
596 drop(state);
597
598 for notification in zombie_notifications {
599 notification.deliver(&mut pids);
600 }
601 self.detach_ptracees(&mut pids);
602
603 for task in tasks {
604 task.write().set_exit_status(exit_status.clone());
605 send_standard_signal(&task, SignalInfo::kernel(SIGKILL));
606 }
607 }
608
609 pub fn add(&self, task: Arc<Task>) -> Result<(), Errno> {
610 let mut state = self.write();
611 if !state.is_running() {
612 if state.tasks_count() == 0 {
613 log_warn!(
614 "Task {} with leader {} not running while adding its first task, \
615 not sending creation notification",
616 task.tid,
617 self.leader
618 );
619 }
620 return error!(EINVAL);
621 }
622 state.tasks.insert(task.persistent_info.clone());
623
624 Ok(())
625 }
626
627 pub fn remove(&self, mut pids: PidTableGuard<'_>, task: &Arc<Task>) {
632 task.set_ptrace_zombie(&mut pids);
633 pids.remove_task(&task.tid);
634
635 let mut state = self.write();
636
637 if !state.tasks.remove(&task.persistent_info) {
638 debug_assert!(!state.is_running());
641 return;
642 }
643
644 if state.tasks.is_empty() {
645 let exit_status = if let ThreadGroupRunState::Exiting(exit_status) = &state.run_state {
646 exit_status.clone()
647 } else {
648 let exit_status = task.exit_status().unwrap_or_else(|| {
649 log_error!("Exiting without an exit code.");
650 ExitStatus::Exit(u8::MAX)
651 });
652 state.set_exiting(exit_status.clone());
653 exit_status
654 };
655
656 let zombie_notifications = state.zombie_ptracees.detach_all(&mut pids);
658
659 let zombie = ZombieProcess::new(
661 task.clone(),
662 state.as_ref(),
663 exit_status,
664 state.exit_signal.clone(),
665 );
666 pids.kill_process(&self.leader);
667
668 let session = state.leave_process_group(&mut pids);
669
670 std::mem::drop(state);
680
681 session.disassociate_controlling_terminal();
684
685 for notification in zombie_notifications {
686 notification.deliver(&mut pids);
687 }
688
689 self.kernel.cgroups.lock_cgroup2_pid_table().remove_process(&self.leader);
693
694 self.detach_ptracees(&mut pids);
695
696 let parent = self.read().parent.clone();
699 let reaper = self.find_reaper();
700
701 {
702 if let Some(reaper) = reaper {
704 let reaper = reaper.upgrade();
705 {
706 let mut reaper_state = reaper.write();
707 let _token = allow_subclass();
711 let mut state = self.write();
712 for (_pid, weak_child) in std::mem::take(&mut state.children) {
713 if let Some(child) = weak_child.upgrade() {
714 let _token = allow_subclass();
719 let mut child_state = child.write();
720
721 child_state.exit_signal = Some(SIGCHLD);
722 child_state.parent =
723 Some(ThreadGroupParent::new(Arc::downgrade(&reaper)));
724 reaper_state.children.insert(child.leader.id, weak_child);
725 }
726 }
727 reaper_state.zombie_children.append(&mut state.zombie_children);
728 }
729 ZombiePtracees::reparent(self, &reaper);
730 } else {
731 let mut state = self.write();
733 for zombie in state.zombie_children.drain(..) {
734 zombie.release(&mut pids);
735 }
736 }
737 }
738
739 self.write().parent = None;
741
742 #[cfg(any(test, debug_assertions))]
743 {
744 let state = self.read();
745 assert!(state.zombie_children.is_empty());
746 assert!(state.zombie_ptracees.is_empty());
747 }
748
749 if let Some(ref parent) = parent {
750 let parent = parent.upgrade();
751
752 let tracer_tg = task
753 .read()
754 .ptrace
755 .as_ref()
756 .and_then(|ptrace| ptrace.core_state.thread_group.upgrade());
757
758 let maybe_zombie = match tracer_tg {
759 Some(tracer_tg) => {
760 tracer_tg.maybe_notify_tracer(task, &mut pids, &parent, zombie)
761 }
762 None => Some(zombie),
763 };
764
765 if let Some(zombie) = maybe_zombie {
766 parent.do_zombie_notifications(zombie, &mut pids);
767 }
768 } else {
769 zombie.release(&mut pids);
770 }
771
772 if let Some(parent) = parent {
778 let parent = parent.upgrade();
779 parent.check_orphans(&pids);
780 }
781
782 self.write().set_exited();
783 }
784 }
785
786 fn detach_ptracees(&self, pids: &mut PidTableGuard<'_>) {
788 let tracee_tids = self.ptracees.lock().iter().map(|info| info.tid.clone()).collect_vec();
789 for tracee_tid in tracee_tids {
790 let Ok(tracee) = tracee_tid.get_task() else {
791 continue;
792 };
793
794 let mut should_send_sigkill = false;
795 if let Some(ptrace) = &tracee.read().ptrace {
796 should_send_sigkill = ptrace.has_option(PtraceOptions::EXITKILL);
797 }
798 if should_send_sigkill {
799 send_standard_signal(tracee.as_ref(), SignalInfo::kernel(SIGKILL));
800 }
801
802 let _ = ptrace_detach(
803 pids,
804 PtraceTracer::Exiting(self),
805 tracee.as_ref(),
806 &UserAddress::NULL,
807 );
808 }
809 }
810
811 pub fn do_zombie_notifications(
812 &self,
813 zombie: OwnedRef<ZombieProcess>,
814 pids: &mut PidTableGuard<'_>,
815 ) {
816 let mut state = self.write();
817
818 state.children.remove(&zombie.task.get_pid());
819 state.deferred_zombie_ptracers.retain(|dzp| dzp.tracee_pid != zombie.task.pid);
820
821 let exit_signal = zombie.exit_signal;
822 let mut signal_info = zombie.to_wait_result().as_signal_info();
823
824 let should_make_zombie = if exit_signal == Some(SIGCHLD) {
834 let action = self.signal_actions.get(SIGCHLD);
835 action.sa_handler != SIG_IGN && (action.sa_flags & SA_NOCLDWAIT as u64) == 0
836 } else {
837 true
838 };
839 if should_make_zombie {
840 state.zombie_children.push(zombie);
841 } else {
842 state.reap_zombie(zombie, pids);
843 }
844
845 state.lifecycle_waiters.notify_value(ThreadGroupLifecycleWaitValue::ChildStatus);
846
847 if let Some(exit_signal) = exit_signal {
849 signal_info.signal = exit_signal;
850 state.send_signal(signal_info);
851 }
852 }
853
854 fn maybe_notify_tracer(
858 &self,
859 tracee: &Task,
860 pids: &mut PidTableGuard<'_>,
861 parent: &ThreadGroup,
862 zombie: OwnedRef<ZombieProcess>,
863 ) -> Option<OwnedRef<ZombieProcess>> {
864 let mut state = self.write();
865 if state.zombie_ptracees.has_tracee(&tracee.tid) {
866 if self == parent {
867 if let Some(zombie_notification) = state.zombie_ptracees.detach(pids, &tracee.tid) {
872 zombie_notification.discard(pids);
873 }
874 return Some(zombie);
875 } else {
876 if !state.is_running() {
879 return Some(zombie);
881 }
882
883 drop(state);
886 {
887 let tracee_pgid = tracee.thread_group().read().process_group.leader.clone();
889 let mut parent_state = parent.write();
890 parent_state.deferred_zombie_ptracers.push(DeferredZombiePTracer::new(
891 self,
892 tracee,
893 tracee_pgid,
894 ));
895 parent_state.children.remove(&tracee.get_pid());
896 }
897
898 let mut state = self.write();
904 state.zombie_ptracees.set_parent_of(&tracee.tid, Some(zombie), parent);
905 tracee.write().notify_ptracers();
906 return None;
907 }
908 } else if self == parent {
909 parent.write().children.remove(&tracee.tid.id);
912 zombie.release(pids);
913 return None;
914 }
915 Some(zombie)
918 }
919
920 fn find_reaper(&self) -> Option<ThreadGroupParent> {
922 let mut weak_parent = self.read().parent.clone()?;
923 loop {
924 weak_parent = {
925 let parent = weak_parent.upgrade();
926 let parent_state = parent.read();
927 if parent_state.is_child_subreaper {
928 break;
929 }
930 match parent_state.parent {
931 Some(ref next_parent) => next_parent.clone(),
932 None => break,
933 }
934 };
935 }
936 Some(weak_parent)
937 }
938
939 pub fn setsid(&self) -> Result<(), Errno> {
940 let mut pids = self.kernel.pids.lock();
941 let pid = self.leader.clone();
942 if pid.get_process_group().is_ok() {
943 return error!(EPERM);
944 }
945 let process_group = ProcessGroup::new(pid, None);
946 pids.add_process_group(&process_group);
947 let session = self.write().set_process_group(process_group, &mut pids);
948 session.disassociate_controlling_terminal();
949 self.check_orphans(&pids);
950
951 Ok(())
952 }
953
954 pub fn setpgid(
955 &self,
956 current_task: &CurrentTask,
957 target: &Task,
958 pgid: &Pid,
959 ) -> Result<(), Errno> {
960 let mut pids = self.kernel.pids.lock();
961
962 {
963 let current_process_group = Arc::clone(&self.read().process_group);
964
965 let mut target_thread_group = target.thread_group().write();
967 let is_target_current_process_child = target_thread_group
968 .parent
969 .as_ref()
970 .is_some_and(|tg| tg.upgrade().leader == self.leader);
971 if target_thread_group.base.leader != self.leader && !is_target_current_process_child {
972 return error!(ESRCH);
973 }
974
975 if is_target_current_process_child && target_thread_group.did_exec {
978 return error!(EACCES);
979 }
980
981 let new_process_group;
982 {
983 let target_process_group = &target_thread_group.process_group;
984
985 if target_thread_group.base.leader == target_process_group.session.leader
987 || current_process_group.session != target_process_group.session
988 {
989 return error!(EPERM);
990 }
991
992 if *pgid == target_process_group.leader {
993 return Ok(());
994 }
995
996 if let Ok(process_group) = pgid.get_process_group() {
999 if process_group.session != target_process_group.session {
1000 return error!(EPERM);
1001 }
1002 security::check_setpgid_access(current_task, target)?;
1003 new_process_group = process_group;
1004 } else if *pgid == target_thread_group.base.leader {
1005 security::check_setpgid_access(current_task, target)?;
1006 new_process_group = ProcessGroup::new(
1008 target_thread_group.base.leader.clone(),
1009 Some(target_process_group.session.clone()),
1010 );
1011 pids.add_process_group(&new_process_group);
1012 } else {
1013 return error!(EPERM);
1014 }
1015 }
1016
1017 let session = target_thread_group.set_process_group(new_process_group, &mut pids);
1018 std::mem::drop(target_thread_group);
1019 session.disassociate_controlling_terminal();
1022 }
1023
1024 target.thread_group().check_orphans(&pids);
1025
1026 Ok(())
1027 }
1028
1029 fn itimer_real(&self) -> IntervalTimerHandle {
1030 self.timers.itimer_real()
1031 }
1032
1033 pub fn set_itimer(
1034 &self,
1035 current_task: &CurrentTask,
1036 which: u32,
1037 value: itimerval,
1038 ) -> Result<itimerval, Errno> {
1039 if which == ITIMER_PROF || which == ITIMER_VIRTUAL {
1040 if value.it_value.tv_sec == 0 && value.it_value.tv_usec == 0 {
1044 return Ok(itimerval::default());
1045 }
1046 track_stub!(TODO("https://fxbug.dev/322874521"), "Unsupported itimer type", which);
1047 return error!(ENOTSUP);
1048 }
1049
1050 if which != ITIMER_REAL {
1051 return error!(EINVAL);
1052 }
1053 let itimer_real = self.itimer_real();
1054 let prev_remaining = itimer_real.time_remaining();
1055 if value.it_value.tv_sec != 0 || value.it_value.tv_usec != 0 {
1056 itimer_real.arm(current_task, itimerspec_from_itimerval(value), false)?;
1057 } else {
1058 itimer_real.disarm(current_task)?;
1059 }
1060 Ok(itimerval {
1061 it_value: timeval_from_duration(prev_remaining.remainder),
1062 it_interval: timeval_from_duration(prev_remaining.interval),
1063 })
1064 }
1065
1066 pub fn get_itimer(&self, which: u32) -> Result<itimerval, Errno> {
1067 if which == ITIMER_PROF || which == ITIMER_VIRTUAL {
1068 return Ok(itimerval::default());
1070 }
1071 if which != ITIMER_REAL {
1072 return error!(EINVAL);
1073 }
1074 let remaining = self.itimer_real().time_remaining();
1075 Ok(itimerval {
1076 it_value: timeval_from_duration(remaining.remainder),
1077 it_interval: timeval_from_duration(remaining.interval),
1078 })
1079 }
1080
1081 fn check_stopped_state(
1084 &self,
1085 new_stopped: StopState,
1086 finalize_only: bool,
1087 ) -> Option<StopState> {
1088 let stopped = self.load_stopped();
1089 if finalize_only && !stopped.is_stopping_or_stopped() {
1090 return Some(stopped);
1091 }
1092
1093 if stopped.is_illegal_transition(new_stopped) {
1094 return Some(stopped);
1095 }
1096
1097 return None;
1098 }
1099
1100 pub fn set_stopped(
1107 &self,
1108 new_stopped: StopState,
1109 siginfo: Option<SignalInfo>,
1110 finalize_only: bool,
1111 ) -> StopState {
1112 if let Some(stopped) = self.check_stopped_state(new_stopped, finalize_only) {
1114 return stopped;
1115 }
1116
1117 self.write().set_stopped(new_stopped, siginfo, finalize_only)
1118 }
1119
1120 fn check_terminal_controller(
1123 session: &Arc<Session>,
1124 terminal_controller: &Option<TerminalController>,
1125 ) -> Result<(), Errno> {
1126 if let Some(terminal_controller) = terminal_controller {
1127 if let Some(terminal_session) = terminal_controller.session.upgrade() {
1128 if Arc::ptr_eq(session, &terminal_session) {
1129 return Ok(());
1130 }
1131 }
1132 }
1133 error!(ENOTTY)
1134 }
1135
1136 pub fn get_foreground_process_group(&self, terminal: &Terminal) -> Result<pid_t, Errno> {
1137 let state = self.read();
1138 let process_group = &state.process_group;
1139 let terminal_state = terminal.read();
1140
1141 Self::check_terminal_controller(&process_group.session, &terminal_state.controller)?;
1144 let pid = process_group.session.read().get_foreground_process_group_leader().id;
1145 Ok(pid)
1146 }
1147
1148 pub fn set_foreground_process_group(
1149 &self,
1150 current_task: &CurrentTask,
1151 terminal: &Terminal,
1152 pgid: &Pid,
1153 ) -> Result<(), Errno> {
1154 let process_group;
1155 let send_ttou;
1156 {
1157 let state = self.read();
1159 process_group = Arc::clone(&state.process_group);
1160 let terminal_state = terminal.read();
1161 Self::check_terminal_controller(&process_group.session, &terminal_state.controller)?;
1162
1163 let new_process_group = pgid.get_process_group()?;
1164 if new_process_group.session != process_group.session {
1165 return error!(EPERM);
1166 }
1167
1168 let mut session_state = process_group.session.write();
1169 send_ttou = &process_group.leader
1172 != session_state.get_foreground_process_group_leader()
1173 && !current_task.read().signal_mask().has_signal(SIGTTOU)
1174 && self.signal_actions.get(SIGTTOU).sa_handler != SIG_IGN;
1175
1176 if !send_ttou {
1177 session_state.set_foreground_process_group(pgid);
1178 }
1179 }
1180
1181 if send_ttou {
1183 process_group.send_signals(&[SIGTTOU]);
1184 return error!(EINTR);
1185 }
1186
1187 Ok(())
1188 }
1189
1190 pub fn set_controlling_terminal(
1191 &self,
1192 current_task: &CurrentTask,
1193 terminal: &Terminal,
1194 is_main: bool,
1195 steal: bool,
1196 is_readable: bool,
1197 ) -> Result<(), Errno> {
1198 let state = self.read();
1200 let process_group = &state.process_group;
1201 let mut terminal_state = terminal.write();
1202
1203 let other_session = terminal_state.controller.as_ref().and_then(|cs| cs.session.upgrade());
1206 let (mut session_writer, other_session) =
1207 if let Some(other_session) = other_session.as_ref() {
1208 if *other_session == process_group.session {
1209 (process_group.session.mutable_state.write(), None)
1210 } else {
1211 let (session_writer, other_session_writer) = ordered_write_lock(
1212 &process_group.session.mutable_state,
1213 &other_session.mutable_state,
1214 );
1215 (session_writer, Some((other_session, other_session_writer)))
1216 }
1217 } else {
1218 (process_group.session.mutable_state.write(), None)
1219 };
1220
1221 if process_group.session.leader != self.leader {
1224 return error!(EINVAL);
1225 }
1226 if let Some(ref current_ct) = session_writer.controlling_terminal {
1227 if current_ct.matches(terminal, is_main) {
1228 return Ok(());
1229 } else {
1230 return error!(EINVAL);
1231 }
1232 }
1233
1234 let mut has_admin_capability_determined = false;
1235
1236 if let Some((other_session, mut other_session_writer)) = other_session {
1242 debug_assert!(*other_session != process_group.session);
1243 if !steal {
1244 return error!(EPERM);
1245 }
1246 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1247 has_admin_capability_determined = true;
1248
1249 other_session_writer.controlling_terminal = None;
1251 }
1252
1253 if !is_readable && !has_admin_capability_determined {
1254 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1255 }
1256
1257 session_writer.controlling_terminal = Some(ControllingTerminal::new(terminal, is_main));
1258 terminal_state.controller = TerminalController::new(&process_group.session);
1259 Ok(())
1260 }
1261
1262 pub fn release_controlling_terminal(
1263 &self,
1264 _current_task: &CurrentTask,
1265 terminal: &Terminal,
1266 is_main: bool,
1267 ) -> Result<(), Errno> {
1268 let process_group;
1269 {
1270 let state = self.read();
1272 process_group = Arc::clone(&state.process_group);
1273 let mut terminal_state = terminal.write();
1274 let mut session_writer = process_group.session.write();
1275
1276 Self::check_terminal_controller(&process_group.session, &terminal_state.controller)?;
1278 if !session_writer
1279 .controlling_terminal
1280 .as_ref()
1281 .map_or(false, |ct| ct.matches(terminal, is_main))
1282 {
1283 return error!(ENOTTY);
1284 }
1285
1286 session_writer.controlling_terminal = None;
1294 terminal_state.controller = None;
1295 }
1296
1297 if process_group.session.leader == self.leader {
1298 process_group.send_signals(&[SIGHUP, SIGCONT]);
1299 }
1300
1301 Ok(())
1302 }
1303
1304 fn check_orphans(&self, pids: &PidTable) {
1305 let mut thread_groups = self.read().children().collect::<Vec<_>>();
1306 let this = self.weak_self.upgrade().unwrap();
1307 thread_groups.push(this);
1308 let process_groups =
1309 thread_groups.iter().map(|tg| Arc::clone(&tg.read().process_group)).unique();
1310 for pg in process_groups {
1311 pg.check_orphaned(pids);
1312 }
1313 }
1314
1315 pub fn get_rlimit(&self, resource: Resource) -> u64 {
1316 self.limits.lock().get(resource).rlim_cur
1317 }
1318
1319 pub fn adjust_rlimits(
1321 current_task: &CurrentTask,
1322 target_task: &Task,
1323 resource: Resource,
1324 maybe_new_limit: Option<rlimit>,
1325 ) -> Result<rlimit, Errno> {
1326 let thread_group = target_task.thread_group();
1327 let mut limit_state = thread_group.limits.lock();
1328 let old_limit = limit_state.get(resource);
1329 if let Some(new_limit) = maybe_new_limit {
1330 if new_limit.rlim_max > old_limit.rlim_max
1331 && !security::is_task_capable_noaudit(current_task, CAP_SYS_RESOURCE)
1332 {
1333 return error!(EPERM);
1334 }
1335 security::task_setrlimit(current_task, &target_task, old_limit, new_limit)?;
1336 limit_state.set(resource, new_limit)
1337 }
1338 Ok(old_limit)
1339 }
1340
1341 pub fn time_stats(&self) -> TaskTimeStats {
1342 let process: &zx::Process = if self.process.as_handle_ref().is_invalid() {
1343 assert_eq!(
1346 self as *const ThreadGroup,
1347 Arc::as_ptr(&self.kernel.kthreads.system_thread_group())
1348 );
1349 &self.kernel.kthreads.starnix_process
1350 } else {
1351 &self.process
1352 };
1353
1354 let info =
1355 zx::Task::get_runtime_info(process).expect("Failed to get starnix process stats");
1356 TaskTimeStats {
1357 user_time: zx::MonotonicDuration::from_nanos(info.cpu_time),
1358 system_time: zx::MonotonicDuration::default(),
1360 }
1361 }
1362
1363 pub fn get_ptracees_and(
1367 &self,
1368 selector: &ProcessSelector,
1369 f: &mut dyn FnMut(&Task, &TaskMutableState),
1370 ) {
1371 for task_ref in self
1372 .ptracees
1373 .lock()
1374 .iter()
1375 .filter(|info| selector.match_tid(&info.tid))
1376 .filter_map(|info| info.tid.get_task().ok())
1377 {
1378 let task_state = task_ref.write();
1379 if task_state.ptrace.is_some() {
1380 f(&task_ref, &task_state);
1381 }
1382 }
1383 }
1384
1385 pub fn get_waitable_ptracee(
1390 &self,
1391 selector: &ProcessSelector,
1392 options: &WaitingOptions,
1393 pids: &mut PidTableGuard<'_>,
1394 ) -> Option<WaitResult> {
1395 let waitable_entry = self.write().zombie_ptracees.get_waitable_entry(selector, options);
1397 match waitable_entry {
1398 None => (),
1399 Some((zombie, None)) => return Some(zombie.to_wait_result()),
1400 Some((zombie, Some((tg, z)))) => {
1401 if let Some(tg) = tg.upgrade() {
1402 if Arc::as_ptr(&tg) != self as *const Self {
1403 tg.do_zombie_notifications(z, pids);
1404 } else {
1405 {
1406 let mut state = tg.write();
1407 state.children.remove(&z.task.get_pid());
1408 state
1409 .deferred_zombie_ptracers
1410 .retain(|dzp| dzp.tracee_pid != z.task.pid);
1411 }
1412
1413 z.release(pids);
1414 };
1415 }
1416 return Some(zombie.to_wait_result());
1417 }
1418 }
1419
1420 let mut tasks = vec![];
1421
1422 self.get_ptracees_and(selector, &mut |task: &Task, _| {
1424 tasks.push(task.weak_self.clone());
1425 });
1426 for task in tasks {
1427 let Some(task_ref) = task.upgrade() else {
1428 continue;
1429 };
1430
1431 let process_state = &mut task_ref.thread_group().write();
1432 let mut task_state = task_ref.write();
1433 if task_state
1434 .ptrace
1435 .as_ref()
1436 .is_some_and(|ptrace| ptrace.is_waitable(task_ref.load_stopped(), options))
1437 {
1438 let info = process_state.tasks.iter().next().unwrap().clone();
1444 let uid = info.real_creds().uid;
1445 let mut exit_status = None;
1446 let exit_signal = process_state.exit_signal.clone();
1447 let time_stats =
1448 process_state.base.time_stats() + process_state.children_time_stats;
1449 let task_stopped = task_ref.load_stopped();
1450
1451 #[derive(PartialEq)]
1452 enum ExitType {
1453 None,
1454 Cont,
1455 Stop,
1456 Kill,
1457 }
1458 if process_state.is_waitable() {
1459 let ptrace = &mut task_state.ptrace;
1460 let process_stopped = process_state.base.load_stopped();
1462 let mut fn_type = ExitType::None;
1463 if process_stopped == StopState::Awake && options.wait_for_continued {
1464 fn_type = ExitType::Cont;
1465 }
1466 let mut event = ptrace
1467 .as_ref()
1468 .map_or(PtraceEvent::None, |ptrace| {
1469 ptrace.event_data.as_ref().map_or(PtraceEvent::None, |data| data.event)
1470 })
1471 .clone();
1472 if process_stopped == StopState::GroupStopped
1474 && (options.wait_for_stopped || ptrace.is_some())
1475 {
1476 fn_type = ExitType::Stop;
1477 }
1478 if fn_type != ExitType::None {
1479 let siginfo = if options.keep_waitable_state {
1480 process_state.last_signal.clone()
1481 } else {
1482 process_state.last_signal.take()
1483 };
1484 if let Some(mut siginfo) = siginfo {
1485 if task_ref.thread_group().load_stopped() == StopState::GroupStopped
1486 && ptrace.as_ref().is_some_and(|ptrace| ptrace.is_seized())
1487 {
1488 if event == PtraceEvent::None {
1489 event = PtraceEvent::Stop;
1490 }
1491 siginfo.code |= (PtraceEvent::Stop as i32) << 8;
1492 }
1493 if siginfo.signal == SIGKILL {
1494 fn_type = ExitType::Kill;
1495 }
1496 exit_status = match fn_type {
1497 ExitType::Stop => Some((
1498 ExitStatus::Stop(siginfo, event),
1499 process_state.base.leader.clone(),
1500 )),
1501 ExitType::Cont => Some((
1502 ExitStatus::Continue(siginfo, event),
1503 process_state.base.leader.clone(),
1504 )),
1505 ExitType::Kill => Some((
1506 ExitStatus::Kill(siginfo),
1507 process_state.base.leader.clone(),
1508 )),
1509 _ => None,
1510 };
1511 }
1512 ptrace
1515 .as_mut()
1516 .map(|ptrace| ptrace.get_last_signal(options.keep_waitable_state));
1517 }
1518 }
1519 if exit_status.is_none() {
1520 if let Some(ptrace) = task_state.ptrace.as_mut() {
1521 let mut fn_type = ExitType::None;
1523 let event = ptrace
1524 .event_data
1525 .as_ref()
1526 .map_or(PtraceEvent::None, |event| event.event);
1527 if task_stopped == StopState::Awake {
1528 fn_type = ExitType::Cont;
1529 }
1530 if task_stopped.is_stopping_or_stopped()
1531 || ptrace.stop_status == PtraceStatus::Listening
1532 {
1533 fn_type = ExitType::Stop;
1534 }
1535 if fn_type != ExitType::None {
1536 if let Some(siginfo) =
1537 ptrace.get_last_signal(options.keep_waitable_state)
1538 {
1539 if siginfo.signal == SIGKILL {
1540 fn_type = ExitType::Kill;
1541 }
1542 exit_status = match fn_type {
1543 ExitType::Stop => Some((
1544 ExitStatus::Stop(siginfo, event),
1545 task_ref.tid.clone(),
1546 )),
1547 ExitType::Cont => Some((
1548 ExitStatus::Continue(siginfo, event),
1549 task_ref.tid.clone(),
1550 )),
1551 ExitType::Kill => {
1552 Some((ExitStatus::Kill(siginfo), task_ref.tid.clone()))
1553 }
1554 _ => None,
1555 };
1556 }
1557 }
1558 }
1559 }
1560 if let Some((exit_status, pid)) = exit_status {
1561 return Some(WaitResult {
1562 pid,
1563 uid,
1564 zombie_state: ZombieState { exit_status, time_stats },
1565 exit_signal,
1566 });
1567 }
1568 }
1569 }
1570 None
1571 }
1572
1573 pub fn send_signal_unchecked(
1583 &self,
1584 current_task: &CurrentTask,
1585 unchecked_signal: UncheckedSignal,
1586 ) -> Result<(), Errno> {
1587 if let Some(signal) = self.check_signal_access(current_task, unchecked_signal)? {
1588 let signal_info = SignalInfo::with_detail(
1589 signal,
1590 SI_USER as i32,
1591 SignalDetail::Kill {
1592 pid: current_task.pid.clone(),
1593 uid: current_task.current_creds().uid,
1594 },
1595 );
1596
1597 self.write().send_signal(signal_info);
1598 }
1599
1600 Ok(())
1601 }
1602
1603 pub unsafe fn send_signal_unchecked_debug(
1608 &self,
1609 current_task: &CurrentTask,
1610 unchecked_signal: UncheckedSignal,
1611 ) -> Result<(), Errno> {
1612 let signal = Signal::try_from(unchecked_signal)?;
1613 let signal_info = SignalInfo::with_detail(
1614 signal,
1615 SI_USER as i32,
1616 SignalDetail::Kill {
1617 pid: current_task.pid.clone(),
1618 uid: current_task.current_creds().uid,
1619 },
1620 );
1621
1622 self.write().send_signal(signal_info);
1623 Ok(())
1624 }
1625
1626 #[track_caller]
1639 pub fn send_signal_unchecked_with_info(
1640 &self,
1641 current_task: &CurrentTask,
1642 unchecked_signal: UncheckedSignal,
1643 siginfo_ref: UserAddress,
1644 options: IntoSignalInfoOptions,
1645 ) -> Result<(), Errno> {
1646 let siginfo = UncheckedSignalInfo::read_from_siginfo(current_task, siginfo_ref)?;
1647 if self.leader.id != current_task.get_pid()
1648 && (siginfo.code() >= 0 || siginfo.code() == SI_TKILL)
1649 {
1650 return error!(EPERM);
1651 }
1652
1653 if matches!(options, IntoSignalInfoOptions::CheckSigno)
1654 && siginfo.signo() as u64 != unchecked_signal.raw()
1655 {
1656 return error!(EINVAL);
1657 }
1658
1659 if let Some(signal) = self.check_signal_access(current_task, unchecked_signal)? {
1660 self.write().send_signal(siginfo.into_signal_info(signal, options)?);
1661 }
1662
1663 Ok(())
1664 }
1665
1666 fn check_signal_access(
1674 &self,
1675 current_task: &CurrentTask,
1676 unchecked_signal: UncheckedSignal,
1677 ) -> Result<Option<Signal>, Errno> {
1678 let Some(target_task) = self.read().get_signalable_task() else {
1682 return Ok(None);
1686 };
1687 current_task.can_signal(&target_task, unchecked_signal)?;
1688
1689 if unchecked_signal.is_zero() {
1691 return Ok(None);
1692 }
1693
1694 let signal = Signal::try_from(unchecked_signal)?;
1695 security::check_signal_access(current_task, &target_task, signal)?;
1696
1697 Ok(Some(signal))
1698 }
1699
1700 pub fn has_signal_queued(&self, signal: Signal) -> bool {
1701 self.pending_signals.lock().has_queued(signal)
1702 }
1703
1704 pub fn num_signals_queued(&self) -> usize {
1705 self.pending_signals.lock().num_queued()
1706 }
1707
1708 pub fn get_pending_signals(&self) -> SigSet {
1709 self.pending_signals.lock().pending()
1710 }
1711
1712 pub fn is_any_signal_allowed_by_mask(&self, mask: SigSet) -> bool {
1713 self.pending_signals.lock().is_any_allowed_by_mask(mask)
1714 }
1715
1716 pub fn take_next_signal_where<F>(&self, predicate: F) -> Option<SignalInfo>
1717 where
1718 F: Fn(&SignalInfo) -> bool,
1719 {
1720 let mut signals = self.pending_signals.lock();
1721 let r = signals.take_next_where(predicate);
1722 self.has_pending_signals.store(!signals.is_empty(), Ordering::Relaxed);
1723 r
1724 }
1725
1726 pub async fn shut_down(this: Weak<Self>) {
1732 const SHUTDOWN_SIGNAL_HANDLING_TIMEOUT: zx::MonotonicDuration =
1733 zx::MonotonicDuration::from_seconds(1);
1734
1735 let (tg_name, mut on_exited) = {
1737 let Some(this) = this.upgrade() else {
1739 return;
1740 };
1741
1742 let mut state = this.write();
1743 if state.is_exited() {
1744 return;
1746 }
1747
1748 let (on_exited_send, on_exited) = futures::channel::oneshot::channel();
1750 state.exit_notifier = Some(on_exited_send);
1751
1752 let tg_name = format!("{this:?}");
1754
1755 (tg_name, on_exited)
1756 };
1757
1758 log_debug!(tg:% = tg_name; "shutting down thread group, sending SIGTERM");
1759 this.upgrade().map(|tg| tg.write().send_signal(SignalInfo::kernel(SIGTERM)));
1760
1761 let timeout = fuchsia_async::Timer::new(SHUTDOWN_SIGNAL_HANDLING_TIMEOUT);
1763 futures::pin_mut!(timeout);
1764
1765 futures::select_biased! {
1767 _ = &mut on_exited => (),
1768 _ = timeout => {
1769 log_debug!(tg:% = tg_name; "sending SIGKILL");
1770 this.upgrade().map(|tg| tg.write().send_signal(SignalInfo::kernel(SIGKILL)));
1771 },
1772 };
1773
1774 log_debug!(tg:% = tg_name; "waiting for exit");
1775 on_exited.await.ok();
1778 log_debug!(tg:% = tg_name; "thread group shutdown complete");
1779 }
1780
1781 pub fn get_process_koid(&self) -> Result<Koid, Status> {
1787 self.process.koid()
1788 }
1789}
1790
1791pub enum WaitableChildResult {
1792 ReadyNow(Box<WaitResult>),
1793 ShouldWait,
1794 NoneFound,
1795}
1796
1797#[apply(state_implementation!)]
1798impl ThreadGroupMutableState<Base = ThreadGroup> {
1799 pub fn leader(&self) -> pid_t {
1800 self.base.leader.id
1801 }
1802
1803 pub fn leader_command(&self) -> TaskCommand {
1804 self.get_task(self.leader())
1805 .map(|l| l.command())
1806 .unwrap_or_else(|| TaskCommand::new(b"<leader exited>"))
1807 }
1808
1809 pub fn is_running(&self) -> bool {
1810 matches!(self.run_state, ThreadGroupRunState::Running)
1811 }
1812
1813 pub fn is_exited(&self) -> bool {
1814 matches!(self.run_state, ThreadGroupRunState::Exited(_))
1815 }
1816
1817 fn set_exiting(&mut self, exit_status: ExitStatus) {
1818 self.run_state = ThreadGroupRunState::Exiting(exit_status);
1819 }
1820
1821 fn set_exited(&mut self) {
1822 let ThreadGroupRunState::Exiting(exit_status) = std::mem::take(&mut self.run_state) else {
1823 panic!("Must transition from Exiting to Exited");
1824 };
1825 self.run_state = ThreadGroupRunState::Exited(exit_status);
1826
1827 if let Some(notifier) = self.exit_notifier.take() {
1828 let _ = notifier.send(());
1829 }
1830 }
1831
1832 pub fn children(&self) -> impl Iterator<Item = Arc<ThreadGroup>> + '_ {
1833 self.children.values().map(|v| {
1834 v.upgrade().expect("Weak references to processes in ThreadGroup must always be valid")
1835 })
1836 }
1837
1838 pub fn tasks(&self) -> Vec<Arc<Task>> {
1839 self.tasks.iter().flat_map(|info| info.tid.get_task().ok()).collect()
1840 }
1841
1842 pub fn task_ids(&self) -> impl Iterator<Item = tid_t> + '_ {
1843 self.tasks.iter().map(|info| info.tid.id)
1844 }
1845
1846 pub fn contains_task(&self, tid: tid_t) -> bool {
1847 self.tasks.iter().any(|info| info.tid.id == tid)
1848 }
1849
1850 pub fn get_task(&self, tid: tid_t) -> Option<Arc<Task>> {
1851 self.tasks.iter().find(|info| info.tid.id == tid).and_then(|info| info.tid.get_task().ok())
1852 }
1853
1854 pub fn tasks_count(&self) -> usize {
1855 self.tasks.len()
1856 }
1857
1858 pub fn get_ppid(&self) -> pid_t {
1859 match &self.parent {
1860 Some(parent) => parent.upgrade().leader.id,
1861 None => 0,
1862 }
1863 }
1864
1865 fn set_process_group(
1873 &mut self,
1874 process_group: Arc<ProcessGroup>,
1875 pids: &mut PidTableGuard<'_>,
1876 ) -> SessionDisassociation {
1877 if self.process_group == process_group {
1878 return SessionDisassociation::new(None);
1879 }
1880 let session = self.leave_process_group(pids);
1881 self.process_group = process_group;
1882 self.process_group.insert(self.base);
1883 session
1884 }
1885
1886 fn leave_process_group(&mut self, pids: &mut PidTableGuard<'_>) -> SessionDisassociation {
1894 let (is_empty, disassociation) = self.process_group.remove(self.base);
1895 if is_empty {
1896 self.process_group.session.write().remove(&self.process_group.leader);
1897 pids.remove_process_group(&self.process_group.leader);
1898 }
1899 disassociation
1900 }
1901
1902 fn reap_zombie(&mut self, zombie: OwnedRef<ZombieProcess>, pids: &mut PidTableGuard<'_>) {
1904 self.children_time_stats += zombie.state.time_stats;
1905 zombie.release(pids);
1906 }
1907
1908 pub fn is_waitable(&self) -> bool {
1911 return self.last_signal.is_some() && !self.base.load_stopped().is_in_progress();
1912 }
1913
1914 pub fn get_waitable_zombie(
1915 &mut self,
1916 zombie_list: &dyn Fn(&mut ThreadGroupMutableState) -> &mut Vec<OwnedRef<ZombieProcess>>,
1917 selector: &ProcessSelector,
1918 options: &WaitingOptions,
1919 pids: &mut PidTableGuard<'_>,
1920 ) -> Option<WaitResult> {
1921 let selected_zombie_position = zombie_list(self)
1923 .iter()
1924 .rev()
1925 .position(|zombie| zombie.matches_selector_and_waiting_option(selector, options))
1926 .map(|position_starting_from_the_back| {
1927 zombie_list(self).len() - 1 - position_starting_from_the_back
1928 });
1929
1930 selected_zombie_position.map(|position| {
1931 if options.keep_waitable_state {
1932 zombie_list(self)[position].to_wait_result()
1933 } else {
1934 let zombie = zombie_list(self).remove(position);
1935 let result = zombie.to_wait_result();
1936 self.reap_zombie(zombie, pids);
1937 result
1938 }
1939 })
1940 }
1941
1942 pub fn is_correct_exit_signal(for_clone: bool, exit_code: Option<Signal>) -> bool {
1943 for_clone == (exit_code != Some(SIGCHLD))
1944 }
1945
1946 fn get_waitable_running_children(
1947 &self,
1948 selector: &ProcessSelector,
1949 options: &WaitingOptions,
1950 ) -> WaitableChildResult {
1951 let filter_children_by_pid_selector = |child: &ThreadGroup| match selector {
1953 ProcessSelector::Any => true,
1954 ProcessSelector::Pid(pid) => &child.leader == pid,
1955 ProcessSelector::Pgid(pgid) => {
1956 let _token = allow_subclass();
1960 &child.read().process_group.leader == pgid
1961 }
1962 };
1963
1964 let filter_children_by_waiting_options = |child: &ThreadGroup| {
1966 if options.wait_for_all {
1967 return true;
1968 }
1969 let _token = allow_subclass();
1973 Self::is_correct_exit_signal(options.wait_for_clone, child.read().exit_signal)
1974 };
1975
1976 let mut selected_children = self
1979 .children
1980 .values()
1981 .map(|t| t.upgrade().unwrap())
1982 .filter(|tg| filter_children_by_pid_selector(&tg))
1983 .filter(|tg| filter_children_by_waiting_options(&tg))
1984 .peekable();
1985 if selected_children.peek().is_none() {
1986 if self.deferred_zombie_ptracers.iter().any(|dzp| match selector {
1988 ProcessSelector::Any => true,
1989 ProcessSelector::Pid(pid) => &dzp.tracee_pid == pid,
1990 ProcessSelector::Pgid(pgid) => &dzp.tracee_pgid == pgid,
1991 }) {
1992 return WaitableChildResult::ShouldWait;
1993 }
1994
1995 return WaitableChildResult::NoneFound;
1996 }
1997 for child in selected_children {
1998 let _token = allow_subclass();
2002 let child = child.write();
2003 if child.last_signal.is_some() {
2004 let build_wait_result = |mut child: ThreadGroupWriteGuard<'_>,
2005 exit_status: &dyn Fn(SignalInfo) -> ExitStatus|
2006 -> WaitResult {
2007 let siginfo = if options.keep_waitable_state {
2008 child.last_signal.clone().unwrap()
2009 } else {
2010 child.last_signal.take().unwrap()
2011 };
2012 let exit_status = if siginfo.signal == SIGKILL {
2013 ExitStatus::Kill(siginfo)
2015 } else {
2016 exit_status(siginfo)
2017 };
2018 let info = child.tasks.iter().next().unwrap();
2019 let uid = info.real_creds().uid;
2020 WaitResult {
2021 pid: child.base.leader.clone(),
2022 uid,
2023 zombie_state: ZombieState {
2024 exit_status,
2025 time_stats: child.base.time_stats() + child.children_time_stats,
2026 },
2027 exit_signal: child.exit_signal,
2028 }
2029 };
2030 let child_stopped = child.base.load_stopped();
2031 if child_stopped == StopState::Awake && options.wait_for_continued {
2032 return WaitableChildResult::ReadyNow(Box::new(build_wait_result(
2033 child,
2034 &|siginfo| ExitStatus::Continue(siginfo, PtraceEvent::None),
2035 )));
2036 }
2037 if child_stopped == StopState::GroupStopped && options.wait_for_stopped {
2038 return WaitableChildResult::ReadyNow(Box::new(build_wait_result(
2039 child,
2040 &|siginfo| ExitStatus::Stop(siginfo, PtraceEvent::None),
2041 )));
2042 }
2043 }
2044 }
2045
2046 WaitableChildResult::ShouldWait
2047 }
2048
2049 pub fn get_waitable_child(
2055 &mut self,
2056 selector: &ProcessSelector,
2057 options: &WaitingOptions,
2058 pids: &mut PidTableGuard<'_>,
2059 ) -> WaitableChildResult {
2060 if options.wait_for_exited {
2061 if let Some(waitable_zombie) = self.get_waitable_zombie(
2062 &|state: &mut ThreadGroupMutableState| &mut state.zombie_children,
2063 selector,
2064 options,
2065 pids,
2066 ) {
2067 return WaitableChildResult::ReadyNow(Box::new(waitable_zombie));
2068 }
2069 }
2070
2071 self.get_waitable_running_children(selector, options)
2072 }
2073
2074 pub fn get_running_task(&self) -> Result<Arc<Task>, Errno> {
2076 self.tasks
2077 .iter()
2078 .find_map(|info| info.tid.get_task().ok().filter(|task| task.is_running()))
2079 .ok_or_else(|| errno!(ESRCH))
2080 }
2081
2082 fn get_signalable_task(&self) -> Option<Arc<Task>> {
2087 let mut non_running = if let Ok(task) = self.base.leader.get_task() {
2088 if task.is_running() {
2089 return Some(task);
2090 }
2091 Some(task)
2092 } else {
2093 None
2094 };
2095 for container in &self.tasks {
2096 if let Ok(task) = container.tid.get_task() {
2097 if task.is_running() {
2098 return Some(task);
2099 }
2100 if non_running.is_none() {
2101 non_running = Some(task);
2102 }
2103 }
2104 }
2105 non_running
2106 }
2107
2108 pub fn set_stopped(
2115 mut self,
2116 new_stopped: StopState,
2117 siginfo: Option<SignalInfo>,
2118 finalize_only: bool,
2119 ) -> StopState {
2120 if let Some(stopped) = self.base.check_stopped_state(new_stopped, finalize_only) {
2121 return stopped;
2122 }
2123
2124 if self.base.load_stopped() == StopState::Waking
2127 && (new_stopped == StopState::GroupStopping || new_stopped == StopState::GroupStopped)
2128 {
2129 return self.base.load_stopped();
2130 }
2131
2132 self.store_stopped(new_stopped);
2136 if let Some(signal) = &siginfo {
2137 if signal.signal != SIGKILL {
2141 self.last_signal = siginfo;
2142 }
2143 }
2144 if new_stopped == StopState::Waking || new_stopped == StopState::ForceWaking {
2145 self.lifecycle_waiters.notify_value(ThreadGroupLifecycleWaitValue::Stopped);
2146 };
2147
2148 let parent = (!new_stopped.is_in_progress()).then(|| self.parent.clone()).flatten();
2149
2150 std::mem::drop(self);
2152 if let Some(parent) = parent {
2153 let parent = parent.upgrade();
2154 parent
2155 .write()
2156 .lifecycle_waiters
2157 .notify_value(ThreadGroupLifecycleWaitValue::ChildStatus);
2158 }
2159
2160 new_stopped
2161 }
2162
2163 fn store_stopped(&mut self, state: StopState) {
2164 self.base.stop_state.store(state, Ordering::Relaxed)
2169 }
2170
2171 #[allow(unused_mut, reason = "needed for some but not all macro outputs")]
2173 pub fn send_signal(mut self, signal_info: SignalInfo) {
2174 let sigaction = self.base.signal_actions.get(signal_info.signal);
2175 let action = action_for_signal(&signal_info, sigaction);
2176
2177 let tasks: Vec<Pid> = self.tasks.iter().map(|info| info.tid.clone()).collect();
2178
2179 let queue_on_group = action != DeliveryAction::Ignore
2185 || tasks
2186 .iter()
2187 .filter_map(|pid| pid.get_task().ok())
2188 .filter(|task| task.is_running())
2189 .any(|task| {
2190 let task_state = task.read();
2191 task_state.is_signal_masked(signal_info.signal)
2192 || task_state.is_signal_masked_by_saved_mask(signal_info.signal)
2193 || task_state.is_ptraced()
2194 });
2195
2196 if queue_on_group {
2197 let mut pending_signals = self.base.pending_signals.lock();
2198 pending_signals.enqueue(signal_info.clone());
2199 self.base.has_pending_signals.store(true, Ordering::Relaxed);
2200 }
2201
2202 if signal_info.signal == SIGKILL {
2204 self.set_stopped(StopState::ForceWaking, Some(signal_info.clone()), false);
2205 } else if signal_info.signal == SIGCONT {
2206 self.set_stopped(StopState::Waking, Some(signal_info.clone()), false);
2207 }
2208
2209 let mut has_interrupted_task = false;
2210 for task in tasks.iter().flat_map(|pid| pid.get_task().ok()) {
2211 if !task.is_running() {
2212 continue;
2213 }
2214
2215 let mut task_state = task.write();
2216
2217 if signal_info.signal == SIGKILL {
2218 task_state.thaw();
2219 task_state.set_stopped(StopState::ForceWaking, None, None, None);
2220 } else if signal_info.signal == SIGCONT {
2221 task_state.set_stopped(StopState::Waking, None, None, None);
2222 }
2223
2224 let is_masked = task_state.is_signal_masked(signal_info.signal);
2225 let was_masked = task_state.is_signal_masked_by_saved_mask(signal_info.signal);
2226
2227 let is_queued = action != DeliveryAction::Ignore
2228 || is_masked
2229 || was_masked
2230 || task_state.is_ptraced();
2231
2232 if is_queued {
2233 task_state.notify_signal_waiters(&signal_info.signal);
2234
2235 let is_fatal = signal_info.signal == SIGKILL
2236 || (action == DeliveryAction::Terminate && !task_state.is_ptraced());
2237
2238 if !is_masked
2239 && action.must_interrupt(Some(sigaction))
2240 && (!has_interrupted_task || is_fatal)
2241 {
2242 drop(task_state);
2245 task.interrupt();
2246 has_interrupted_task = true;
2247 }
2248 }
2249 }
2250 }
2251}
2252
2253#[cfg(test)]
2254mod test {
2255 use super::*;
2256 use crate::testing::*;
2257
2258 #[::fuchsia::test]
2259 async fn test_setsid() {
2260 spawn_kernel_and_run(async |current_task| {
2261 fn get_process_group(task: &Task) -> Arc<ProcessGroup> {
2262 Arc::clone(&task.thread_group().read().process_group)
2263 }
2264 assert_eq!(current_task.thread_group().setsid(), error!(EPERM));
2265
2266 let child_task = current_task.clone_task_for_test(0, Some(SIGCHLD));
2267 assert_eq!(get_process_group(¤t_task), get_process_group(&child_task));
2268
2269 let old_process_group = child_task.thread_group().read().process_group.clone();
2270 assert_eq!(child_task.thread_group().setsid(), Ok(()));
2271 assert_eq!(
2272 child_task.thread_group().read().process_group.session.leader,
2273 child_task.pid
2274 );
2275 assert!(!old_process_group.read().thread_groups().contains(child_task.thread_group()));
2276 })
2277 .await;
2278 }
2279
2280 #[::fuchsia::test]
2281 async fn test_exit_status() {
2282 spawn_kernel_and_run(async |current_task| {
2283 let child = current_task.clone_task_for_test(0, Some(SIGCHLD));
2284 child.thread_group().kill(ExitStatus::Exit(42), None);
2285 std::mem::drop(child);
2286 assert_eq!(
2287 current_task.thread_group().read().zombie_children[0].state.exit_status,
2288 ExitStatus::Exit(42)
2289 );
2290 })
2291 .await;
2292 }
2293
2294 #[::fuchsia::test]
2295 async fn test_setgpid() {
2296 spawn_kernel_and_run(async |current_task| {
2297 assert_eq!(current_task.thread_group().setsid(), error!(EPERM));
2298
2299 let child_task1 = current_task.clone_task_for_test(0, Some(SIGCHLD));
2300 let child_task2 = current_task.clone_task_for_test(0, Some(SIGCHLD));
2301 let execd_child_task = current_task.clone_task_for_test(0, Some(SIGCHLD));
2302 execd_child_task.thread_group().write().did_exec = true;
2303 let other_session_child_task = current_task.clone_task_for_test(0, Some(SIGCHLD));
2304 assert_eq!(other_session_child_task.thread_group().setsid(), Ok(()));
2305
2306 assert_eq!(
2307 child_task1.thread_group().setpgid(¤t_task, ¤t_task, ¤t_task.pid),
2308 error!(ESRCH)
2309 );
2310 assert_eq!(
2311 current_task.thread_group().setpgid(
2312 ¤t_task,
2313 &execd_child_task,
2314 &execd_child_task.pid
2315 ),
2316 error!(EACCES)
2317 );
2318 assert_eq!(
2319 current_task.thread_group().setpgid(
2320 ¤t_task,
2321 ¤t_task,
2322 ¤t_task.pid
2323 ),
2324 error!(EPERM)
2325 );
2326 assert_eq!(
2327 current_task.thread_group().setpgid(
2328 ¤t_task,
2329 &other_session_child_task,
2330 &other_session_child_task.pid
2331 ),
2332 error!(EPERM)
2333 );
2334 assert_eq!(
2335 current_task.thread_group().setpgid(¤t_task, &child_task1, &child_task2.pid),
2336 error!(EPERM)
2337 );
2338 assert_eq!(
2339 current_task.thread_group().setpgid(
2340 ¤t_task,
2341 &child_task1,
2342 &other_session_child_task.pid
2343 ),
2344 error!(EPERM)
2345 );
2346
2347 assert_eq!(
2348 child_task1.thread_group().setpgid(¤t_task, &child_task1, &child_task1.pid),
2349 Ok(())
2350 );
2351 assert_eq!(
2352 child_task1.thread_group().read().process_group.session.leader,
2353 current_task.tid
2354 );
2355 assert_eq!(child_task1.thread_group().read().process_group.leader, child_task1.tid);
2356
2357 let old_process_group = child_task2.thread_group().read().process_group.clone();
2358 assert_eq!(
2359 current_task.thread_group().setpgid(¤t_task, &child_task2, &child_task1.pid),
2360 Ok(())
2361 );
2362 assert_eq!(child_task2.thread_group().read().process_group.leader, child_task1.tid);
2363 assert!(!old_process_group.read().thread_groups().contains(child_task2.thread_group()));
2364
2365 let child_task3 = current_task.clone_task_for_test(0, Some(SIGCHLD));
2366 assert_eq!(
2367 child_task3.thread_group().setpgid(¤t_task, &child_task3, &child_task3.pid),
2368 Ok(())
2369 );
2370 assert_eq!(
2372 current_task.thread_group().setpgid(¤t_task, &child_task1, &child_task3.pid),
2373 Ok(())
2374 );
2375 assert_eq!(child_task1.thread_group().read().process_group.leader, child_task3.tid);
2376
2377 assert_eq!(
2379 child_task1.thread_group().setpgid(¤t_task, &child_task1, &child_task1.pid),
2380 Ok(())
2381 );
2382 assert_eq!(child_task1.thread_group().read().process_group.leader, child_task1.tid);
2383 let pg1 = child_task1.thread_group().read().process_group.clone();
2384 let pg2 = child_task2.thread_group().read().process_group.clone();
2385 assert_eq!(pg1, pg2);
2386
2387 assert_eq!(
2388 crate::task::syscalls::sys_setpgid(¤t_task, child_task1.pid.id, -1),
2389 error!(EINVAL)
2390 );
2391 assert_eq!(
2392 crate::task::syscalls::sys_setpgid(¤t_task, child_task1.pid.id, 255),
2393 error!(EPERM)
2394 );
2395 })
2396 .await;
2397 }
2398
2399 #[::fuchsia::test]
2400 async fn test_adopt_children() {
2401 spawn_kernel_and_run(async |current_task| {
2402 let task1 = current_task.clone_task_for_test(0, None);
2403 let task2 = task1.clone_task_for_test(0, None);
2404 let task3 = task2.clone_task_for_test(0, None);
2405
2406 assert_eq!(task3.thread_group().read().get_ppid(), task2.tid.id);
2407
2408 task2.thread_group().kill(ExitStatus::Exit(0), None);
2409 std::mem::drop(task2);
2410
2411 assert_eq!(task3.thread_group().read().get_ppid(), current_task.tid.id);
2413 })
2414 .await;
2415 }
2416
2417 #[::fuchsia::test]
2418 async fn test_getppid_after_self_and_parent_exit() {
2419 spawn_kernel_and_run(async |current_task| {
2420 let task1 = current_task.clone_task_for_test(0, None);
2421 let task2 = task1.clone_task_for_test(0, None);
2422
2423 let tg1 = task1.thread_group().clone();
2425 let tg2 = task2.thread_group().clone();
2426
2427 assert_eq!(tg1.read().get_ppid(), current_task.tid.id);
2428 assert_eq!(tg2.read().get_ppid(), task1.tid.id);
2429
2430 tg2.kill(ExitStatus::Exit(0), None);
2432 std::mem::drop(task2);
2433
2434 tg1.kill(ExitStatus::Exit(0), None);
2436 std::mem::drop(task1);
2437 std::mem::drop(tg1);
2438
2439 let _ = tg2.read().get_ppid();
2442 })
2443 .await;
2444 }
2445}