1use crate::device::terminal::{ControllingSession, ControllingTerminal, Terminal, TerminalSide};
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};
17#[cfg(doc)]
18use crate::task::TaskFlags;
19use crate::task::memory_attribution::MemoryAttributionLifecycleEvent;
20use crate::task::{
21 CurrentTask, ExitStatus, Kernel, Pid, PidTableGuard, Task, TaskMutableState,
22 TaskPersistentInfo, TypedWaitQueue, WaitResult, ZombieProcess, ZombieState,
23};
24use crate::time::{IntervalTimerHandle, TimerTable};
25use fuchsia_rcu::subtle::RcuPtr;
26use fuchsia_rcu::{RcuDroppable, RcuReadScope};
27use fuchsia_rcu_collections::rcu_intrusive_list::{Link, RcuListAdapter, rcu_list_adapter};
28use itertools::Itertools;
29use macro_rules_attribute::apply;
30use starnix_lifecycle::{AtomicCounter, DropNotifier};
31use starnix_logging::{log_debug, log_error, log_info, log_warn, track_stub};
32use starnix_sync::{
33 LockDepMutex, LockDepRwLock, ThreadGroupLimits, ThreadGroupMutableStateLock,
34 ThreadGroupPendingSignalsLock, ThreadGroupPtraceesLock, allow_subclass,
35};
36use starnix_task_command::TaskCommand;
37use starnix_types::ownership::{OwnedRef, Releasable};
38use starnix_types::stats::TaskTimeStats;
39use starnix_types::time::{itimerspec_from_itimerval, timeval_from_duration};
40use starnix_uapi::auth::{CAP_SYS_ADMIN, CAP_SYS_RESOURCE};
41use starnix_uapi::errors::Errno;
42use starnix_uapi::personality::PersonalityFlags;
43use starnix_uapi::resource_limits::{Resource, ResourceLimits};
44use starnix_uapi::signals::{
45 SIGCHLD, SIGCONT, SIGHUP, SIGKILL, SIGTERM, SIGTTOU, SigSet, Signal, UncheckedSignal,
46};
47use starnix_uapi::user_address::UserAddress;
48use starnix_uapi::{
49 ITIMER_PROF, ITIMER_REAL, ITIMER_VIRTUAL, SA_NOCLDWAIT, SI_TKILL, SI_USER, SIG_IGN, errno,
50 error, itimerval, pid_t, rlimit, tid_t,
51};
52use std::collections::HashSet;
53use std::fmt;
54use std::sync::atomic::{AtomicBool, Ordering};
55use std::sync::{Arc, Weak};
56use zx::{Koid, Status};
57
58#[derive(Debug)]
59pub struct ZirconProcess {
60 process: zx::Process,
61 koid: Result<Koid, Status>,
62}
63
64impl ZirconProcess {
65 pub fn new(process: zx::Process) -> Self {
66 let koid = process.koid();
67 Self { process, koid }
68 }
69
70 pub fn koid(&self) -> Result<Koid, Status> {
71 self.koid
72 }
73}
74
75impl std::ops::Deref for ZirconProcess {
76 type Target = zx::Process;
77 fn deref(&self) -> &Self::Target {
78 &self.process
79 }
80}
81
82#[repr(u64)]
84pub enum ThreadGroupLifecycleWaitValue {
85 ChildStatus,
87 Stopped,
89}
90
91impl Into<u64> for ThreadGroupLifecycleWaitValue {
92 fn into(self) -> u64 {
93 self as u64
94 }
95}
96
97#[derive(Clone, Debug)]
100pub struct DeferredZombiePTracer {
101 pub tracer_pid: Pid,
103 pub tracee_tid: Pid,
105 pub tracee_pgid: Pid,
107 pub tracee_pid: Pid,
109}
110
111impl DeferredZombiePTracer {
112 fn new(tracer: &ThreadGroup, tracee: &Task, tracee_pgid: Pid) -> Self {
113 Self {
114 tracer_pid: tracer.leader.clone(),
115 tracee_tid: tracee.tid.clone(),
116 tracee_pgid,
117 tracee_pid: tracee.pid.clone(),
118 }
119 }
120}
121
122pub struct ThreadGroupMutableState {
124 pub parent: Option<ThreadGroupParent>,
129
130 pub exit_signal: Option<Signal>,
132
133 parent_death_signal: Option<Signal>,
139
140 tasks: HashSet<TaskPersistentInfo>,
147
148 pub children: HashSet<Pid>,
153
154 pub zombie_children: Vec<OwnedRef<ZombieProcess>>,
156
157 pub zombie_ptracees: ZombiePtracees,
159
160 pub deferred_zombie_ptracers: Vec<DeferredZombiePTracer>,
163
164 pub lifecycle_waiters: TypedWaitQueue<ThreadGroupLifecycleWaitValue>,
166
167 pub is_child_subreaper: bool,
170
171 pub process_group: Pid,
173
174 pub session: Pid,
176
177 pub controlling_terminal: Option<ControllingTerminal>,
179
180 pub did_exec: bool,
181
182 pub last_signal: Option<SignalInfo>,
186
187 run_state: ThreadGroupRunState,
191
192 pub children_time_stats: TaskTimeStats,
194
195 pub personality: PersonalityFlags,
197
198 pub allowed_ptracers: PtraceAllowedPtracers,
200
201 exit_notifier: Option<futures::channel::oneshot::Sender<()>>,
203
204 pub notifier: Option<std::sync::mpsc::Sender<MemoryAttributionLifecycleEvent>>,
206}
207
208pub struct ThreadGroup {
232 pub weak_self: Weak<ThreadGroup>,
235
236 pub kernel: Arc<Kernel>,
238
239 pub process: ZirconProcess,
248
249 pub root_vmar: zx::Vmar,
251
252 pub leader: Pid,
256
257 pub(super) pgrp_node: RcuPtr<ThreadGroupLinkNode>,
259
260 pub(super) session_node: RcuPtr<ThreadGroupLinkNode>,
262
263 pub signal_actions: Arc<SignalActions>,
265
266 pub timers: TimerTable,
268
269 pub drop_notifier: DropNotifier,
271
272 stop_state: AtomicStopState,
276
277 mutable_state: LockDepRwLock<ThreadGroupMutableState, ThreadGroupMutableStateLock>,
279
280 pub limits: LockDepMutex<ResourceLimits, ThreadGroupLimits>,
284
285 pub next_seccomp_filter_id: AtomicCounter<u64>,
290
291 pub ptracees: LockDepMutex<HashSet<TaskPersistentInfo>, ThreadGroupPtraceesLock>,
293
294 pub pending_signals: LockDepMutex<QueuedSignals, ThreadGroupPendingSignalsLock>,
296
297 pub has_pending_signals: AtomicBool,
300
301 pub start_time: zx::MonotonicInstant,
303
304 log_syscalls_as_info: AtomicBool,
306}
307
308impl fmt::Debug for ThreadGroup {
309 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310 write!(
311 f,
312 "{}({})",
313 self.process.get_name().unwrap_or(zx::Name::new_lossy("<unknown>")),
314 self.leader
315 )
316 }
317}
318
319impl ThreadGroup {
320 pub fn to_owned(&self) -> Arc<Self> {
321 self.weak_self.upgrade().expect("ThreadGroup is alive")
322 }
323
324 pub fn sync_syscall_log_level(&self) {
325 let command = self.read().leader_command();
326 let filters = self.kernel.syscall_log_filters.lock();
327 let should_log = filters.iter().any(|f| f.matches(&command));
328 let prev_should_log = self.log_syscalls_as_info.swap(should_log, Ordering::Relaxed);
329 let change_str = match (should_log, prev_should_log) {
330 (true, false) => Some("Enabled"),
331 (false, true) => Some("Disabled"),
332 _ => None,
333 };
334 if let Some(change_str) = change_str {
335 log_info!(
336 "{change_str} info syscall logs for thread group {} (command: {command})",
337 self.leader
338 );
339 }
340 }
341
342 #[inline]
343 pub fn syscall_log_level(&self) -> starnix_logging::Level {
344 if self.log_syscalls_as_info.load(Ordering::Relaxed) {
345 starnix_logging::Level::Info
346 } else {
347 starnix_logging::Level::Trace
348 }
349 }
350}
351
352impl PartialEq for ThreadGroup {
353 fn eq(&self, other: &Self) -> bool {
354 self.leader == other.leader
355 }
356}
357
358#[derive(Debug, RcuDroppable)]
364pub(super) struct ThreadGroupLinkNode {
365 pub(super) thread_group: Weak<ThreadGroup>,
366 pub(super) link: Link,
367}
368
369impl ThreadGroupLinkNode {
370 pub(super) fn new(thread_group: Weak<ThreadGroup>) -> Self {
371 Self { thread_group, link: Link::default() }
372 }
373}
374
375#[derive(Debug, RcuDroppable)]
377pub(super) struct ThreadGroupLinkAdapter;
378
379impl RcuListAdapter<ThreadGroupLinkNode> for ThreadGroupLinkAdapter {
380 rcu_list_adapter!(ThreadGroupLinkNode, link);
381}
382
383impl Drop for ThreadGroup {
384 fn drop(&mut self) {
385 let state = self.mutable_state.get_mut();
386 assert!(state.tasks.is_empty());
387 assert!(state.children.is_empty());
388 assert!(state.zombie_children.is_empty());
389 assert!(state.zombie_ptracees.is_empty());
390 #[cfg(any(test, debug_assertions))]
391 {
392 let scope = fuchsia_rcu::RcuReadScope::new();
393 assert!(self.pgrp_node.read(&scope).is_null());
394 assert!(self.session_node.read(&scope).is_null());
395 assert!(
396 state
397 .parent
398 .as_ref()
399 .and_then(|p| p
400 .thread_group
401 .upgrade()
402 .map(|p| !p.read().children.contains(&self.leader)))
403 .unwrap_or(true)
404 );
405 }
406 }
407}
408
409#[derive(Clone)]
413pub struct ThreadGroupParent {
414 thread_group: Weak<ThreadGroup>,
416
417 creator_task: Option<Weak<Task>>,
420}
421
422impl ThreadGroupParent {
423 pub fn new(thread_group: Weak<ThreadGroup>) -> Self {
430 let upgraded = thread_group.upgrade();
431 debug_assert!(upgraded.is_some());
432 let creator_task =
433 upgraded.and_then(|tg| tg.leader.get_task().ok()).map(|t| t.weak_self.clone());
434 Self { thread_group, creator_task }
435 }
436
437 pub(super) fn from_reaper(thread_group: Weak<ThreadGroup>) -> Self {
444 debug_assert!(thread_group.upgrade().is_some());
445 Self { thread_group, creator_task: None }
446 }
447
448 pub fn upgrade(&self) -> Arc<ThreadGroup> {
450 self.thread_group.upgrade().expect("ThreadGroupParent references must always be valid")
451 }
452
453 pub(super) fn creator_task(&self) -> Option<&Weak<Task>> {
456 self.creator_task.as_ref()
457 }
458
459 pub(super) fn set_creator_task(&mut self, creator_task: Option<Weak<Task>>) {
462 self.creator_task = creator_task;
463 }
464}
465
466#[derive(Debug, Clone)]
469pub enum ProcessSelector {
470 Any,
472 Pid(Pid),
474 Pgid(Pid),
476}
477
478impl ProcessSelector {
479 pub fn match_tid(&self, tid: &Pid) -> bool {
480 match self {
481 ProcessSelector::Pid(pid) => {
482 if pid == tid {
483 true
484 } else if let Ok(task_ref) = tid.get_task() {
485 &task_ref.pid == pid
486 } else {
487 false
488 }
489 }
490 ProcessSelector::Any => true,
491 ProcessSelector::Pgid(pgid) => {
492 if let Ok(task_ref) = tid.get_task() {
493 &task_ref.thread_group().read().process_group == pgid
494 } else {
495 false
496 }
497 }
498 }
499 }
500}
501
502#[derive(Clone, Debug, Default, PartialEq, Eq)]
503enum ThreadGroupRunState {
504 #[default]
505 Running,
506 Exiting(ExitStatus),
507 Exited(ExitStatus),
508}
509
510impl ThreadGroup {
511 pub fn new(
513 kernel: Arc<Kernel>,
514 process: zx::Process,
515 root_vmar: zx::Vmar,
516 parent: Option<ThreadGroupWriteGuard<'_>>,
517 leader: Pid,
518 exit_signal: Option<Signal>,
519 signal_actions: Arc<SignalActions>,
520 ) -> Arc<ThreadGroup> {
521 debug_assert!(!process.is_invalid());
522 debug_assert!(!root_vmar.is_invalid());
523 Self::new_internal(kernel, process, root_vmar, parent, leader, exit_signal, signal_actions)
524 }
525
526 pub fn for_system(kernel: Arc<Kernel>, leader: Pid) -> Arc<ThreadGroup> {
528 Self::new_internal(
529 kernel,
530 zx::Process::invalid(),
531 zx::Vmar::invalid(),
532 None,
533 leader,
534 Some(SIGCHLD),
535 SignalActions::default(),
536 )
537 }
538
539 pub fn for_test(
547 kernel: Arc<Kernel>,
548 process: zx::Process,
549 parent: ThreadGroupWriteGuard<'_>,
550 leader: Pid,
551 ) -> Arc<ThreadGroup> {
552 Self::new_internal(
553 kernel,
554 process,
555 zx::Vmar::invalid(),
556 Some(parent),
557 leader,
558 Some(SIGCHLD),
559 SignalActions::default(),
560 )
561 }
562
563 fn new_internal(
564 kernel: Arc<Kernel>,
565 process: zx::Process,
566 root_vmar: zx::Vmar,
567 parent: Option<ThreadGroupWriteGuard<'_>>,
568 leader: Pid,
569 exit_signal: Option<Signal>,
570 signal_actions: Arc<SignalActions>,
571 ) -> Arc<ThreadGroup> {
572 Arc::new_cyclic(|weak_self| {
573 let process = ZirconProcess::new(process);
574 let process_group =
575 parent.as_ref().map(|p| p.process_group.clone()).unwrap_or_else(|| leader.clone());
576 let session =
577 parent.as_ref().map(|p| p.session.clone()).unwrap_or_else(|| leader.clone());
578 let mut thread_group = ThreadGroup {
579 weak_self: weak_self.clone(),
580 kernel,
581 process,
582 root_vmar,
583 leader,
584 pgrp_node: RcuPtr::null(),
585 session_node: RcuPtr::null(),
586 signal_actions,
587 timers: Default::default(),
588 drop_notifier: Default::default(),
589 limits: LockDepMutex::new(
595 parent.as_ref().map(|p| p.base.limits.lock().clone()).unwrap_or_else(|| {
596 ResourceLimits::from_total_ram(zx::system_get_physmem())
597 }),
598 ),
599 next_seccomp_filter_id: Default::default(),
600 ptracees: Default::default(),
601 stop_state: AtomicStopState::new(StopState::Awake),
602 pending_signals: Default::default(),
603 has_pending_signals: Default::default(),
604 start_time: zx::MonotonicInstant::get(),
605 mutable_state: ThreadGroupMutableState {
606 parent: parent
607 .as_ref()
608 .map(|p| ThreadGroupParent::new(p.base.weak_self.clone())),
609 exit_signal,
610 parent_death_signal: None,
615 tasks: HashSet::new(),
616 children: HashSet::new(),
617 zombie_children: vec![],
618 zombie_ptracees: ZombiePtracees::new(),
619 deferred_zombie_ptracers: vec![],
620 lifecycle_waiters: TypedWaitQueue::<ThreadGroupLifecycleWaitValue>::default(),
621 is_child_subreaper: false,
622 process_group,
623 session,
624 controlling_terminal: None,
625 did_exec: false,
626 last_signal: None,
627 run_state: Default::default(),
628 children_time_stats: Default::default(),
629 personality: parent
630 .as_ref()
631 .map(|p| p.personality)
632 .unwrap_or(Default::default()),
633 allowed_ptracers: PtraceAllowedPtracers::None,
634 exit_notifier: None,
635 notifier: None,
636 }
637 .into(),
638 log_syscalls_as_info: AtomicBool::new(false),
639 };
640
641 if let Some(mut parent) = parent {
642 thread_group.next_seccomp_filter_id.reset(parent.base.next_seccomp_filter_id.get());
643 parent.children.insert(thread_group.leader.clone());
644 };
645 thread_group
646 })
647 }
648
649 state_accessor!(ThreadGroup, mutable_state);
650
651 pub fn load_stopped(&self) -> StopState {
652 self.stop_state.load(Ordering::Relaxed)
653 }
654
655 pub fn kill(&self, exit_status: ExitStatus, mut current_task: Option<&mut CurrentTask>) {
663 let state = self.write();
664 if !state.is_running() {
665 if let Some(current_task) = current_task {
666 current_task.write().set_exit_status_if_not_already(exit_status);
667 }
668 return;
669 }
670
671 let current_tid = current_task.as_ref().map(|task| task.tid.clone());
676 state.terminate_tasks(
677 exit_status.clone(),
678 SignalInfo::forced(SIGKILL),
679 current_tid.as_ref(),
680 );
681
682 if let Some(ref mut current_task) = current_task {
696 current_task
697 .ptrace_event(PtraceOptions::TRACEEXIT, exit_status.signal_info_status() as u64);
698 let mut task_state = current_task.write();
699 task_state.set_exit_status(exit_status);
700 task_state.force_wake_for_exit();
701 }
702 }
703
704 pub fn add(&self, task: Arc<Task>) -> Result<(), Errno> {
705 let mut state = self.write();
706 if !state.is_running() {
707 if state.tasks_count() == 0 {
708 log_warn!(
709 "Task {} with leader {} not running while adding its first task, \
710 not sending creation notification",
711 task.tid,
712 self.leader
713 );
714 }
715 return error!(EINVAL);
716 }
717 state.tasks.insert(task.persistent_info.clone());
718
719 Ok(())
720 }
721
722 pub fn remove(&self, mut pids: PidTableGuard<'_>, task: &Arc<Task>) {
727 task.set_ptrace_zombie(&mut pids);
728
729 let mut state = self.write();
730
731 if !state.tasks.remove(&task.persistent_info) {
732 debug_assert!(!state.is_running());
735 pids.remove_task(&task.tid);
736 return;
737 }
738
739 if state.tasks.is_empty() {
740 let pgid = Arc::clone(&state.process_group);
741 let sid = Arc::clone(&state.session);
742 pids.detach_pgid(&pgid, self);
743 pids.detach_sid(&sid, self);
744
745 let exit_status = if let ThreadGroupRunState::Exiting(exit_status) = &state.run_state {
746 exit_status.clone()
747 } else {
748 let exit_status = task.exit_status().unwrap_or_else(|| {
749 log_error!("Exiting without an exit code.");
750 ExitStatus::Exit(u8::MAX)
751 });
752 state.set_exiting(exit_status.clone());
753 exit_status
754 };
755
756 let zombie_notifications = state.zombie_ptracees.detach_all(&mut pids);
758
759 let zombie = ZombieProcess::new(
763 task.clone(),
764 state.as_ref(),
765 exit_status,
766 state.exit_signal.clone(),
767 );
768 pids.kill_process(&self.leader, Arc::downgrade(task));
769 pids.remove_task(&task.tid);
770
771 let disassociated_controlling_terminal =
772 if state.session == self.leader { state.controlling_terminal.take() } else { None };
773
774 std::mem::drop(state);
784
785 if let Some(controlling_terminal) = disassociated_controlling_terminal {
788 controlling_terminal.terminal.disassociate_controlling_session_if(
789 Some(&sid),
790 Some(controlling_terminal.side),
791 );
792 }
793
794 for notification in zombie_notifications {
795 notification.deliver(&mut pids);
796 }
797
798 self.kernel.cgroups.lock_cgroup2_pid_table().remove_process(&self.leader);
802
803 self.detach_ptracees(&mut pids);
804
805 let parent = self.read().parent.clone();
808 let reaper = self.find_reaper();
809
810 let mut children = Vec::new();
825 {
826 if let Some(reaper) = reaper {
828 let reaper = reaper.upgrade();
829 {
830 let mut reaper_state = reaper.write();
831 let _token = allow_subclass();
834 let mut state = self.write();
835 for child_pid in std::mem::take(&mut state.children) {
836 if let Ok(child) = child_pid.get_thread_group() {
837 let signal = {
838 let _token = allow_subclass();
842 let mut child_state = child.write();
843
844 let signal = child_state.parent_death_signal_for_exiting_task(
845 task,
846 state.is_child_subreaper,
847 );
848 child_state.exit_signal = Some(SIGCHLD);
849 child_state.parent = Some(ThreadGroupParent::from_reaper(
850 Arc::downgrade(&reaper),
851 ));
852 signal
853 };
854 reaper_state.children.insert(child_pid);
855 children.push((child, signal));
856 }
857 }
858 reaper_state.zombie_children.append(&mut state.zombie_children);
859 }
860 ZombiePtracees::reparent(self, &reaper);
861
862 for (child, _) in &children {
863 child.kill_orphaned_pgrp(&pids, Some(self), None);
864 }
865 } else {
866 let mut state = self.write();
868 for child_pid in std::mem::take(&mut state.children) {
869 if let Ok(child) = child_pid.get_thread_group() {
870 let signal = {
871 let _token = allow_subclass();
874 let mut child_state = child.write();
875 let signal = child_state.parent_death_signal_for_exiting_task(
876 task,
877 state.is_child_subreaper,
878 );
879 child_state.parent = None;
880 signal
881 };
882 children.push((child, signal));
883 }
884 }
885 for zombie in state.zombie_children.drain(..) {
886 zombie.release(&mut pids);
887 }
888 }
889 }
890
891 self.send_parent_death_signals(
892 task,
893 children.into_iter().filter_map(|(child, signal)| Some((child, signal?))),
894 );
895
896 self.write().parent = None;
898
899 #[cfg(any(test, debug_assertions))]
900 {
901 let state = self.read();
902 assert!(state.zombie_children.is_empty());
903 assert!(state.zombie_ptracees.is_empty());
904 }
905
906 if let Some(ref parent) = parent {
907 let parent = parent.upgrade();
908
909 let tracer_tg = task
910 .read()
911 .ptrace
912 .as_ref()
913 .and_then(|ptrace| ptrace.core_state.thread_group.upgrade());
914
915 let maybe_zombie = match tracer_tg {
916 Some(tracer_tg) => {
917 tracer_tg.maybe_notify_tracer(task, &mut pids, &parent, zombie)
918 }
919 None => Some(zombie),
920 };
921
922 if let Some(zombie) = maybe_zombie {
923 parent.do_zombie_notifications(zombie, &mut pids);
924 }
925 } else {
926 zombie.release(&mut pids);
927 }
928
929 let parent_tg = parent.as_ref().map(|p| p.upgrade());
935 self.kill_orphaned_pgrp(&pids, parent_tg.as_deref(), Some(self));
936
937 self.write().set_exited();
938 } else {
939 pids.remove_task(&task.tid);
940 let mut children_to_signal = Vec::new();
947 for child in state.children() {
948 let _token = allow_subclass();
951 let child_state = child.read();
952 if let Some(signal) = child_state.parent_death_signal_for_exiting_task(
953 task, false,
954 ) {
955 children_to_signal.push((child.clone(), signal));
956 }
957 }
958 std::mem::drop(state);
959 self.send_parent_death_signals(task, children_to_signal);
960 }
961 }
962
963 fn send_parent_death_signals(
964 &self,
965 task: &Arc<Task>,
966 children_to_signal: impl IntoIterator<Item = (Arc<ThreadGroup>, Signal)>,
967 ) {
968 let uid = task.real_creds().uid;
969 for (child, signal) in children_to_signal {
970 child.write().send_signal(SignalInfo::with_detail(
975 signal,
976 SI_USER as i32,
977 SignalDetail::Kill { pid: self.leader.clone(), uid },
978 ));
979 }
980 }
981
982 fn detach_ptracees(&self, pids: &mut PidTableGuard<'_>) {
984 let tracee_tids = self.ptracees.lock().iter().map(|info| info.tid.clone()).collect_vec();
985 for tracee_tid in tracee_tids {
986 let Ok(tracee) = tracee_tid.get_task() else {
987 continue;
988 };
989
990 let mut should_send_sigkill = false;
991 if let Some(ptrace) = &tracee.read().ptrace {
992 should_send_sigkill = ptrace.has_option(PtraceOptions::EXITKILL);
993 }
994 if should_send_sigkill {
995 send_standard_signal(tracee.as_ref(), SignalInfo::kernel(SIGKILL));
996 }
997
998 let _ = ptrace_detach(
999 pids,
1000 PtraceTracer::Exiting(self),
1001 tracee.as_ref(),
1002 &UserAddress::NULL,
1003 );
1004 }
1005 }
1006
1007 pub fn do_zombie_notifications(
1008 &self,
1009 zombie: OwnedRef<ZombieProcess>,
1010 pids: &mut PidTableGuard<'_>,
1011 ) {
1012 let mut state = self.write();
1013
1014 state.children.remove(&zombie.task.pid);
1015 state.deferred_zombie_ptracers.retain(|dzp| dzp.tracee_pid != zombie.task.pid);
1016
1017 let exit_signal = zombie.exit_signal;
1018 let mut signal_info = zombie.to_wait_result().as_signal_info();
1019
1020 let should_make_zombie = if exit_signal == Some(SIGCHLD) {
1030 let action = self.signal_actions.get(SIGCHLD);
1031 action.sa_handler != SIG_IGN && (action.sa_flags & SA_NOCLDWAIT as u64) == 0
1032 } else {
1033 true
1034 };
1035 if should_make_zombie {
1036 state.zombie_children.push(zombie);
1037 } else {
1038 state.reap_zombie(zombie, pids);
1039 }
1040
1041 state.lifecycle_waiters.notify_value(ThreadGroupLifecycleWaitValue::ChildStatus);
1042
1043 if let Some(exit_signal) = exit_signal {
1045 signal_info.signal = exit_signal;
1046 state.send_signal(signal_info);
1047 }
1048 }
1049
1050 fn maybe_notify_tracer(
1054 &self,
1055 tracee: &Task,
1056 pids: &mut PidTableGuard<'_>,
1057 parent: &ThreadGroup,
1058 zombie: OwnedRef<ZombieProcess>,
1059 ) -> Option<OwnedRef<ZombieProcess>> {
1060 let mut state = self.write();
1061 if state.zombie_ptracees.has_tracee(&tracee.tid) {
1062 if self == parent {
1063 if let Some(zombie_notification) = state.zombie_ptracees.detach(pids, &tracee.tid) {
1068 zombie_notification.discard(pids);
1069 }
1070 return Some(zombie);
1071 } else {
1072 if state.is_exited() {
1075 return Some(zombie);
1077 }
1078
1079 drop(state);
1082 {
1083 let tracee_pgid = tracee.thread_group().read().process_group.clone();
1085 let mut parent_state = parent.write();
1086 parent_state.deferred_zombie_ptracers.push(DeferredZombiePTracer::new(
1087 self,
1088 tracee,
1089 tracee_pgid,
1090 ));
1091 parent_state.children.remove(&tracee.pid);
1092 }
1093
1094 let mut state = self.write();
1100 state.zombie_ptracees.set_parent_of(&tracee.tid, Some(zombie), parent);
1101 tracee.write().notify_ptracers();
1102 return None;
1103 }
1104 } else if self == parent {
1105 state.children.remove(&tracee.pid);
1108 zombie.release(pids);
1109 return None;
1110 }
1111 Some(zombie)
1114 }
1115
1116 fn find_reaper(&self) -> Option<ThreadGroupParent> {
1118 let mut weak_parent = self.read().parent.clone()?;
1119 loop {
1120 weak_parent = {
1121 let parent = weak_parent.upgrade();
1122 let parent_state = parent.read();
1123 if parent_state.is_child_subreaper {
1124 break;
1125 }
1126 match parent_state.parent {
1127 Some(ref next_parent) => next_parent.clone(),
1128 None => break,
1129 }
1130 };
1131 }
1132 Some(weak_parent)
1133 }
1134
1135 pub fn setsid(&self) -> Result<(), Errno> {
1136 let mut pids = self.kernel.pids.lock();
1137 let pid = self.leader.clone();
1138
1139 let scope = RcuReadScope::new();
1141 if self.leader.is_process_group(&scope) || self.leader.is_session(&scope) {
1142 return error!(EPERM);
1143 }
1144
1145 let self_arc = self.to_owned();
1146 let (old_process_group, check_old_pgrp, child_pgrps) = {
1147 let mut state = self.write();
1148 if !state.is_running() {
1149 return error!(ESRCH);
1150 }
1151 if state.session == self.leader || state.process_group == self.leader {
1152 return error!(EPERM);
1153 }
1154 let old_process_group = std::mem::replace(&mut state.process_group, pid.clone());
1155 let old_session = std::mem::replace(&mut state.session, pid.clone());
1156 state.controlling_terminal = None;
1157
1158 pids.detach_pgid(&old_process_group, self);
1159 pids.detach_sid(&old_session, self);
1160 pids.attach_pgid(&pid, &self_arc);
1161 pids.attach_sid(&pid, &self_arc);
1162
1163 let parent_tg = state.parent.as_ref().map(|p| p.upgrade());
1164 let mut child_pgrps = HashSet::new();
1165 for child in state.children() {
1166 let _token = allow_subclass();
1167 let child_state = child.read();
1168 if child_state.session == old_session
1169 && child_state.process_group != old_process_group
1170 {
1171 child_pgrps.insert(Arc::clone(&child_state.process_group));
1172 }
1173 }
1174 std::mem::drop(state);
1175
1176 let check_old_pgrp = parent_tg.is_some_and(|parent_tg| {
1177 let parent_state = parent_tg.read();
1178 parent_state.session == old_session
1179 && parent_state.process_group != old_process_group
1180 });
1181
1182 (old_process_group, check_old_pgrp, child_pgrps)
1183 };
1184 std::mem::drop(scope);
1185
1186 if check_old_pgrp {
1189 Self::check_orphaned_pgrp(&pids, &old_process_group, None);
1190 }
1191 for child_pgrp in child_pgrps {
1192 Self::check_orphaned_pgrp(&pids, &child_pgrp, None);
1193 }
1194
1195 Ok(())
1196 }
1197
1198 pub fn setpgid(
1199 &self,
1200 current_task: &CurrentTask,
1201 target: &Task,
1202 pgid: &Pid,
1203 ) -> Result<(), Errno> {
1204 let mut pids = self.kernel.pids.lock();
1205
1206 let (old_process_group, check_old_pgrp, check_new_pgrp) = {
1207 let current_session = Arc::clone(&self.read().session);
1208
1209 let mut target_thread_group = target.thread_group().write();
1211 if !target_thread_group.is_running() {
1212 return error!(ESRCH);
1213 }
1214 let parent_tg = target_thread_group.parent.as_ref().map(|p| p.upgrade());
1215 let is_target_current_process_child =
1216 parent_tg.as_ref().is_some_and(|tg| tg.leader == self.leader);
1217 if target_thread_group.base.leader != self.leader && !is_target_current_process_child {
1218 return error!(ESRCH);
1219 }
1220
1221 if is_target_current_process_child && target_thread_group.did_exec {
1223 return error!(EACCES);
1224 }
1225
1226 if target_thread_group.base.leader == target_thread_group.session
1228 || current_session != target_thread_group.session
1229 {
1230 return error!(EPERM);
1231 }
1232
1233 if *pgid == target_thread_group.process_group {
1234 return Ok(());
1235 }
1236
1237 if *pgid != target_thread_group.base.leader {
1239 let scope = RcuReadScope::new();
1240 if !pgid.is_process_group_in_session(&target_thread_group.session, &scope) {
1241 return error!(EPERM);
1242 }
1243 }
1244 security::check_setpgid_access(current_task, target)?;
1245
1246 let old_process_group =
1247 std::mem::replace(&mut target_thread_group.process_group, pgid.clone());
1248 pids.detach_pgid(&old_process_group, target.thread_group());
1249 pids.attach_pgid(pgid, target.thread_group());
1250
1251 let check_new_pgrp = target_thread_group.children().any(|child| {
1252 let _token = allow_subclass();
1253 child.read().process_group == *pgid
1254 });
1255 std::mem::drop(target_thread_group);
1256
1257 let check_old_pgrp = parent_tg.is_some_and(|parent_tg| {
1258 let parent_state = parent_tg.read();
1259 parent_state.session == current_session
1260 && parent_state.process_group != old_process_group
1261 });
1262
1263 (old_process_group, check_old_pgrp, check_new_pgrp)
1264 };
1265
1266 if check_old_pgrp {
1269 Self::check_orphaned_pgrp(&pids, &old_process_group, None);
1270 }
1271 if check_new_pgrp {
1272 Self::check_orphaned_pgrp(&pids, pgid, None);
1273 }
1274
1275 Ok(())
1276 }
1277
1278 fn itimer_real(&self) -> IntervalTimerHandle {
1279 self.timers.itimer_real()
1280 }
1281
1282 pub fn set_itimer(
1283 &self,
1284 current_task: &CurrentTask,
1285 which: u32,
1286 value: itimerval,
1287 ) -> Result<itimerval, Errno> {
1288 if which == ITIMER_PROF || which == ITIMER_VIRTUAL {
1289 if value.it_value.tv_sec == 0 && value.it_value.tv_usec == 0 {
1293 return Ok(itimerval::default());
1294 }
1295 track_stub!(TODO("https://fxbug.dev/322874521"), "Unsupported itimer type", which);
1296 return error!(ENOTSUP);
1297 }
1298
1299 if which != ITIMER_REAL {
1300 return error!(EINVAL);
1301 }
1302 let itimer_real = self.itimer_real();
1303 let prev_remaining = itimer_real.time_remaining();
1304 if value.it_value.tv_sec != 0 || value.it_value.tv_usec != 0 {
1305 itimer_real.arm(current_task, itimerspec_from_itimerval(value), false)?;
1306 } else {
1307 itimer_real.disarm(current_task)?;
1308 }
1309 Ok(itimerval {
1310 it_value: timeval_from_duration(prev_remaining.remainder),
1311 it_interval: timeval_from_duration(prev_remaining.interval),
1312 })
1313 }
1314
1315 pub fn get_itimer(&self, which: u32) -> Result<itimerval, Errno> {
1316 if which == ITIMER_PROF || which == ITIMER_VIRTUAL {
1317 return Ok(itimerval::default());
1319 }
1320 if which != ITIMER_REAL {
1321 return error!(EINVAL);
1322 }
1323 let remaining = self.itimer_real().time_remaining();
1324 Ok(itimerval {
1325 it_value: timeval_from_duration(remaining.remainder),
1326 it_interval: timeval_from_duration(remaining.interval),
1327 })
1328 }
1329
1330 fn check_stopped_state(
1333 &self,
1334 new_stopped: StopState,
1335 finalize_only: bool,
1336 ) -> Option<StopState> {
1337 let stopped = self.load_stopped();
1338 if finalize_only && !stopped.is_stopping_or_stopped() {
1339 return Some(stopped);
1340 }
1341
1342 if stopped.is_illegal_transition(new_stopped) {
1343 return Some(stopped);
1344 }
1345
1346 return None;
1347 }
1348
1349 pub fn set_stopped(
1356 &self,
1357 new_stopped: StopState,
1358 siginfo: Option<SignalInfo>,
1359 finalize_only: bool,
1360 ) -> StopState {
1361 if let Some(stopped) = self.check_stopped_state(new_stopped, finalize_only) {
1363 return stopped;
1364 }
1365
1366 self.write().set_stopped(new_stopped, siginfo, finalize_only)
1367 }
1368
1369 pub fn controlling_terminal(&self) -> Option<ControllingTerminal> {
1371 self.read().controlling_terminal.clone()
1372 }
1373
1374 fn check_controlling_session(
1376 session: &Pid,
1377 controlling_session: &Option<ControllingSession>,
1378 ) -> Result<(), Errno> {
1379 if controlling_session.as_ref().is_some_and(|cs| Arc::ptr_eq(session, &cs.session)) {
1380 Ok(())
1381 } else {
1382 error!(ENOTTY)
1383 }
1384 }
1385
1386 pub fn get_foreground_process_group(&self, terminal: &Terminal) -> Result<pid_t, Errno> {
1387 let state = self.read();
1388 let terminal_state = terminal.read();
1389
1390 Self::check_controlling_session(&state.session, &terminal_state.controlling_session)?;
1393 if !state
1394 .controlling_terminal
1395 .as_ref()
1396 .is_some_and(|ct| std::ptr::eq(terminal, Arc::as_ptr(&ct.terminal)))
1397 {
1398 return error!(ENOTTY);
1399 }
1400 let controlling_session =
1401 terminal_state.controlling_session.as_ref().ok_or_else(|| errno!(ENOTTY))?;
1402 Ok(controlling_session.foreground_pgid())
1403 }
1404
1405 pub fn set_foreground_process_group(
1406 &self,
1407 current_task: &CurrentTask,
1408 terminal: &Terminal,
1409 pgid: &Pid,
1410 ) -> Result<(), Errno> {
1411 let process_group;
1412 let send_ttou;
1413 {
1414 let state = self.read();
1416 process_group = Arc::clone(&state.process_group);
1417 let mut terminal_state = terminal.write();
1418 Self::check_controlling_session(&state.session, &terminal_state.controlling_session)?;
1419 if !state
1420 .controlling_terminal
1421 .as_ref()
1422 .is_some_and(|ct| std::ptr::eq(terminal, Arc::as_ptr(&ct.terminal)))
1423 {
1424 return error!(ENOTTY);
1425 }
1426
1427 {
1429 let scope = RcuReadScope::new();
1430 if !pgid.is_process_group_in_session(&state.session, &scope) {
1431 return error!(EPERM);
1432 }
1433 }
1434
1435 let controlling_session =
1436 terminal_state.controlling_session.as_mut().ok_or_else(|| errno!(ENOTTY))?;
1437
1438 send_ttou = process_group.id != controlling_session.foreground_pgid()
1441 && !current_task.read().signal_mask().has_signal(SIGTTOU)
1442 && self.signal_actions.get(SIGTTOU).sa_handler != SIG_IGN;
1443
1444 if !send_ttou {
1445 controlling_session.set_foreground_process_group(pgid.clone());
1446 }
1447 }
1448
1449 if send_ttou {
1451 process_group.send_signals_to_pgid(&[SIGTTOU]);
1452 return error!(EINTR);
1453 }
1454
1455 Ok(())
1456 }
1457
1458 pub fn set_controlling_terminal(
1459 &self,
1460 current_task: &CurrentTask,
1461 terminal: &Terminal,
1462 side: TerminalSide,
1463 steal: bool,
1464 is_readable: bool,
1465 ) -> Result<(), Errno> {
1466 let steal_from_session;
1467 let new_controlling_terminal = ControllingTerminal::new(terminal, side);
1468 {
1469 let mut state = self.write();
1471 let mut terminal_state = terminal.write();
1472
1473 if state.session != self.leader {
1476 return error!(EPERM);
1477 }
1478
1479 if let Some(ref current_ct) = state.controlling_terminal {
1480 if current_ct.matches(terminal, side) {
1481 return Ok(());
1482 } else {
1483 return error!(EPERM);
1484 }
1485 }
1486
1487 let session_pid = state.session.clone();
1488 let other_session_pid = terminal_state.controlling_session().cloned();
1489 let mut has_admin_capability_determined = false;
1490 let mut stolen_session = None;
1491
1492 if let Some(other_sid) = other_session_pid {
1493 if other_sid != session_pid {
1494 if !steal {
1500 return error!(EPERM);
1501 }
1502 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1503 has_admin_capability_determined = true;
1504 stolen_session = Some(other_sid);
1505 }
1506 }
1507
1508 if !is_readable && !has_admin_capability_determined {
1509 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1510 }
1511
1512 state.controlling_terminal = Some(new_controlling_terminal);
1513 terminal_state.controlling_session =
1514 Some(ControllingSession::new(&session_pid, &state.process_group));
1515 steal_from_session = stolen_session;
1516 }
1517
1518 if let Some(other_sid) = steal_from_session {
1520 other_sid.clear_controlling_terminal(Some((terminal, None)));
1521 }
1522
1523 Ok(())
1524 }
1525
1526 pub fn release_controlling_terminal(
1527 &self,
1528 _current_task: &CurrentTask,
1529 terminal: &Terminal,
1530 side: TerminalSide,
1531 ) -> Result<(), Errno> {
1532 let controlling_session = {
1533 let mut state = self.write();
1535 let is_session_leader = state.session == self.leader;
1536 let mut terminal_state = terminal.write();
1537
1538 Self::check_controlling_session(&state.session, &terminal_state.controlling_session)?;
1540 if !state.controlling_terminal.as_ref().is_some_and(|ct| ct.matches(terminal, side)) {
1541 return error!(ENOTTY);
1542 }
1543
1544 state.controlling_terminal = None;
1545 is_session_leader.then(|| terminal_state.controlling_session.take()).flatten()
1546 };
1547
1548 if let Some(controlling_session) = controlling_session {
1549 controlling_session.disassociate(terminal, Some(side));
1550 }
1551
1552 Ok(())
1553 }
1554
1555 fn check_orphaned_pgrp(
1558 _pids: &PidTableGuard<'_>,
1559 pgrp: &Pid,
1560 ignored_tg: Option<&ThreadGroup>,
1561 ) {
1562 let scope = RcuReadScope::new();
1563 if pgrp.will_become_orphaned_pgrp(&scope, ignored_tg) && pgrp.has_stopped_jobs(&scope) {
1564 pgrp.send_signals_to_pgid(&[SIGHUP, SIGCONT]);
1565 }
1566 }
1567
1568 pub fn kill_orphaned_pgrp(
1574 &self,
1575 pids: &PidTableGuard<'_>,
1576 parent: Option<&ThreadGroup>,
1577 ignored_tg: Option<&ThreadGroup>,
1578 ) {
1579 let Some(parent_tg) = parent else {
1580 return;
1581 };
1582
1583 let (pgrp, my_sid) = {
1584 let state = self.read();
1585 (Arc::clone(&state.process_group), state.session.id)
1586 };
1587
1588 let (parent_pgid, parent_sid) = {
1589 let parent_state = parent_tg.read();
1590 (parent_state.process_group.id, parent_state.session.id)
1591 };
1592
1593 if parent_pgid == pgrp.id || parent_sid != my_sid {
1595 return;
1596 }
1597
1598 Self::check_orphaned_pgrp(pids, &pgrp, ignored_tg);
1599 }
1600
1601 pub fn get_rlimit(&self, resource: Resource) -> u64 {
1602 self.limits.lock().get(resource).rlim_cur
1603 }
1604
1605 pub fn adjust_rlimits(
1607 current_task: &CurrentTask,
1608 target_task: &Task,
1609 resource: Resource,
1610 maybe_new_limit: Option<rlimit>,
1611 ) -> Result<rlimit, Errno> {
1612 let thread_group = target_task.thread_group();
1613 let mut limit_state = thread_group.limits.lock();
1614 let old_limit = limit_state.get(resource);
1615 if let Some(new_limit) = maybe_new_limit {
1616 if new_limit.rlim_max > old_limit.rlim_max
1617 && !security::is_task_capable_noaudit(current_task, CAP_SYS_RESOURCE)
1618 {
1619 return error!(EPERM);
1620 }
1621 security::task_setrlimit(current_task, &target_task, old_limit, new_limit)?;
1622 limit_state.set(resource, new_limit)
1623 }
1624 Ok(old_limit)
1625 }
1626
1627 pub fn time_stats(&self) -> TaskTimeStats {
1628 let process: &zx::Process = if self.process.as_handle_ref().is_invalid() {
1629 assert_eq!(
1632 self as *const ThreadGroup,
1633 Arc::as_ptr(&self.kernel.kthreads.system_thread_group())
1634 );
1635 &self.kernel.kthreads.starnix_process
1636 } else {
1637 &self.process
1638 };
1639
1640 let info =
1641 zx::Task::get_runtime_info(process).expect("Failed to get starnix process stats");
1642 TaskTimeStats {
1643 user_time: zx::MonotonicDuration::from_nanos(info.cpu_time),
1644 system_time: zx::MonotonicDuration::default(),
1646 }
1647 }
1648
1649 pub fn get_ptracees_and(
1653 &self,
1654 selector: &ProcessSelector,
1655 f: &mut dyn FnMut(&Task, &TaskMutableState),
1656 ) {
1657 for task_ref in self
1658 .ptracees
1659 .lock()
1660 .iter()
1661 .filter(|info| selector.match_tid(&info.tid))
1662 .filter_map(|info| info.tid.get_task().ok())
1663 {
1664 let task_state = task_ref.write();
1665 if task_state.ptrace.is_some() {
1666 f(&task_ref, &task_state);
1667 }
1668 }
1669 }
1670
1671 pub fn get_waitable_ptracee(
1676 &self,
1677 selector: &ProcessSelector,
1678 options: &WaitingOptions,
1679 pids: &mut PidTableGuard<'_>,
1680 ) -> Option<WaitResult> {
1681 let waitable_entry = self.write().zombie_ptracees.get_waitable_entry(selector, options);
1683 match waitable_entry {
1684 None => (),
1685 Some((zombie, None)) => return Some(zombie.to_wait_result()),
1686 Some((zombie, Some((tg, z)))) => {
1687 if let Some(tg) = tg.upgrade() {
1688 if Arc::as_ptr(&tg) != self as *const Self {
1689 tg.do_zombie_notifications(z, pids);
1690 } else {
1691 {
1692 let mut state = tg.write();
1693 state.children.remove(&z.task.pid);
1694 state
1695 .deferred_zombie_ptracers
1696 .retain(|dzp| dzp.tracee_pid != z.task.pid);
1697 }
1698
1699 z.release(pids);
1700 };
1701 }
1702 return Some(zombie.to_wait_result());
1703 }
1704 }
1705
1706 let mut tasks = vec![];
1707
1708 self.get_ptracees_and(selector, &mut |task: &Task, _| {
1710 tasks.push(task.weak_self.clone());
1711 });
1712 for task in tasks {
1713 let Some(task_ref) = task.upgrade() else {
1714 continue;
1715 };
1716
1717 let process_state = &mut task_ref.thread_group().write();
1718 let mut task_state = task_ref.write();
1719 if task_state
1720 .ptrace
1721 .as_ref()
1722 .is_some_and(|ptrace| ptrace.is_waitable(task_ref.load_stopped(), options))
1723 {
1724 let info = process_state.tasks.iter().next().unwrap().clone();
1730 let uid = info.real_creds().uid;
1731 let mut exit_status = None;
1732 let exit_signal = process_state.exit_signal.clone();
1733 let time_stats =
1734 process_state.base.time_stats() + process_state.children_time_stats;
1735 let task_stopped = task_ref.load_stopped();
1736
1737 #[derive(PartialEq)]
1738 enum ExitType {
1739 None,
1740 Cont,
1741 Stop,
1742 Kill,
1743 }
1744 if process_state.is_waitable() {
1745 let ptrace = &mut task_state.ptrace;
1746 let process_stopped = process_state.base.load_stopped();
1748 let mut fn_type = ExitType::None;
1749 if process_stopped == StopState::Awake && options.wait_for_continued {
1750 fn_type = ExitType::Cont;
1751 }
1752 let mut event = ptrace
1753 .as_ref()
1754 .map_or(PtraceEvent::None, |ptrace| {
1755 ptrace.event_data.as_ref().map_or(PtraceEvent::None, |data| data.event)
1756 })
1757 .clone();
1758 if process_stopped == StopState::GroupStopped
1760 && (options.wait_for_stopped || ptrace.is_some())
1761 {
1762 fn_type = ExitType::Stop;
1763 }
1764 if fn_type != ExitType::None {
1765 let siginfo = if options.keep_waitable_state {
1766 process_state.last_signal.clone()
1767 } else {
1768 process_state.last_signal.take()
1769 };
1770 if let Some(mut siginfo) = siginfo {
1771 if task_ref.thread_group().load_stopped() == StopState::GroupStopped
1772 && ptrace.as_ref().is_some_and(|ptrace| ptrace.is_seized())
1773 {
1774 if event == PtraceEvent::None {
1775 event = PtraceEvent::Stop;
1776 }
1777 siginfo.code |= (PtraceEvent::Stop as i32) << 8;
1778 }
1779 if siginfo.signal == SIGKILL {
1780 fn_type = ExitType::Kill;
1781 }
1782 exit_status = match fn_type {
1783 ExitType::Stop => Some((
1784 ExitStatus::Stop(siginfo, event),
1785 process_state.base.leader.clone(),
1786 )),
1787 ExitType::Cont => Some((
1788 ExitStatus::Continue(siginfo, event),
1789 process_state.base.leader.clone(),
1790 )),
1791 ExitType::Kill => Some((
1792 ExitStatus::Kill(siginfo),
1793 process_state.base.leader.clone(),
1794 )),
1795 _ => None,
1796 };
1797 }
1798 ptrace
1801 .as_mut()
1802 .map(|ptrace| ptrace.get_last_signal(options.keep_waitable_state));
1803 }
1804 }
1805 if exit_status.is_none() {
1806 if let Some(ptrace) = task_state.ptrace.as_mut() {
1807 let mut fn_type = ExitType::None;
1809 let event = ptrace
1810 .event_data
1811 .as_ref()
1812 .map_or(PtraceEvent::None, |event| event.event);
1813 if task_stopped == StopState::Awake {
1814 fn_type = ExitType::Cont;
1815 }
1816 if task_stopped.is_stopping_or_stopped()
1817 || ptrace.stop_status == PtraceStatus::Listening
1818 {
1819 fn_type = ExitType::Stop;
1820 }
1821 if fn_type != ExitType::None {
1822 if let Some(siginfo) =
1823 ptrace.get_last_signal(options.keep_waitable_state)
1824 {
1825 if siginfo.signal == SIGKILL {
1826 fn_type = ExitType::Kill;
1827 }
1828 exit_status = match fn_type {
1829 ExitType::Stop => Some((
1830 ExitStatus::Stop(siginfo, event),
1831 task_ref.tid.clone(),
1832 )),
1833 ExitType::Cont => Some((
1834 ExitStatus::Continue(siginfo, event),
1835 task_ref.tid.clone(),
1836 )),
1837 ExitType::Kill => {
1838 Some((ExitStatus::Kill(siginfo), task_ref.tid.clone()))
1839 }
1840 _ => None,
1841 };
1842 }
1843 }
1844 }
1845 }
1846 if let Some((exit_status, pid)) = exit_status {
1847 return Some(WaitResult {
1848 pid,
1849 uid,
1850 zombie_state: ZombieState { exit_status, time_stats },
1851 exit_signal,
1852 });
1853 }
1854 }
1855 }
1856 None
1857 }
1858
1859 pub fn send_signal_unchecked(
1869 &self,
1870 current_task: &CurrentTask,
1871 unchecked_signal: UncheckedSignal,
1872 ) -> Result<(), Errno> {
1873 if let Some(signal) = self.check_signal_access(current_task, unchecked_signal)? {
1874 let signal_info = SignalInfo::with_detail(
1875 signal,
1876 SI_USER as i32,
1877 SignalDetail::Kill {
1878 pid: current_task.pid.clone(),
1879 uid: current_task.current_creds().uid,
1880 },
1881 );
1882
1883 self.write().send_signal(signal_info);
1884 }
1885
1886 Ok(())
1887 }
1888
1889 pub unsafe fn send_signal_unchecked_debug(
1894 &self,
1895 current_task: &CurrentTask,
1896 unchecked_signal: UncheckedSignal,
1897 ) -> Result<(), Errno> {
1898 let signal = Signal::try_from(unchecked_signal)?;
1899 let signal_info = SignalInfo::with_detail(
1900 signal,
1901 SI_USER as i32,
1902 SignalDetail::Kill {
1903 pid: current_task.pid.clone(),
1904 uid: current_task.current_creds().uid,
1905 },
1906 );
1907
1908 self.write().send_signal(signal_info);
1909 Ok(())
1910 }
1911
1912 #[track_caller]
1925 pub fn send_signal_unchecked_with_info(
1926 &self,
1927 current_task: &CurrentTask,
1928 unchecked_signal: UncheckedSignal,
1929 siginfo_ref: UserAddress,
1930 options: IntoSignalInfoOptions,
1931 ) -> Result<(), Errno> {
1932 let siginfo = UncheckedSignalInfo::read_from_siginfo(current_task, siginfo_ref)?;
1933 if self.leader.id != current_task.get_pid()
1934 && (siginfo.code() >= 0 || siginfo.code() == SI_TKILL)
1935 {
1936 return error!(EPERM);
1937 }
1938
1939 if matches!(options, IntoSignalInfoOptions::CheckSigno)
1940 && siginfo.signo() as u64 != unchecked_signal.raw()
1941 {
1942 return error!(EINVAL);
1943 }
1944
1945 if let Some(signal) = self.check_signal_access(current_task, unchecked_signal)? {
1946 self.write().send_signal(siginfo.into_signal_info(signal, options)?);
1947 }
1948
1949 Ok(())
1950 }
1951
1952 fn check_signal_access(
1960 &self,
1961 current_task: &CurrentTask,
1962 unchecked_signal: UncheckedSignal,
1963 ) -> Result<Option<Signal>, Errno> {
1964 let Some(target_task) = self.read().get_signalable_task() else {
1968 return Ok(None);
1972 };
1973 current_task.can_signal(&target_task, unchecked_signal)?;
1974
1975 if unchecked_signal.is_zero() {
1977 return Ok(None);
1978 }
1979
1980 let signal = Signal::try_from(unchecked_signal)?;
1981 security::check_signal_access(current_task, &target_task, signal)?;
1982
1983 Ok(Some(signal))
1984 }
1985
1986 pub fn has_signal_queued(&self, signal: Signal) -> bool {
1987 self.pending_signals.lock().has_queued(signal)
1988 }
1989
1990 pub fn num_signals_queued(&self) -> usize {
1991 self.pending_signals.lock().num_queued()
1992 }
1993
1994 pub fn get_pending_signals(&self) -> SigSet {
1995 self.pending_signals.lock().pending()
1996 }
1997
1998 pub fn is_any_signal_allowed_by_mask(&self, mask: SigSet) -> bool {
1999 self.pending_signals.lock().is_any_allowed_by_mask(mask)
2000 }
2001
2002 pub fn take_next_signal_where<F>(&self, predicate: F) -> Option<SignalInfo>
2003 where
2004 F: Fn(&SignalInfo) -> bool,
2005 {
2006 let mut signals = self.pending_signals.lock();
2007 let r = signals.take_next_where(predicate);
2008 self.has_pending_signals.store(!signals.is_empty(), Ordering::Relaxed);
2009 r
2010 }
2011
2012 pub async fn shut_down(this: Weak<Self>) {
2018 const SHUTDOWN_SIGNAL_HANDLING_TIMEOUT: zx::MonotonicDuration =
2019 zx::MonotonicDuration::from_seconds(1);
2020
2021 let (tg_name, mut on_exited) = {
2023 let Some(this) = this.upgrade() else {
2025 return;
2026 };
2027
2028 let mut state = this.write();
2029 if state.is_exited() {
2030 return;
2032 }
2033
2034 let (on_exited_send, on_exited) = futures::channel::oneshot::channel();
2036 state.exit_notifier = Some(on_exited_send);
2037
2038 let tg_name = format!("{this:?}");
2040
2041 (tg_name, on_exited)
2042 };
2043
2044 log_debug!(tg:% = tg_name; "shutting down thread group, sending SIGTERM");
2045 this.upgrade().map(|tg| tg.write().send_signal(SignalInfo::kernel(SIGTERM)));
2046
2047 let timeout = fuchsia_async::Timer::new(SHUTDOWN_SIGNAL_HANDLING_TIMEOUT);
2049 futures::pin_mut!(timeout);
2050
2051 futures::select_biased! {
2053 _ = &mut on_exited => (),
2054 _ = timeout => {
2055 log_debug!(tg:% = tg_name; "sending SIGKILL");
2056 this.upgrade().map(|tg| tg.write().send_signal(SignalInfo::kernel(SIGKILL)));
2057 },
2058 };
2059
2060 log_debug!(tg:% = tg_name; "waiting for exit");
2061 on_exited.await.ok();
2064 log_debug!(tg:% = tg_name; "thread group shutdown complete");
2065 }
2066
2067 pub fn get_process_koid(&self) -> Result<Koid, Status> {
2073 self.process.koid()
2074 }
2075}
2076
2077pub enum WaitableChildResult {
2078 ReadyNow(Box<WaitResult>),
2079 ShouldWait,
2080 NoneFound,
2081}
2082
2083#[apply(state_implementation!)]
2084impl ThreadGroupMutableState<Base = ThreadGroup> {
2085 pub fn parent_death_signal(&self) -> Option<Signal> {
2087 self.parent_death_signal
2088 }
2089
2090 pub fn set_parent_death_signal(&mut self, signal: Option<Signal>) {
2092 self.parent_death_signal = signal;
2093 }
2094
2095 fn parent_death_signal_for_exiting_task(
2103 &self,
2104 exiting_task: &Arc<Task>,
2105 parent_is_subreaper: bool,
2106 ) -> Option<Signal> {
2107 let should_signal =
2108 self.parent.as_ref().is_some_and(|parent| match parent.creator_task() {
2109 Some(creator_task) => Weak::ptr_eq(creator_task, &exiting_task.weak_self),
2110 None => parent_is_subreaper,
2111 });
2112 should_signal.then_some(self.parent_death_signal).flatten()
2113 }
2114
2115 pub fn leader(&self) -> pid_t {
2116 self.base.leader.id
2117 }
2118
2119 pub fn leader_command(&self) -> TaskCommand {
2120 self.get_task(self.leader())
2121 .map(|l| l.command())
2122 .unwrap_or_else(|| TaskCommand::new(b"<leader exited>"))
2123 }
2124
2125 pub fn is_running(&self) -> bool {
2126 matches!(self.run_state, ThreadGroupRunState::Running)
2127 }
2128
2129 pub fn is_exited(&self) -> bool {
2130 matches!(self.run_state, ThreadGroupRunState::Exited(_))
2131 }
2132
2133 fn set_exiting(&mut self, exit_status: ExitStatus) {
2135 self.run_state = ThreadGroupRunState::Exiting(exit_status);
2136 }
2137
2138 fn set_exited(&mut self) {
2139 let ThreadGroupRunState::Exiting(exit_status) = std::mem::take(&mut self.run_state) else {
2140 panic!("Must transition from Exiting to Exited");
2141 };
2142 self.run_state = ThreadGroupRunState::Exited(exit_status);
2143
2144 if let Some(notifier) = self.exit_notifier.take() {
2145 let _ = notifier.send(());
2146 }
2147 }
2148
2149 pub fn children(&self) -> impl Iterator<Item = Arc<ThreadGroup>> + '_ {
2155 self.children.iter().flat_map(|pid| pid.get_thread_group().ok())
2156 }
2157
2158 pub fn tasks(&self) -> Vec<Arc<Task>> {
2159 self.tasks.iter().flat_map(|info| info.tid.get_task().ok()).collect()
2160 }
2161
2162 pub fn first_task(&self) -> Option<Arc<Task>> {
2163 self.tasks.iter().find_map(|info| info.tid.get_task().ok())
2164 }
2165
2166 pub fn task_ids(&self) -> impl Iterator<Item = tid_t> + '_ {
2167 self.tasks.iter().map(|info| info.tid.id)
2168 }
2169
2170 pub fn contains_task(&self, tid: tid_t) -> bool {
2171 self.tasks.iter().any(|info| info.tid.id == tid)
2172 }
2173
2174 pub fn get_task(&self, tid: tid_t) -> Option<Arc<Task>> {
2175 self.tasks.iter().find(|info| info.tid.id == tid).and_then(|info| info.tid.get_task().ok())
2176 }
2177
2178 pub fn tasks_count(&self) -> usize {
2179 self.tasks.len()
2180 }
2181
2182 pub fn get_ppid(&self) -> pid_t {
2183 match &self.parent {
2184 Some(parent) => parent.upgrade().leader.id,
2185 None => 0,
2186 }
2187 }
2188
2189 fn reap_zombie(&mut self, zombie: OwnedRef<ZombieProcess>, pids: &mut PidTableGuard<'_>) {
2191 self.children_time_stats += zombie.state.time_stats;
2192 zombie.release(pids);
2193 }
2194
2195 pub fn is_waitable(&self) -> bool {
2198 return self.last_signal.is_some() && !self.base.load_stopped().is_in_progress();
2199 }
2200
2201 pub fn get_waitable_zombie(
2202 &mut self,
2203 zombie_list: &dyn Fn(&mut ThreadGroupMutableState) -> &mut Vec<OwnedRef<ZombieProcess>>,
2204 selector: &ProcessSelector,
2205 options: &WaitingOptions,
2206 pids: &mut PidTableGuard<'_>,
2207 ) -> Option<WaitResult> {
2208 let selected_zombie_position = zombie_list(self)
2210 .iter()
2211 .rev()
2212 .position(|zombie| zombie.matches_selector_and_waiting_option(selector, options))
2213 .map(|position_starting_from_the_back| {
2214 zombie_list(self).len() - 1 - position_starting_from_the_back
2215 });
2216
2217 selected_zombie_position.map(|position| {
2218 if options.keep_waitable_state {
2219 zombie_list(self)[position].to_wait_result()
2220 } else {
2221 let zombie = zombie_list(self).remove(position);
2222 let result = zombie.to_wait_result();
2223 self.reap_zombie(zombie, pids);
2224 result
2225 }
2226 })
2227 }
2228
2229 pub fn is_correct_exit_signal(for_clone: bool, exit_code: Option<Signal>) -> bool {
2230 for_clone == (exit_code != Some(SIGCHLD))
2231 }
2232
2233 fn get_waitable_running_children(
2234 &self,
2235 selector: &ProcessSelector,
2236 options: &WaitingOptions,
2237 ) -> WaitableChildResult {
2238 let filter_children_by_pid_selector = |child: &ThreadGroup| match selector {
2240 ProcessSelector::Any => true,
2241 ProcessSelector::Pid(pid) => &child.leader == pid,
2242 ProcessSelector::Pgid(pgid) => {
2243 let _token = allow_subclass();
2247 &child.read().process_group == pgid
2248 }
2249 };
2250
2251 let filter_children_by_waiting_options = |child: &ThreadGroup| {
2253 if options.wait_for_all {
2254 return true;
2255 }
2256 let _token = allow_subclass();
2260 Self::is_correct_exit_signal(options.wait_for_clone, child.read().exit_signal)
2261 };
2262
2263 let mut selected_children = self
2266 .children()
2267 .filter(|tg| filter_children_by_pid_selector(&tg))
2268 .filter(|tg| filter_children_by_waiting_options(&tg))
2269 .peekable();
2270 if selected_children.peek().is_none() {
2271 if self.deferred_zombie_ptracers.iter().any(|dzp| match selector {
2273 ProcessSelector::Any => true,
2274 ProcessSelector::Pid(pid) => &dzp.tracee_pid == pid,
2275 ProcessSelector::Pgid(pgid) => &dzp.tracee_pgid == pgid,
2276 }) {
2277 return WaitableChildResult::ShouldWait;
2278 }
2279
2280 return WaitableChildResult::NoneFound;
2281 }
2282 for child in selected_children {
2283 let _token = allow_subclass();
2287 let child = child.write();
2288 if child.last_signal.is_some() {
2289 let build_wait_result = |mut child: ThreadGroupWriteGuard<'_>,
2290 exit_status: &dyn Fn(SignalInfo) -> ExitStatus|
2291 -> WaitResult {
2292 let siginfo = if options.keep_waitable_state {
2293 child.last_signal.clone().unwrap()
2294 } else {
2295 child.last_signal.take().unwrap()
2296 };
2297 let exit_status = if siginfo.signal == SIGKILL {
2298 ExitStatus::Kill(siginfo)
2300 } else {
2301 exit_status(siginfo)
2302 };
2303 let info = child.tasks.iter().next().unwrap();
2304 let uid = info.real_creds().uid;
2305 WaitResult {
2306 pid: child.base.leader.clone(),
2307 uid,
2308 zombie_state: ZombieState {
2309 exit_status,
2310 time_stats: child.base.time_stats() + child.children_time_stats,
2311 },
2312 exit_signal: child.exit_signal,
2313 }
2314 };
2315 let child_stopped = child.base.load_stopped();
2316 if child_stopped == StopState::Awake && options.wait_for_continued {
2317 return WaitableChildResult::ReadyNow(Box::new(build_wait_result(
2318 child,
2319 &|siginfo| ExitStatus::Continue(siginfo, PtraceEvent::None),
2320 )));
2321 }
2322 if child_stopped == StopState::GroupStopped && options.wait_for_stopped {
2323 return WaitableChildResult::ReadyNow(Box::new(build_wait_result(
2324 child,
2325 &|siginfo| ExitStatus::Stop(siginfo, PtraceEvent::None),
2326 )));
2327 }
2328 }
2329 }
2330
2331 WaitableChildResult::ShouldWait
2332 }
2333
2334 pub fn get_waitable_child(
2340 &mut self,
2341 selector: &ProcessSelector,
2342 options: &WaitingOptions,
2343 pids: &mut PidTableGuard<'_>,
2344 ) -> WaitableChildResult {
2345 if options.wait_for_exited {
2346 if let Some(waitable_zombie) = self.get_waitable_zombie(
2347 &|state: &mut ThreadGroupMutableState| &mut state.zombie_children,
2348 selector,
2349 options,
2350 pids,
2351 ) {
2352 return WaitableChildResult::ReadyNow(Box::new(waitable_zombie));
2353 }
2354 }
2355
2356 self.get_waitable_running_children(selector, options)
2357 }
2358
2359 pub fn get_running_task(&self) -> Result<Arc<Task>, Errno> {
2361 self.tasks
2362 .iter()
2363 .find_map(|info| info.tid.get_task().ok().filter(|task| task.is_running()))
2364 .ok_or_else(|| errno!(ESRCH))
2365 }
2366
2367 pub fn get_running_task_with_files(&self) -> Result<Arc<Task>, Errno> {
2370 if let Ok(task) = self.base.leader.get_task() {
2371 if task.is_running() && task.files().is_ok() {
2372 return Ok(task);
2373 }
2374 }
2375 self.tasks
2376 .iter()
2377 .find_map(|info| {
2378 info.tid.get_task().ok().filter(|task| task.is_running() && task.files().is_ok())
2379 })
2380 .ok_or_else(|| errno!(ESRCH))
2381 }
2382
2383 fn get_signalable_task(&self) -> Option<Arc<Task>> {
2388 let mut non_running = if let Ok(task) = self.base.leader.get_task() {
2389 if task.is_running() {
2390 return Some(task);
2391 }
2392 Some(task)
2393 } else {
2394 None
2395 };
2396 for container in &self.tasks {
2397 if let Ok(task) = container.tid.get_task() {
2398 if task.is_running() {
2399 return Some(task);
2400 }
2401 if non_running.is_none() {
2402 non_running = Some(task);
2403 }
2404 }
2405 }
2406 non_running
2407 }
2408
2409 pub fn set_stopped(
2416 mut self,
2417 new_stopped: StopState,
2418 siginfo: Option<SignalInfo>,
2419 finalize_only: bool,
2420 ) -> StopState {
2421 if let Some(stopped) = self.base.check_stopped_state(new_stopped, finalize_only) {
2422 return stopped;
2423 }
2424
2425 if self.base.load_stopped() == StopState::Waking
2428 && (new_stopped == StopState::GroupStopping || new_stopped == StopState::GroupStopped)
2429 {
2430 return self.base.load_stopped();
2431 }
2432
2433 self.store_stopped(new_stopped);
2437 if let Some(signal) = &siginfo {
2438 if signal.signal != SIGKILL {
2442 self.last_signal = siginfo;
2443 }
2444 }
2445 if new_stopped == StopState::Waking || new_stopped == StopState::ForceWaking {
2446 self.lifecycle_waiters.notify_value(ThreadGroupLifecycleWaitValue::Stopped);
2447 };
2448
2449 let parent = (!new_stopped.is_in_progress()).then(|| self.parent.clone()).flatten();
2450
2451 std::mem::drop(self);
2453 if let Some(parent) = parent {
2454 let parent = parent.upgrade();
2455 parent
2456 .write()
2457 .lifecycle_waiters
2458 .notify_value(ThreadGroupLifecycleWaitValue::ChildStatus);
2459 }
2460
2461 new_stopped
2462 }
2463
2464 fn store_stopped(&mut self, state: StopState) {
2465 self.base.stop_state.store(state, Ordering::Relaxed)
2470 }
2471
2472 #[allow(unused_mut, reason = "needed for some but not all macro outputs")]
2482 fn terminate_tasks(
2483 mut self,
2484 exit_status: ExitStatus,
2485 wake_signal: SignalInfo,
2486 excluded_tid: Option<&Pid>,
2487 ) {
2488 if self.is_running() {
2489 self.set_exiting(exit_status.clone());
2490 }
2491
2492 let tasks: Vec<Arc<Task>> = self
2493 .tasks()
2494 .into_iter()
2495 .filter(|task| task.is_running() && excluded_tid != Some(&task.tid))
2496 .collect();
2497 for task in &tasks {
2498 let mut task_state = task.write();
2499 task_state.set_exit_status_if_not_already(exit_status.clone());
2500 task_state.force_wake_for_exit();
2501 }
2502
2503 self.set_stopped(
2504 StopState::ForceWaking,
2505 Some(wake_signal),
2506 false,
2507 );
2508
2509 for task in tasks {
2510 task.interrupt();
2511 }
2512 }
2513
2514 #[allow(unused_mut, reason = "needed for some but not all macro outputs")]
2515 pub(crate) fn force_exit_for_sigkill(mut self, signal_info: SignalInfo) {
2516 let exit_status = ExitStatus::Kill(signal_info.clone());
2517 self.terminate_tasks(exit_status, signal_info, None);
2518 }
2519
2520 #[allow(unused_mut, reason = "needed for some but not all macro outputs")]
2522 pub fn send_signal(mut self, signal_info: SignalInfo) {
2523 if signal_info.signal == SIGKILL {
2526 self.force_exit_for_sigkill(signal_info);
2527 return;
2528 }
2529
2530 let sigaction = self.base.signal_actions.get(signal_info.signal);
2531 let action = action_for_signal(&signal_info, sigaction);
2532
2533 let queue_on_group = action != DeliveryAction::Ignore
2539 || self
2540 .tasks
2541 .iter()
2542 .filter_map(|info| info.tid.get_task().ok())
2543 .filter(|task| task.is_running())
2544 .any(|task| {
2545 let task_state = task.read();
2546 task_state.is_signal_masked(signal_info.signal)
2547 || task_state.is_signal_masked_by_saved_mask(signal_info.signal)
2548 || task_state.is_ptraced()
2549 });
2550
2551 if queue_on_group {
2552 let mut pending_signals = self.base.pending_signals.lock();
2553 pending_signals.enqueue(signal_info.clone());
2554 self.base.has_pending_signals.store(true, Ordering::Relaxed);
2555 }
2556
2557 let tasks: Vec<Pid> = self.tasks.iter().map(|info| info.tid.clone()).collect();
2558
2559 if signal_info.signal == SIGCONT {
2561 self.set_stopped(
2562 StopState::Waking,
2563 Some(signal_info.clone()),
2564 false,
2565 );
2566 }
2567
2568 let mut has_interrupted_task = false;
2569 for task in tasks.iter().flat_map(|pid| pid.get_task().ok()) {
2570 if !task.is_running() {
2571 continue;
2572 }
2573
2574 let mut task_state = task.write();
2575
2576 if signal_info.signal == SIGCONT {
2577 task_state.set_stopped(
2578 StopState::Waking,
2579 None,
2580 None,
2581 None,
2582 );
2583 }
2584
2585 let is_masked = task_state.is_signal_masked(signal_info.signal);
2586 let was_masked = task_state.is_signal_masked_by_saved_mask(signal_info.signal);
2587
2588 let is_queued = action != DeliveryAction::Ignore
2589 || is_masked
2590 || was_masked
2591 || task_state.is_ptraced();
2592
2593 if is_queued {
2594 task_state.notify_signal_waiters(&signal_info.signal);
2595
2596 let is_fatal = action == DeliveryAction::Terminate && !task_state.is_ptraced();
2597
2598 if !is_masked
2599 && action.must_interrupt(Some(sigaction))
2600 && (!has_interrupted_task || is_fatal)
2601 {
2602 drop(task_state);
2605 task.interrupt();
2606 has_interrupted_task = true;
2607 }
2608 }
2609 }
2610 }
2611}
2612
2613#[cfg(test)]
2614mod test {
2615 use super::*;
2616 use crate::ptrace::ptrace_traceme;
2617 use crate::signals::send_signal;
2618 use crate::testing::*;
2619 use starnix_syscalls::SUCCESS;
2620 use starnix_uapi::user_address::UserRef;
2621 use starnix_uapi::{CLONE_SIGHAND, CLONE_THREAD, CLONE_VM};
2622
2623 #[::fuchsia::test]
2624 async fn test_setsid() {
2625 spawn_kernel_and_run(async |current_task| {
2626 fn get_process_group(task: &Task) -> Pid {
2627 Arc::clone(&task.thread_group().read().process_group)
2628 }
2629 assert_eq!(current_task.thread_group().setsid(), error!(EPERM));
2630
2631 let child_task = current_task.clone_task_for_test(0, Some(SIGCHLD));
2632 assert_eq!(get_process_group(¤t_task), get_process_group(&child_task));
2633
2634 let old_process_group = child_task.thread_group().read().process_group.clone();
2635 assert_eq!(child_task.thread_group().setsid(), Ok(()));
2636 assert_eq!(child_task.thread_group().read().session, child_task.pid);
2637 let scope = RcuReadScope::new();
2638 assert!(
2639 !old_process_group
2640 .pgid_thread_groups(&scope)
2641 .any(|tg| Arc::ptr_eq(&tg, child_task.thread_group()))
2642 );
2643 })
2644 .await;
2645 }
2646
2647 #[::fuchsia::test]
2648 async fn test_exit_status() {
2649 spawn_kernel_and_run(async |current_task| {
2650 let child = current_task.clone_task_for_test(0, Some(SIGCHLD));
2651 child.thread_group().kill(ExitStatus::Exit(42), None);
2652 assert_eq!(child.exit_status(), Some(ExitStatus::Exit(42)));
2653 std::mem::drop(child);
2654 assert_eq!(
2655 current_task.thread_group().read().zombie_children[0].state.exit_status,
2656 ExitStatus::Exit(42)
2657 );
2658 })
2659 .await;
2660 }
2661
2662 #[::fuchsia::test]
2663 async fn test_kill_thread_group_when_already_exiting() {
2664 spawn_kernel_and_run(async |current_task| {
2665 let clone_thread_flags = (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM) as u64;
2666 let mut leader = current_task.clone_task_for_test(0, Some(SIGCHLD));
2667 let mut sibling = leader.clone_task_for_test(clone_thread_flags, None);
2668
2669 leader.thread_group().write().set_exiting(ExitStatus::Exit(42));
2672 sibling.kill_thread_group(ExitStatus::Exit(99));
2673 assert!(sibling.is_exitted());
2674
2675 leader.kill_thread_group(ExitStatus::Exit(0));
2676 assert!(leader.is_exitted());
2677 std::mem::drop(sibling);
2678 std::mem::drop(leader);
2679 assert_eq!(
2680 current_task.thread_group().read().zombie_children[0].state.exit_status,
2681 ExitStatus::Exit(42)
2682 );
2683 })
2684 .await;
2685 }
2686
2687 #[::fuchsia::test]
2688 async fn test_sigkill_fast_path_exiting() {
2689 spawn_kernel_and_run(async |current_task| {
2690 let clone_thread_flags = (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM) as u64;
2691
2692 let process_killed_leader = current_task.clone_task_for_test(0, Some(SIGCHLD));
2694 let process_killed_thread =
2695 process_killed_leader.clone_task_for_test(clone_thread_flags, None);
2696 assert!(process_killed_leader.thread_group().read().is_running());
2697 assert!(!process_killed_leader.is_exitted());
2698 assert!(!process_killed_thread.is_exitted());
2699
2700 assert_eq!(
2701 process_killed_leader
2702 .thread_group()
2703 .send_signal_unchecked(current_task, SIGKILL.into()),
2704 Ok(())
2705 );
2706 assert!(!process_killed_leader.thread_group().read().is_running());
2707 assert!(process_killed_leader.is_exitted());
2708 assert!(process_killed_thread.is_exitted());
2709 std::mem::drop(process_killed_thread);
2710 std::mem::drop(process_killed_leader);
2711
2712 let task_killed_leader = current_task.clone_task_for_test(0, Some(SIGCHLD));
2714 let task_killed_thread =
2715 task_killed_leader.clone_task_for_test(clone_thread_flags, None);
2716 let task_sigkill_info = SignalInfo::with_sender(
2717 SIGKILL,
2718 SI_TKILL,
2719 SignalDetail::Kill {
2720 pid: current_task.pid.clone(),
2721 uid: current_task.current_creds().uid,
2722 },
2723 Some(current_task.weak_self.clone()),
2724 );
2725 assert_eq!(send_signal(&task_killed_thread, task_sigkill_info), Ok(()));
2726 assert!(!task_killed_leader.thread_group().read().is_running());
2727 assert!(task_killed_leader.is_exitted());
2728 assert!(task_killed_thread.is_exitted());
2729 })
2730 .await;
2731 }
2732
2733 #[::fuchsia::test]
2734 async fn test_setgpid() {
2735 spawn_kernel_and_run(async |current_task| {
2736 assert_eq!(current_task.thread_group().setsid(), error!(EPERM));
2737
2738 let child_task1 = current_task.clone_task_for_test(0, Some(SIGCHLD));
2739 let child_task2 = current_task.clone_task_for_test(0, Some(SIGCHLD));
2740 let execd_child_task = current_task.clone_task_for_test(0, Some(SIGCHLD));
2741 execd_child_task.thread_group().write().did_exec = true;
2742 let other_session_child_task = current_task.clone_task_for_test(0, Some(SIGCHLD));
2743 assert_eq!(other_session_child_task.thread_group().setsid(), Ok(()));
2744
2745 assert_eq!(
2746 child_task1.thread_group().setpgid(¤t_task, ¤t_task, ¤t_task.pid),
2747 error!(ESRCH)
2748 );
2749 assert_eq!(
2750 current_task.thread_group().setpgid(
2751 ¤t_task,
2752 &execd_child_task,
2753 &execd_child_task.pid
2754 ),
2755 error!(EACCES)
2756 );
2757 assert_eq!(
2758 current_task.thread_group().setpgid(
2759 ¤t_task,
2760 ¤t_task,
2761 ¤t_task.pid
2762 ),
2763 error!(EPERM)
2764 );
2765 assert_eq!(
2766 current_task.thread_group().setpgid(
2767 ¤t_task,
2768 &other_session_child_task,
2769 &other_session_child_task.pid
2770 ),
2771 error!(EPERM)
2772 );
2773 assert_eq!(
2774 current_task.thread_group().setpgid(¤t_task, &child_task1, &child_task2.pid),
2775 error!(EPERM)
2776 );
2777 assert_eq!(
2778 current_task.thread_group().setpgid(
2779 ¤t_task,
2780 &child_task1,
2781 &other_session_child_task.pid
2782 ),
2783 error!(EPERM)
2784 );
2785
2786 assert_eq!(
2787 child_task1.thread_group().setpgid(¤t_task, &child_task1, &child_task1.pid),
2788 Ok(())
2789 );
2790 assert_eq!(child_task1.thread_group().read().session, current_task.tid);
2791 assert_eq!(child_task1.thread_group().read().process_group, child_task1.tid);
2792
2793 let old_process_group = child_task2.thread_group().read().process_group.clone();
2794 assert_eq!(
2795 current_task.thread_group().setpgid(¤t_task, &child_task2, &child_task1.pid),
2796 Ok(())
2797 );
2798 assert_eq!(child_task2.thread_group().read().process_group, child_task1.tid);
2799 let scope = RcuReadScope::new();
2800 assert!(
2801 !old_process_group
2802 .pgid_thread_groups(&scope)
2803 .any(|tg| Arc::ptr_eq(&tg, child_task2.thread_group()))
2804 );
2805
2806 let child_task3 = current_task.clone_task_for_test(0, Some(SIGCHLD));
2807 assert_eq!(
2808 child_task3.thread_group().setpgid(¤t_task, &child_task3, &child_task3.pid),
2809 Ok(())
2810 );
2811 assert_eq!(
2813 current_task.thread_group().setpgid(¤t_task, &child_task1, &child_task3.pid),
2814 Ok(())
2815 );
2816 assert_eq!(child_task1.thread_group().read().process_group, child_task3.tid);
2817
2818 assert_eq!(
2820 child_task1.thread_group().setpgid(¤t_task, &child_task1, &child_task1.pid),
2821 Ok(())
2822 );
2823 assert_eq!(child_task1.thread_group().read().process_group, child_task1.tid);
2824 let pg1 = child_task1.thread_group().read().process_group.clone();
2825 let pg2 = child_task2.thread_group().read().process_group.clone();
2826 assert_eq!(pg1, pg2);
2827
2828 assert_eq!(
2829 crate::task::syscalls::sys_setpgid(¤t_task, child_task1.pid.id, -1),
2830 error!(EINVAL)
2831 );
2832 assert_eq!(
2833 crate::task::syscalls::sys_setpgid(¤t_task, child_task1.pid.id, 255),
2834 error!(EPERM)
2835 );
2836 })
2837 .await;
2838 }
2839
2840 #[::fuchsia::test]
2841 async fn test_adopt_children() {
2842 spawn_kernel_and_run(async |current_task| {
2843 let task1 = current_task.clone_task_for_test(0, None);
2844 let task2 = task1.clone_task_for_test(0, None);
2845 let task3 = task2.clone_task_for_test(0, None);
2846
2847 assert_eq!(task3.thread_group().read().get_ppid(), task2.tid.id);
2848 assert!(current_task.thread_group().read().children.contains(&task1.pid));
2849 assert!(task1.thread_group().read().children.contains(&task2.pid));
2850 assert!(task2.thread_group().read().children.contains(&task3.pid));
2851
2852 task2.thread_group().kill(ExitStatus::Exit(0), None);
2853 std::mem::drop(task2);
2854
2855 assert_eq!(task3.thread_group().read().get_ppid(), current_task.tid.id);
2857 assert!(current_task.thread_group().read().children.contains(&task3.pid));
2858 assert!(!task1.thread_group().read().children.contains(&task3.pid));
2859 })
2860 .await;
2861 }
2862
2863 #[::fuchsia::test]
2864 async fn test_thread_group_children_lifecycle() {
2865 spawn_kernel_and_run(async |current_task| {
2866 let child1 = current_task.clone_task_for_test(0, Some(SIGCHLD));
2867 let child2 = current_task.clone_task_for_test(0, Some(SIGCHLD));
2868 let child1_pid = child1.pid.clone();
2869 let child2_pid = child2.pid.clone();
2870
2871 assert!(current_task.thread_group().read().children.contains(&child1_pid));
2872 assert!(current_task.thread_group().read().children.contains(&child2_pid));
2873
2874 let children_pids: HashSet<Pid> =
2875 current_task.thread_group().read().children().map(|tg| tg.leader.clone()).collect();
2876 assert!(children_pids.contains(&child1_pid));
2877 assert!(children_pids.contains(&child2_pid));
2878
2879 child1.thread_group().kill(ExitStatus::Exit(0), None);
2880 std::mem::drop(child1);
2881
2882 assert!(child1_pid.get_thread_group().is_err());
2883 assert!(!current_task.thread_group().read().children.contains(&child1_pid));
2884 assert!(current_task.thread_group().read().children.contains(&child2_pid));
2885 let children_pids: HashSet<Pid> =
2886 current_task.thread_group().read().children().map(|tg| tg.leader.clone()).collect();
2887 assert!(!children_pids.contains(&child1_pid));
2888 assert!(children_pids.contains(&child2_pid));
2889
2890 child2.thread_group().kill(ExitStatus::Exit(0), None);
2891 std::mem::drop(child2);
2892
2893 assert!(child2_pid.get_thread_group().is_err());
2894 assert!(current_task.thread_group().read().children.is_empty());
2895 assert_eq!(current_task.thread_group().read().children().count(), 0);
2896 })
2897 .await;
2898 }
2899
2900 #[::fuchsia::test]
2901 async fn test_ptrace_unspawned_child_drop() {
2902 spawn_kernel_and_run(async |current_task| {
2903 let mut child = create_task(current_task.kernel(), "tracee");
2904 let child_pid = child.pid.clone();
2905 assert!(current_task.thread_group().read().children.contains(&child_pid));
2906
2907 assert_eq!(ptrace_traceme(&mut child), Ok(SUCCESS));
2908 child.thread_group().kill(ExitStatus::Exit(0), None);
2909 std::mem::drop(child);
2910
2911 assert!(!current_task.thread_group().read().children.contains(&child_pid));
2912 assert!(current_task.thread_group().read().zombie_children.is_empty());
2913
2914 let child_leader = current_task.clone_task_for_test(0, Some(SIGCHLD));
2917 let child_pid = child_leader.pid.clone();
2918 let mut child_thread: AutoReleasableTask = child_leader
2919 .clone_task(
2920 (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM) as u64,
2921 None,
2922 UserRef::default(),
2923 UserRef::default(),
2924 UserRef::default(),
2925 )
2926 .expect("failed to create thread")
2927 .into();
2928 assert_ne!(child_thread.tid, child_pid);
2929 assert_eq!(child_thread.pid, child_pid);
2930 assert!(current_task.thread_group().read().children.contains(&child_pid));
2931
2932 child_leader.write().set_exit_status(ExitStatus::Exit(0));
2934 std::mem::drop(child_leader);
2935 assert!(current_task.thread_group().read().children.contains(&child_pid));
2936
2937 assert_eq!(ptrace_traceme(&mut child_thread), Ok(SUCCESS));
2938 child_thread.thread_group().kill(ExitStatus::Exit(0), None);
2939 std::mem::drop(child_thread);
2940
2941 assert!(!current_task.thread_group().read().children.contains(&child_pid));
2942 assert!(current_task.thread_group().read().zombie_children.is_empty());
2943 })
2944 .await;
2945 }
2946
2947 #[::fuchsia::test]
2948 async fn test_getppid_after_self_and_parent_exit() {
2949 spawn_kernel_and_run(async |current_task| {
2950 let task1 = current_task.clone_task_for_test(0, None);
2951 let task2 = task1.clone_task_for_test(0, None);
2952
2953 let tg1 = task1.thread_group().clone();
2955 let tg2 = task2.thread_group().clone();
2956
2957 assert_eq!(tg1.read().get_ppid(), current_task.tid.id);
2958 assert_eq!(tg2.read().get_ppid(), task1.tid.id);
2959
2960 tg2.kill(ExitStatus::Exit(0), None);
2962 std::mem::drop(task2);
2963
2964 tg1.kill(ExitStatus::Exit(0), None);
2966 std::mem::drop(task1);
2967 std::mem::drop(tg1);
2968
2969 let _ = tg2.read().get_ppid();
2972 })
2973 .await;
2974 }
2975
2976 #[::fuchsia::test]
2977 async fn test_thread_group_rcu_links_and_adapters() {
2978 spawn_kernel_and_run(async |current_task| {
2979 let scope = RcuReadScope::new();
2980 let tg = current_task.thread_group();
2981 let node_ptr = tg.pgrp_node.read(&scope);
2982 assert!(!node_ptr.is_null());
2983 let link_ptr = ThreadGroupLinkAdapter::to_link(node_ptr);
2984 assert_eq!(ThreadGroupLinkAdapter::from_link(link_ptr).as_ptr(), node_ptr.as_ptr());
2985
2986 let init_pid = current_task.pid.clone();
2987
2988 assert!(init_pid.is_process_group(&scope));
2989 assert!(init_pid.is_session(&scope));
2990 assert_eq!(init_pid.pgid_thread_groups(&scope).count(), 1);
2991 assert_eq!(init_pid.sid_thread_groups(&scope).count(), 1);
2992
2993 let child = current_task.clone_task_for_test(0, None);
2994 assert_eq!(init_pid.pgid_thread_groups(&scope).count(), 2);
2995 assert_eq!(init_pid.sid_thread_groups(&scope).count(), 2);
2996
2997 child
3000 .thread_group()
3001 .setpgid(¤t_task, &child, &child.pid)
3002 .expect("setpgid failed");
3003 assert_eq!(init_pid.pgid_thread_groups(&scope).count(), 1);
3004 assert_eq!(init_pid.sid_thread_groups(&scope).count(), 2);
3005 assert!(child.pid.is_process_group(&scope));
3006 assert!(!child.pid.is_session(&scope));
3007 assert_eq!(child.pid.pgid_thread_groups(&scope).count(), 1);
3008
3009 child
3011 .thread_group()
3012 .setpgid(¤t_task, &child, &init_pid)
3013 .expect("setpgid back to init failed");
3014 assert_eq!(init_pid.pgid_thread_groups(&scope).count(), 2);
3015 assert_eq!(init_pid.sid_thread_groups(&scope).count(), 2);
3016
3017 child.thread_group().setsid().expect("setsid failed");
3018 assert_eq!(init_pid.pgid_thread_groups(&scope).count(), 1);
3019 assert_eq!(init_pid.sid_thread_groups(&scope).count(), 1);
3020 assert!(child.pid.is_process_group(&scope));
3021 assert!(child.pid.is_session(&scope));
3022 assert_eq!(child.pid.pgid_thread_groups(&scope).count(), 1);
3023 assert_eq!(child.pid.sid_thread_groups(&scope).count(), 1);
3024
3025 let grandchild = child.clone_task_for_test(0, None);
3029 let child_pid = child.pid.clone();
3030 child.thread_group().kill(ExitStatus::Exit(0), None);
3031 std::mem::drop(child);
3032 {
3033 let mut pids = current_task.kernel().pids.lock();
3034 for zombie in current_task.thread_group().write().zombie_children.drain(..) {
3035 zombie.release(&mut pids);
3036 }
3037 }
3038 assert!(child_pid.get_process().is_none());
3039 assert!(current_task.kernel().pids.get(child_pid.id).is_ok());
3040
3041 grandchild
3042 .thread_group()
3043 .setpgid(&grandchild, &grandchild, &grandchild.pid)
3044 .expect("grandchild setpgid failed");
3045 assert!(!child_pid.is_process_group(&scope));
3046 assert!(child_pid.is_session(&scope));
3047 assert!(current_task.kernel().pids.get(child_pid.id).is_ok());
3048 assert!(grandchild.pid.is_process_group(&scope));
3049
3050 grandchild.thread_group().kill(ExitStatus::Exit(0), None);
3051 std::mem::drop(grandchild);
3052 {
3053 let mut pids = current_task.kernel().pids.lock();
3054 for zombie in current_task.thread_group().write().zombie_children.drain(..) {
3055 zombie.release(&mut pids);
3056 }
3057 }
3058
3059 assert!(!child_pid.is_process_group(&scope));
3060 assert!(!child_pid.is_session(&scope));
3061 assert!(current_task.kernel().pids.get(child_pid.id).is_err());
3062 })
3063 .await;
3064 }
3065
3066 #[::fuchsia::test]
3067 async fn test_orphaned_pgrp_signals_stopped_jobs() {
3068 spawn_kernel_and_run(async |init| {
3069 let parent = init.clone_task_for_test(0, Some(SIGCHLD));
3072 parent.thread_group().setsid().expect("setsid");
3073 let child = parent.clone_task_for_test(0, Some(SIGCHLD));
3074 child.thread_group().setpgid(&child, &child, &child.pid).expect("setpgid");
3075
3076 child.thread_group().set_stopped(StopState::GroupStopped, None, false);
3077 assert_eq!(child.thread_group().load_stopped(), StopState::GroupStopped);
3078 assert!(!child.read().has_signal_pending(SIGHUP));
3079
3080 parent.thread_group().kill(ExitStatus::Exit(0), None);
3081 std::mem::drop(parent);
3082
3083 assert!(child.read().has_signal_pending(SIGHUP));
3084 assert_ne!(child.thread_group().load_stopped(), StopState::GroupStopped);
3085
3086 child.thread_group().kill(ExitStatus::Exit(0), None);
3087 std::mem::drop(child);
3088
3089 let session_leader = init.clone_task_for_test(0, Some(SIGCHLD));
3092 session_leader.thread_group().setsid().expect("setsid");
3093 let middle = session_leader.clone_task_for_test(0, Some(SIGCHLD));
3094 let leaf = middle.clone_task_for_test(0, Some(SIGCHLD));
3095 leaf.thread_group().setpgid(&leaf, &leaf, &leaf.pid).expect("setpgid");
3096
3097 leaf.thread_group().set_stopped(StopState::GroupStopped, None, false);
3098 assert_eq!(leaf.thread_group().load_stopped(), StopState::GroupStopped);
3099 assert!(!leaf.read().has_signal_pending(SIGHUP));
3100
3101 middle.thread_group().setsid().expect("middle setsid");
3102
3103 assert!(leaf.read().has_signal_pending(SIGHUP));
3104 assert_ne!(leaf.thread_group().load_stopped(), StopState::GroupStopped);
3105 })
3106 .await;
3107 }
3108}