Skip to main content

starnix_core/task/
thread_group.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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/// Values used for waiting on the [ThreadGroup] lifecycle wait queue.
79#[repr(u64)]
80pub enum ThreadGroupLifecycleWaitValue {
81    /// Wait for updates to the WaitResults of tasks in the group.
82    ChildStatus,
83    /// Wait for updates to `stopped`.
84    Stopped,
85}
86
87impl Into<u64> for ThreadGroupLifecycleWaitValue {
88    fn into(self) -> u64 {
89        self as u64
90    }
91}
92
93/// Child process that have exited, but the zombie ptrace needs to be consumed
94/// before they can be waited for.
95#[derive(Clone, Debug)]
96pub struct DeferredZombiePTracer {
97    /// Original tracer
98    pub tracer_pid: Pid,
99    /// Tracee tid
100    pub tracee_tid: Pid,
101    /// Tracee pgid
102    pub tracee_pgid: Pid,
103    /// Tracee thread group
104    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
118/// The mutable state of the ThreadGroup.
119pub struct ThreadGroupMutableState {
120    /// The parent thread group.
121    ///
122    /// The value needs to be writable so that it can be re-parent to the correct subreaper if the
123    /// parent ends before the child.
124    pub parent: Option<ThreadGroupParent>,
125
126    /// The signal this process generates on exit.
127    pub exit_signal: Option<Signal>,
128
129    /// The tasks in the thread group.
130    ///
131    /// The references to Task is weak to prevent cycles as Task have a Arc reference to their
132    /// thread group.
133    /// It is still expected that these weak references are always valid, as tasks must unregister
134    /// themselves before they are deleted.
135    tasks: HashSet<TaskPersistentInfo>,
136
137    /// The children of this thread group.
138    ///
139    /// The references to ThreadGroup is weak to prevent cycles as ThreadGroup have a Arc reference
140    /// to their parent.
141    /// It is still expected that these weak references are always valid, as thread groups must unregister
142    /// themselves before they are deleted.
143    pub children: BTreeMap<pid_t, Weak<ThreadGroup>>,
144
145    /// Child tasks that have exited, but not yet been waited for.
146    pub zombie_children: Vec<OwnedRef<ZombieProcess>>,
147
148    /// ptracees of this process that have exited, but not yet been waited for.
149    pub zombie_ptracees: ZombiePtracees,
150
151    /// Child processes that have exited, but the zombie ptrace needs to be consumed
152    /// before they can be waited for.
153    pub deferred_zombie_ptracers: Vec<DeferredZombiePTracer>,
154
155    /// Unified [WaitQueue] for all waited ThreadGroup events.
156    pub lifecycle_waiters: TypedWaitQueue<ThreadGroupLifecycleWaitValue>,
157
158    /// Whether this thread group will inherit from children of dying processes in its descendant
159    /// tree.
160    pub is_child_subreaper: bool,
161
162    /// The IDs used to perform shell job control.
163    pub process_group: Arc<ProcessGroup>,
164
165    pub did_exec: bool,
166
167    /// A signal that indicates whether the process is going to become waitable
168    /// via waitid and waitpid for either WSTOPPED or WCONTINUED, depending on
169    /// the value of `stopped`. If not None, contains the SignalInfo to return.
170    pub last_signal: Option<SignalInfo>,
171
172    /// Whether the `ThreadGroup` is running or not.
173    ///
174    /// For exited thread groups, this contains the exit status.
175    run_state: ThreadGroupRunState,
176
177    /// Time statistics accumulated from the children.
178    pub children_time_stats: TaskTimeStats,
179
180    /// Personality flags set with `sys_personality()`.
181    pub personality: PersonalityFlags,
182
183    /// Thread groups allowed to trace tasks in this this thread group.
184    pub allowed_ptracers: PtraceAllowedPtracers,
185
186    /// Channel to message when this thread group exits.
187    exit_notifier: Option<futures::channel::oneshot::Sender<()>>,
188
189    /// Notifier for name changes.
190    pub notifier: Option<std::sync::mpsc::Sender<MemoryAttributionLifecycleEvent>>,
191}
192
193/// A collection of `Task` objects that roughly correspond to a "process".
194///
195/// Userspace programmers often think about "threads" and "process", but those concepts have no
196/// clear analogs inside the kernel because tasks are typically created using `clone(2)`, which
197/// takes a complex set of flags that describes how much state is shared between the original task
198/// and the new task.
199///
200/// If a new task is created with the `CLONE_THREAD` flag, the new task will be placed in the same
201/// `ThreadGroup` as the original task. Userspace typically uses this flag in conjunction with the
202/// `CLONE_FILES`, `CLONE_VM`, and `CLONE_FS`, which corresponds to the userspace notion of a
203/// "thread". For example, that's how `pthread_create` behaves. In that sense, a `ThreadGroup`
204/// normally corresponds to the set of "threads" in a "process". However, this pattern is purely a
205/// userspace convention, and nothing stops userspace from using `CLONE_THREAD` without
206/// `CLONE_FILES`, for example.
207///
208/// In Starnix, a `ThreadGroup` corresponds to a Zircon process, which means we do not support the
209/// `CLONE_THREAD` flag without the `CLONE_VM` flag. If we run into problems with this limitation,
210/// we might need to revise this correspondence.
211///
212/// Each `Task` in a `ThreadGroup` has the same thread group ID (`tgid`). The task with the same
213/// `pid` as the `tgid` is called the thread group leader.
214///
215/// Thread groups are destroyed when the last task in the group exits.
216pub struct ThreadGroup {
217    /// Weak reference to the `OwnedRef` of this `ThreadGroup`. This allows to retrieve the
218    /// `TempRef` from a raw `ThreadGroup`.
219    pub weak_self: Weak<ThreadGroup>,
220
221    /// The kernel to which this thread group belongs.
222    pub kernel: Arc<Kernel>,
223
224    /// A handle to the underlying Zircon process object.
225    ///
226    /// Currently, we have a 1-to-1 mapping between thread groups and zx::process
227    /// objects. This approach might break down if/when we implement CLONE_VM
228    /// without CLONE_THREAD because that creates a situation where two thread
229    /// groups share an address space. To implement that situation, we might
230    /// need to break the 1-to-1 mapping between thread groups and zx::process
231    /// or teach zx::process to share address spaces.
232    pub process: ZirconProcess,
233
234    /// A handle to the restricted address space for the Zircon process object.
235    pub root_vmar: zx::Vmar,
236
237    /// The lead task of this thread group.
238    ///
239    /// The lead task is typically the initial thread created in the thread group.
240    pub leader: Pid,
241
242    /// The signal actions that are registered for this process.
243    pub signal_actions: Arc<SignalActions>,
244
245    /// The timers for this thread group (from timer_create(), etc.).
246    pub timers: TimerTable,
247
248    /// A mechanism to be notified when this `ThreadGroup` is destroyed.
249    pub drop_notifier: DropNotifier,
250
251    /// Whether the process is currently stopped.
252    ///
253    /// Must only be set when the `mutable_state` write lock is held.
254    stop_state: AtomicStopState,
255
256    /// The mutable state of the ThreadGroup.
257    mutable_state: LockDepRwLock<ThreadGroupMutableState, ThreadGroupMutableStateLock>,
258
259    /// The resource limits for this thread group.  This is outside mutable_state
260    /// to avoid deadlocks where the thread_group lock is held when acquiring
261    /// the task lock, and vice versa.
262    pub limits: LockDepMutex<ResourceLimits, ThreadGroupLimits>,
263
264    /// The next unique identifier for a seccomp filter.  These are required to be
265    /// able to distinguish identical seccomp filters, which are treated differently
266    /// for the purposes of SECCOMP_FILTER_FLAG_TSYNC.  Inherited across clone because
267    /// seccomp filters are also inherited across clone.
268    pub next_seccomp_filter_id: AtomicCounter<u64>,
269
270    /// Tasks ptraced by this process
271    pub ptracees: LockDepMutex<HashSet<TaskPersistentInfo>, ThreadGroupPtraceesLock>,
272
273    /// The signals that are currently pending for this thread group.
274    pub pending_signals: LockDepMutex<QueuedSignals, ThreadGroupPendingSignalsLock>,
275
276    /// Whether or not there are any pending signals available for tasks in this thread group.
277    /// Used to avoid having to acquire the signal state lock in hot paths.
278    pub has_pending_signals: AtomicBool,
279
280    /// The monotonic time at which the thread group started.
281    pub start_time: zx::MonotonicInstant,
282
283    /// Whether to log syscalls at INFO level for this thread group.
284    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
355/// A wrapper around a `Weak<ThreadGroup>` that expects the underlying `Weak` to always be
356/// valid. The wrapper will check this at runtime during creation and upgrade.
357pub 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/// A selector that can match a process. Works as a representation of the pid argument to syscalls
377/// like wait and kill.
378#[derive(Debug, Clone)]
379pub enum ProcessSelector {
380    /// Matches any process at all.
381    Any,
382    /// Matches only the process with the specified pid
383    Pid(Pid),
384    /// Matches all the processes in the given process group
385    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    /// Creates a ThreadGroup for a regular userspace process.
422    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    /// Creates a ThreadGroup for a kernel system task (e.g., kthreadd).
447    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    /// Creates a ThreadGroup suitable for use in tests.
465    ///
466    /// This function performs the minimal setup necessary to produce a valid `ThreadGroup`
467    /// instance. It uses an invalid handle for the root VMAR, sets no parent, and uses
468    /// default signal actions with `SIGCHLD` as the exit signal.
469    ///
470    /// This should only be used in tests where a full process environment is not required.
471    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                // A child process created via fork(2) inherits its parent's
512                // resource limits.  Resource limits are preserved across execve(2).
513                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    /// Causes the thread group to exit.
570    ///
571    /// This marks the thread group as exiting and sends [`SIGKILL`] to its tasks to initiate
572    /// teardown. The thread group will not exist until the last task exits.
573    ///
574    /// If this is being called from a task that is part of the current thread group, the caller
575    /// should pass `current_task`. If ownership issues prevent passing `current_task`, then callers
576    /// should use [`CurrentTask::kill_thread_group()`] instead.
577    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        // Detach from any ptraced zombie tasks.
591        let zombie_notifications = state.zombie_ptracees.detach_all(&mut pids);
592
593        // Interrupt each task. Unlock the group because send_signal will lock the group in order
594        // to call set_stopped.
595        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    /// Remove the task from the children of this ThreadGroup.
628    ///
629    /// It is important that the task is taken as an `Arc`. It ensures the tasks of the
630    /// ThreadGroup are always valid as they are still valid when removed.
631    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            // The task has never been added. The only expected case is that this thread group
639            // is not running.
640            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            // Detach from any ptraced zombie tasks.
657            let zombie_notifications = state.zombie_ptracees.detach_all(&mut pids);
658
659            // Replace PID table entry with a zombie.
660            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            // I have no idea if dropping the lock here is correct, and I don't want to think about
671            // it. If problems do turn up with another thread observing an intermediate state of
672            // this exit operation, the solution is to unify locks. It should be sensible and
673            // possible for there to be a single lock that protects all (or nearly all) of the
674            // data accessed by both exit and wait. In gvisor and linux this is the lock on the
675            // equivalent of the PidTable. This is made more difficult by rust locks being
676            // containers that only lock the data they contain, but see
677            // https://docs.google.com/document/d/1YHrhBqNhU1WcrsYgGAu3JwwlVmFXPlwWHTJLAbwRebY/edit
678            // for an idea.
679            std::mem::drop(state);
680
681            // `disassociate_controlling_terminal` can not be called while holding the
682            // ThreadGroup state lock.
683            session.disassociate_controlling_terminal();
684
685            for notification in zombie_notifications {
686                notification.deliver(&mut pids);
687            }
688
689            // Remove the process from the cgroup2 pid table after TG lock is dropped.
690            // This function will hold the CgroupState lock which should be before the TG lock. See
691            // more in lock_cgroup2_pid_table comments.
692            self.kernel.cgroups.lock_cgroup2_pid_table().remove_process(&self.leader);
693
694            self.detach_ptracees(&mut pids);
695
696            // We will need the immediate parent and the reaper. Once we have them, we can make
697            // sure to take the locks in the right order: parent before child.
698            let parent = self.read().parent.clone();
699            let reaper = self.find_reaper();
700
701            {
702                // Reparent the children.
703                if let Some(reaper) = reaper {
704                    let reaper = reaper.upgrade();
705                    {
706                        let mut reaper_state = reaper.write();
707                        // This allow_subclass is safe because we lock the reaper (an ancestor)
708                        // before locking `self` and its children. Lock ordering follows
709                        // strictly top-down traversal in the process tree, avoiding cycles.
710                        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                                // This allow_subclass is safe because we lock the reaper (an
715                                // ancestor) before locking `self` and its children. Lock ordering
716                                // follows strictly top-down traversal in the process tree, avoiding
717                                // cycles.
718                                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                    // If we don't have a reaper then just drop the zombies.
732                    let mut state = self.write();
733                    for zombie in state.zombie_children.drain(..) {
734                        zombie.release(&mut pids);
735                    }
736                }
737            }
738
739            // Clear the `parent` reference now that children have been re-`parent`ed.
740            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            // TODO: Set the error_code on the Zircon process object. Currently missing a way
773            // to do this in Zircon. Might be easier in the new execution model.
774
775            // Once the last zircon thread stops, the zircon process will also stop executing.
776
777            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    /// Detach from any ptraced tasks, killing the ones that set `PTRACE_O_EXITKILL`.
787    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        // From https://man7.org/linux/man-pages/man2/sigaction.2.html
825        //
826        // > SA_NOCLDWAIT (since Linux 2.6)
827        // >
828        // >     If signum is SIGCHLD, do not transform children into
829        // >     zombies when they terminate.  See also waitpid(2).  This
830        // >     flag is meaningful only when establishing a handler for
831        // >     SIGCHLD, or when setting that signal's disposition to
832        // >     SIG_DFL.
833        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        // Send signals
848        if let Some(exit_signal) = exit_signal {
849            signal_info.signal = exit_signal;
850            state.send_signal(signal_info);
851        }
852    }
853
854    /// Notifies the tracer if appropriate.  Returns Some(zombie) if caller
855    /// needs to notify the parent, None otherwise.  The caller should probably
856    /// invoke parent.do_zombie_notifications(zombie) on the result.
857    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                // The tracer is the parent and has not consumed the
868                // notification.  Detach to clean up ptrace state, then
869                // notify the parent by discarding the notification
870                // generated by the detach and returning Some(zombie).
871                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                // The tracer is not the parent and the tracer has not consumed
877                // the notification.
878                if !state.is_running() {
879                    // The tracer exited concurrently. Notify the parent.
880                    return Some(zombie);
881                }
882
883                // THREAD SAFETY: Release the tracer state lock before acquiring the parent state
884                // lock to respect parent => child lock ordering.
885                drop(state);
886                {
887                    // Tell the parent to expect a notification later.
888                    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                // Tell the tracer that there is a notification pending.
899                // THREAD SAFETY: Checking for concurrent exit with is_running(), releasing the
900                // tracer state lock, then reacquiring the lock introduces a TOCTOU race. This
901                // hazard is safe because exit synchronizes on the PidTable lock, which is held
902                // continuously.
903                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            // The tracer is the parent and has already consumed the parent
910            // notification.  No further action required.
911            parent.write().children.remove(&tracee.tid.id);
912            zombie.release(pids);
913            return None;
914        }
915        // The tracer is not the parent and has already consumed the parent
916        // notification.  Notify the parent.
917        Some(zombie)
918    }
919
920    /// Find the task which will adopt our children after we die.
921    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            // The target process must be either the current process of a child of the current process
966            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 the target process is a child of the current task, it must not have executed one of the exec
976            // function.
977            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                // The target process must not be a session leader and must be in the same session as the current process.
986                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 the process group already exists, join it. Both process groups must be in the
997                // same session.
998                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                    // Create a new process group.
1007                    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            // `disassociate_controlling_terminal` can not be called while holding the
1020            // ThreadGroup state lock.
1021            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            // We don't support setting these timers.
1041            // The gvisor test suite clears ITIMER_PROF as part of its test setup logic, so we support
1042            // clearing these values.
1043            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            // We don't support setting these timers, so we can accurately report that these are not set.
1069            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    /// Check whether the stop state is compatible with `new_stopped`. If it is return it,
1082    /// otherwise, return None.
1083    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    /// Set the stop status of the process.  If you pass |siginfo| of |None|,
1101    /// does not update the signal.  If |finalize_only| is set, will check that
1102    /// the set will be a finalize (Stopping -> Stopped or Stopped -> Stopped)
1103    /// before executing it.
1104    ///
1105    /// Returns the latest stop state after any changes.
1106    pub fn set_stopped(
1107        &self,
1108        new_stopped: StopState,
1109        siginfo: Option<SignalInfo>,
1110        finalize_only: bool,
1111    ) -> StopState {
1112        // Perform an early return check to see if we can avoid taking the lock.
1113        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    /// Ensures |session| is the controlling session inside of |terminal_controller|, and returns a
1121    /// reference to the |TerminalController|.
1122    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        // "When fd does not refer to the controlling terminal of the calling
1142        // process, -1 is returned" - tcgetpgrp(3)
1143        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            // Keep locks to ensure atomicity.
1158            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            // If the calling process is a member of a background group and not ignoring SIGTTOU, a
1170            // SIGTTOU signal is sent to all members of this background process group.
1171            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        // Locks must not be held when sending signals.
1182        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        // Keep locks to ensure atomicity.
1199        let state = self.read();
1200        let process_group = &state.process_group;
1201        let mut terminal_state = terminal.write();
1202
1203        // It might be necessary to lock the existing session, to steal the terminal
1204        // for it. Because of ordering requirement, it must be locked now.
1205        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        // "The calling process must be a session leader and not have a
1222        // controlling terminal already." - tty_ioctl(4)
1223        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 this terminal is already the controlling terminal of a different
1237        // session group, then the ioctl fails with EPERM, unless the caller
1238        // has the CAP_SYS_ADMIN capability and arg equals 1, in which case the
1239        // terminal is stolen, and all processes that had it as controlling
1240        // terminal lose it." - tty_ioctl(4)
1241        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            // Steal the TTY away. Unlike TIOCNOTTY, don't send signals.
1250            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            // Keep locks to ensure atomicity.
1271            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            // tty must be the controlling terminal.
1277            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            // "If the process was session leader, then send SIGHUP and SIGCONT to the foreground
1287            // process group and all processes in the current session lose their controlling terminal."
1288            // - tty_ioctl(4)
1289
1290            // Remove tty as the controlling tty for each process in the session, then
1291            // send them SIGHUP and SIGCONT.
1292
1293            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    /// Adjusts the rlimits of the ThreadGroup to which `target_task` belongs to.
1320    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            // `process` must be valid for all tasks, except `kthreads`. In that case get the
1344            // stats from starnix process.
1345            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            // TODO(https://fxbug.dev/42078242): How can we calculate system time?
1359            system_time: zx::MonotonicDuration::default(),
1360        }
1361    }
1362
1363    /// For each task traced by this thread_group that matches the given
1364    /// selector, acquire its TaskMutableState and ptracees lock and execute the
1365    /// given function.
1366    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    /// Returns a tracee whose state has changed, so that waitpid can report on
1386    /// it. If this returns a value, and the pid is being traced, the tracer
1387    /// thread is deemed to have seen the tracee ptrace-stop for the purposes of
1388    /// PTRACE_LISTEN.
1389    pub fn get_waitable_ptracee(
1390        &self,
1391        selector: &ProcessSelector,
1392        options: &WaitingOptions,
1393        pids: &mut PidTableGuard<'_>,
1394    ) -> Option<WaitResult> {
1395        // This checks to see if the target is a zombie ptracee.
1396        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        // This checks to see if the target is a running ptracee.
1423        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                // We've identified a potential target.  Need to return either
1439                // the process's information (if we are in group-stop) or the
1440                // thread's information (if we are in a different stop).
1441
1442                // The shared information:
1443                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                    // The information for processes, if we were in group stop.
1461                    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                    // Tasks that are ptrace'd always get stop notifications.
1473                    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                        // Clear the wait status of the ptrace, because we're
1513                        // using the tg status instead.
1514                        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                        // The information for the task, if we were in a non-group stop.
1522                        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    /// Attempts to send an unchecked signal to this thread group.
1574    ///
1575    /// - `current_task`: The task that is sending the signal.
1576    /// - `unchecked_signal`: The signal that is to be sent. Unchecked, since `0` is a sentinel value
1577    /// where rights are to be checked but no signal is actually sent.
1578    ///
1579    /// # Returns
1580    /// Returns Ok(()) if the signal was sent, or the permission checks passed with a 0 signal, otherwise
1581    /// the error that was encountered.
1582    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    /// Sends a signal to this thread_group without performing any access checks.
1604    ///
1605    /// # Safety
1606    /// This is unsafe, because it should only be called by tools and tests.
1607    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    /// Attempts to send an unchecked signal to this thread group, with info read from
1627    /// `siginfo_ref`.
1628    ///
1629    /// - `current_task`: The task that is sending the signal.
1630    /// - `unchecked_signal`: The signal that is to be sent. Unchecked, since `0` is a sentinel value
1631    /// where rights are to be checked but no signal is actually sent.
1632    /// - `siginfo_ref`: The siginfo that will be enqueued.
1633    /// - `options`: Options for how to convert the siginfo into a signal info.
1634    ///
1635    /// # Returns
1636    /// Returns Ok(()) if the signal was sent, or the permission checks passed with a 0 signal, otherwise
1637    /// the error that was encountered.
1638    #[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    /// Checks whether or not `current_task` can signal this thread group with `unchecked_signal`.
1667    ///
1668    /// Returns:
1669    ///   - `Ok(Some(Signal))` if the signal passed checks and should be sent.
1670    ///   - `Ok(None)` if the signal passed checks, but should not be sent. This is used by
1671    ///   userspace for permission checks.
1672    ///   - `Err(_)` if the permission checks failed.
1673    fn check_signal_access(
1674        &self,
1675        current_task: &CurrentTask,
1676        unchecked_signal: UncheckedSignal,
1677    ) -> Result<Option<Signal>, Errno> {
1678        // Pick an arbitrary task in thread_group to check permissions.
1679        //
1680        // Tasks can technically have different credentials, but in practice they are kept in sync.
1681        let Some(target_task) = self.read().get_signalable_task() else {
1682            // If there are no signalable tasks in the thread group, all tasks have exited and the
1683            // process is terminating or a zombie. A signal sent to a terminating or zombie process
1684            // is ignored, matching the behavior for Zombie processes in sys_kill.
1685            return Ok(None);
1686        };
1687        current_task.can_signal(&target_task, unchecked_signal)?;
1688
1689        // 0 is a sentinel value used to do permission checks.
1690        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    /// Drive this `ThreadGroup` to exit, allowing it time to handle SIGTERM before sending SIGKILL.
1727    ///
1728    /// Returns once `ThreadGroup::exit()` has completed.
1729    ///
1730    /// Must be called from the system task.
1731    pub async fn shut_down(this: Weak<Self>) {
1732        const SHUTDOWN_SIGNAL_HANDLING_TIMEOUT: zx::MonotonicDuration =
1733            zx::MonotonicDuration::from_seconds(1);
1734
1735        // Prepare for shutting down the thread group.
1736        let (tg_name, mut on_exited) = {
1737            // Nest this upgraded access so upgraded references aren't held across await-points.
1738            let Some(this) = this.upgrade() else {
1739                return;
1740            };
1741
1742            let mut state = this.write();
1743            if state.is_exited() {
1744                // Do not set an exit notifier on an exited thread group. It will never be notified.
1745                return;
1746            }
1747
1748            // Register a channel to be notified when exit() is complete.
1749            let (on_exited_send, on_exited) = futures::channel::oneshot::channel();
1750            state.exit_notifier = Some(on_exited_send);
1751
1752            // We want to be able to log about this thread group without upgrading the `Weak`.
1753            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        // Give thread groups some time to handle SIGTERM, proceeding early if they exit
1762        let timeout = fuchsia_async::Timer::new(SHUTDOWN_SIGNAL_HANDLING_TIMEOUT);
1763        futures::pin_mut!(timeout);
1764
1765        // Use select_biased instead of on_timeout() so that we can await on on_exited later
1766        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        // It doesn't matter whether ThreadGroup::exit() was called or the process exited with
1776        // a return code and dropped the sender end of the channel.
1777        on_exited.await.ok();
1778        log_debug!(tg:% = tg_name; "thread group shutdown complete");
1779    }
1780
1781    /// Returns the KOID of the process for this thread group.
1782    /// This method should be used to when mapping 32 bit linux process ids to KOIDs
1783    /// to avoid breaking the encapsulation of the zx::process within the ThreadGroup.
1784    /// This encapsulation is important since the relationship between the ThreadGroup
1785    /// and the Process may change over time. See [ThreadGroup::process] for more details.
1786    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    /// Changes the process group of the thread group.
1866    ///
1867    /// Returns a `SessionDisassociation`, which the caller must use to explicitly
1868    /// disassociate the controlling terminal if the thread group was previously a session
1869    /// leader.
1870    /// This must be done after the ThreadGroup state lock is released to avoid lock order
1871    /// violations.
1872    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    /// Removes the thread group from its current process group.
1887    ///
1888    /// Returns a `SessionDisassociation`, which the caller must use to explicitly
1889    /// disassociate the controlling terminal if the thread group was previously a session
1890    /// leader.
1891    /// This must be done after the ThreadGroup state lock is released to avoid lock order
1892    /// violations.
1893    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    /// Reaps the given zombie, making its PID available for reuse.
1903    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    /// Indicates whether the thread group is waitable via waitid and waitpid for
1909    /// either WSTOPPED or WCONTINUED.
1910    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        // We look for the last zombie in the vector that matches pid selector and waiting options
1922        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        // The children whose pid matches the pid selector queried.
1952        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                // This allow_subclass is safe because the lock is being acquired
1957                // in a strictly top-down traversal of the ThreadGroup tree (from parent
1958                // to child), so no lock ordering cycles can be formed.
1959                let _token = allow_subclass();
1960                &child.read().process_group.leader == pgid
1961            }
1962        };
1963
1964        // The children whose exit signal matches the waiting options queried.
1965        let filter_children_by_waiting_options = |child: &ThreadGroup| {
1966            if options.wait_for_all {
1967                return true;
1968            }
1969            // This allow_subclass is safe because the lock is being acquired
1970            // in a strictly top-down traversal of the ThreadGroup tree (from parent
1971            // to child), so no lock ordering cycles can be formed.
1972            let _token = allow_subclass();
1973            Self::is_correct_exit_signal(options.wait_for_clone, child.read().exit_signal)
1974        };
1975
1976        // If wait_for_exited flag is disabled or no exited children were found we look for running
1977        // children.
1978        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            // There still might be a process that ptrace hasn't looked at yet.
1987            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            // This allow_subclass is safe because the lock is being acquired
1999            // in a strictly top-down traversal of the ThreadGroup tree (from parent
2000            // to child), so no lock ordering cycles can be formed.
2001            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                        // This overrides the stop/continue choice.
2014                        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    /// Returns any waitable child matching the given `selector` and `options`. Returns None if no
2050    /// child matching the selector is waitable. Returns ECHILD if no child matches the selector at
2051    /// all.
2052    ///
2053    /// Will remove the waitable status from the child depending on `options`.
2054    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    /// Returns a running task in the current thread group.
2075    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    /// Returns a task representative of the [`ThreadGroup`] for signal access checks.
2083    ///
2084    /// Prefers a running task, but falls back to the first available non-running task.
2085    /// Returns `None` if the task list is empty or no tasks can be upgraded.
2086    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    /// Set the stop status of the process.  If you pass |siginfo| of |None|,
2109    /// does not update the signal.  If |finalize_only| is set, will check that
2110    /// the set will be a finalize (Stopping -> Stopped or Stopped -> Stopped)
2111    /// before executing it.
2112    ///
2113    /// Returns the latest stop state after any changes.
2114    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        // Thread groups don't transition to group stop if they are waking, because waking
2125        // means something told it to wake up (like a SIGCONT) but hasn't finished yet.
2126        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        // TODO(https://g-issues.fuchsia.dev/issues/306438676): When thread
2133        // group can be stopped inside user code, tasks/thread groups will
2134        // need to be either restarted or stopped here.
2135        self.store_stopped(new_stopped);
2136        if let Some(signal) = &siginfo {
2137            // We don't want waiters to think the process was unstopped
2138            // because of a sigkill.  They will get woken when the
2139            // process dies.
2140            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        // Drop the lock before locking the parent.
2151        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        // We don't actually use the guard but we require it to enforce that the
2165        // caller holds the thread group's mutable state lock (identified by
2166        // mutable access to the thread group's mutable state).
2167
2168        self.base.stop_state.store(state, Ordering::Relaxed)
2169    }
2170
2171    /// Sends the signal `signal_info` to this thread group.
2172    #[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        // Like `send_signal_prio` does for a single task, discard an ignored signal instead of
2180        // queueing it: no task would ever act on it, but it would still make interruptible syscalls
2181        // fail with EINTR. It must still be queued when a task blocks it with its current or its
2182        // saved mask, as it can be accepted later (see the `SigtimedwaitTest.IgnoredUnmaskedSignal`
2183        // gvisor test), or when a task is ptraced, for the signal-delivery-stop.
2184        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        // Set state to waking before interrupting any tasks.
2203        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                    // Interrupt every task if the action is fatal (such as SIGKILL),
2243                    // or only one task for catchable signals.
2244                    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(&current_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(&current_task, &current_task, &current_task.pid),
2308                error!(ESRCH)
2309            );
2310            assert_eq!(
2311                current_task.thread_group().setpgid(
2312                    &current_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                    &current_task,
2321                    &current_task,
2322                    &current_task.pid
2323                ),
2324                error!(EPERM)
2325            );
2326            assert_eq!(
2327                current_task.thread_group().setpgid(
2328                    &current_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(&current_task, &child_task1, &child_task2.pid),
2336                error!(EPERM)
2337            );
2338            assert_eq!(
2339                current_task.thread_group().setpgid(
2340                    &current_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(&current_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(&current_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(&current_task, &child_task3, &child_task3.pid),
2368                Ok(())
2369            );
2370            // Move child_task1 to child_task3's process group.
2371            assert_eq!(
2372                current_task.thread_group().setpgid(&current_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            // Rejoin child_task1's original process group (which still contains child_task2).
2378            assert_eq!(
2379                child_task1.thread_group().setpgid(&current_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(&current_task, child_task1.pid.id, -1),
2389                error!(EINVAL)
2390            );
2391            assert_eq!(
2392                crate::task::syscalls::sys_setpgid(&current_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            // Task3 parent should be current_task.
2412            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            // Take strong references to the ThreadGroups.
2424            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            // Exit `task2` first, so that when `task1` exits, it will not be reparented to init.
2431            tg2.kill(ExitStatus::Exit(0), None);
2432            std::mem::drop(task2);
2433
2434            // Exit `task1`, and drop the task and ThreadGroup.
2435            tg1.kill(ExitStatus::Exit(0), None);
2436            std::mem::drop(task1);
2437            std::mem::drop(tg1);
2438
2439            // It should still be valid to call `get_ppid()` on `tg2`, though is parent ThreadGroup
2440            // no longer exists.
2441            let _ = tg2.read().get_ppid();
2442        })
2443        .await;
2444    }
2445}