Skip to main content

starnix_core/task/
current_task.rs

1// Copyright 2023 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::arch::task::handle_hardware_exception;
6use crate::execution::{CreateDuringShutdown, TaskInfo, create_zircon_process};
7use crate::mm::{
8    DumpPolicy, MappingAccess, MemoryAccessor, MemoryAccessorExt, MemoryManager, TaskMemoryAccessor,
9};
10use crate::ptrace::{PtraceEvent, PtraceEventData, PtraceOptions, StopState};
11use crate::security;
12use crate::signals::{SignalInfo, send_standard_signal};
13use crate::task::loader::{
14    ResolvedProgram, load_executable, resolve_elf_interpreter, resolve_executable,
15};
16use crate::task::{
17    CurrentTaskCredentialsWriteGuard, ExitStatus, PageFaultExceptionReport, RobustListHeadPtr,
18    RunState, SeccompFilter, SeccompFilterContainer, SeccompState, SeccompStateValue, Task,
19    TaskFlags, TaskRunningState, ThreadState, Waiter,
20};
21use crate::vfs::{
22    AccessCheck, CreationStatus, DirEntry, DirectoryMode, FdFlags, FdNumber, FdTable, FileHandle,
23    FileMapping, FileWriteGuardMode, FsContext, FsStr, LookupContext, LookupVec,
24    MAX_SYMLINK_FOLLOWS, NamespaceNode, OpenAccessCheck, ResolveBase, SymlinkMode, SymlinkTarget,
25    new_pidfd,
26};
27use futures::FutureExt;
28use linux_uapi::CLONE_PIDFD;
29use starnix_logging::{CATEGORY_STARNIX, log_error, log_warn, track_file_not_found, track_stub};
30use starnix_registers::{HeapRegs, RegisterStorageEnum};
31use starnix_sync::{EventWaitGuard, UninterruptibleLock, WakeReason, assert_lock_level};
32use starnix_syscalls::SyscallResult;
33use starnix_syscalls::decls::Syscall;
34use starnix_task_command::TaskCommand;
35use starnix_types::futex_address::FutexAddress;
36use starnix_types::ownership::{Releasable, release_on_error};
37use starnix_types::user_buffer::UserBuffer;
38use starnix_uapi::auth::{
39    CAP_KILL, CAP_SYS_ADMIN, Credentials, FsCred, PTRACE_MODE_FSCREDS, PTRACE_MODE_REALCREDS,
40    PtraceAccessMode,
41};
42use starnix_uapi::device_id::DeviceId;
43use starnix_uapi::errors::Errno;
44use starnix_uapi::file_mode::{Access, FileMode};
45use starnix_uapi::open_flags::OpenFlags;
46use starnix_uapi::signals::{
47    SIGCHLD, SIGCONT, SIGILL, SIGKILL, SIGSEGV, SIGSYS, SIGTRAP, SigSet, Signal, UncheckedSignal,
48};
49use starnix_uapi::user_address::{ArchSpecific, UserAddress, UserRef};
50use starnix_uapi::vfs::ResolveFlags;
51use starnix_uapi::{
52    CLONE_CHILD_CLEARTID, CLONE_CHILD_SETTID, CLONE_CLEAR_SIGHAND, CLONE_FILES, CLONE_FS,
53    CLONE_INTO_CGROUP, CLONE_NEWUTS, CLONE_PARENT, CLONE_PARENT_SETTID, CLONE_PTRACE, CLONE_SETTLS,
54    CLONE_SIGHAND, CLONE_SYSVSEM, CLONE_THREAD, CLONE_VFORK, CLONE_VM, FUTEX_OWNER_DIED,
55    FUTEX_TID_MASK, ROBUST_LIST_LIMIT, SECCOMP_FILTER_FLAG_LOG, SECCOMP_FILTER_FLAG_NEW_LISTENER,
56    SECCOMP_FILTER_FLAG_TSYNC, SECCOMP_FILTER_FLAG_TSYNC_ESRCH, errno, error, pid_t, sock_filter,
57    ucred,
58};
59use std::cell::{Ref, RefCell};
60use std::collections::VecDeque;
61use std::ffi::CString;
62use std::fmt;
63use std::marker::PhantomData;
64use std::mem::MaybeUninit;
65use std::sync::{Arc, Weak};
66use zx::sys::zx_restricted_state_t;
67
68use super::ThreadGroupLifecycleWaitValue;
69
70pub struct TaskBuilder {
71    /// The underlying task object.
72    pub task: Arc<Task>,
73
74    pub thread_state: ThreadState<HeapRegs>,
75}
76
77impl TaskBuilder {
78    pub fn new(task: Arc<Task>) -> Self {
79        Self { task, thread_state: Default::default() }
80    }
81
82    #[inline(always)]
83    pub fn release(self, _context: ()) {
84        Releasable::release(self, ());
85    }
86}
87
88impl From<TaskBuilder> for CurrentTask {
89    fn from(builder: TaskBuilder) -> Self {
90        Self::new(builder.task, builder.thread_state.into())
91    }
92}
93
94impl Releasable for TaskBuilder {
95    type Context<'a> = ();
96
97    fn release<'a>(self, _context: Self::Context<'a>) {
98        // Build a temporary CurrentTask to run release actions that require ThreadState.
99        let current_task = CurrentTask::new(self.task, self.thread_state.into());
100        current_task.exit();
101    }
102}
103
104impl std::ops::Deref for TaskBuilder {
105    type Target = Task;
106    fn deref(&self) -> &Self::Target {
107        &self.task
108    }
109}
110
111/// The task object associated with the currently executing thread.
112///
113/// We often pass the `CurrentTask` as the first argument to functions if those functions need to
114/// know contextual information about the thread on which they are running. For example, we often
115/// use the `CurrentTask` to perform access checks, which ensures that the caller is authorized to
116/// perform the requested operation.
117///
118/// The `CurrentTask` also has state that can be referenced only on the currently executing thread,
119/// such as the register state for that thread. Syscalls are given a mutable references to the
120/// `CurrentTask`, which lets them manipulate this state.
121///
122/// See also `Task` for more information about tasks.
123pub struct CurrentTask {
124    /// The underlying task object.
125    pub task: Arc<Task>,
126
127    pub thread_state: ThreadState<RegisterStorageEnum>,
128
129    /// The cached running state of the task.
130    ///
131    /// Extracting `TaskRunningState` from a generic `Task` requires acquiring an RCU read lock.
132    /// While this is a relatively inexpensive operation, it is unnecessary in most cases because
133    /// `CurrentTask` always corresponds to a running `Task`, and every running `Task` has a
134    /// `TaskRunningState`. As such, the `CurrentTask` can safely cache a reference to its
135    /// `TaskRunningState`. This reference will only be invalidated during task exit.
136    pub running_state: Option<Arc<TaskRunningState>>,
137
138    /// The cached file descriptor table of the task.
139    ///
140    /// Extracting `FdTable` from a generic `Task` is a heavy operation with multiple levels of
141    /// synchronization and reference counting. However, because `CurrentTask` always corresponds to
142    /// a running `Task`, and every running `Task` has an `FdTable`, the `CurrentTask` can safely
143    /// cache a reference to its `FdTable`.
144    pub files: RefCell<Option<Arc<FdTable>>>,
145
146    /// The cached memory manager of the task.
147    pub mm: Option<Arc<MemoryManager>>,
148
149    /// The current subjective credentials of the task.
150    // TODO(https://fxbug.dev/433548348): Avoid interior mutability here by passing a
151    // &mut CurrentTask around instead of &CurrentTask.
152    pub current_creds: RefCell<CurrentCreds>,
153
154    pub security_state: security::CurrentTaskState,
155
156    /// Makes CurrentTask neither Sync not Send.
157    _local_marker: PhantomData<*mut u8>,
158}
159
160/// Represents the current state of the task's subjective credentials.
161pub enum CurrentCreds {
162    /// The task does not have overridden credentials, the subjective creds are identical to the
163    /// objective creds stored in the Task. Since credentials are often accessed from the current
164    /// task, we hold a reference here that does not necessitate going through the RCU machinery to
165    /// read.
166    Cached(Arc<Credentials>),
167    /// The task has overridden subjective credentials.
168    Overridden(Arc<Credentials>),
169}
170
171impl CurrentCreds {
172    fn creds(&self) -> &Arc<Credentials> {
173        match self {
174            CurrentCreds::Cached(creds) => creds,
175            CurrentCreds::Overridden(creds) => creds,
176        }
177    }
178}
179
180impl Releasable for CurrentTask {
181    type Context<'a> = ();
182
183    fn release<'a>(self, _context: Self::Context<'a>) {
184        self.exit();
185    }
186}
187
188impl std::ops::Deref for CurrentTask {
189    type Target = Task;
190    fn deref(&self) -> &Self::Target {
191        &self.task
192    }
193}
194
195impl fmt::Debug for CurrentTask {
196    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197        self.task.fmt(f)
198    }
199}
200
201impl CurrentTask {
202    pub fn new(task: Arc<Task>, thread_state: ThreadState<RegisterStorageEnum>) -> Self {
203        let current_creds = RefCell::new(CurrentCreds::Cached(task.clone_creds()));
204        let running_state = task.running_state().expect("CurrentTask must have TaskRunningState");
205        let files = running_state.files().expect("CurrentTask must have FdTable");
206        let mm = running_state.mm.upgrade();
207        Self {
208            task,
209            thread_state,
210            running_state: Some(running_state),
211            files: RefCell::new(Some(files)),
212            mm,
213            current_creds,
214            security_state: Default::default(),
215            _local_marker: Default::default(),
216        }
217    }
218
219    /// Exit the task by dropping its running state.
220    pub fn exit(mut self) {
221        // When this method returns, the following invariants must be met:
222        // 1. No new references to running `Task` state must be obtainable.
223        // 2. All externally-visible `Task` state must reflect that the `Task` has exited.
224        // 3. All observers of `Task` exit events must be notified.
225
226        self.notify_robust_list();
227        let _ignored = self.clear_child_tid_if_needed();
228
229        self.signal_vfork();
230
231        // Release references to resources specific to the running task before triggering its
232        // delayed releaser for the last time. This schedules any RCU-guarded references retained
233        // solely by this task for RCU reclamation. Triggering the delayed releaser runs RCU
234        // callbacks, ensuring that:
235        //
236        // 1. Any delayed release actions registered by the resource being dropped during
237        //    reclamation are applied during the final delayed releaser trigger.
238        // 2. Any other drop side-effects happen before the thread group sends zombie notifications.
239        //
240        // Specifically, the following resources require explicit release:
241        //
242        // 1. `running_state`: Transitively releases `proc_pid_directory_cache`
243        // 2. `files`: Drops `FileHandle` to close open file descriptors
244        // 3. `mm`: Drops `FsNodeHandle` to remove memory-mapped filesystem nodes and drops
245        //    `FileWriteGuard` for executable mappings
246        // 4. `fs`: Drops `MountClientMarker` to allow unmounting and drops `FsNodeHandle` to remove
247        //    namespace filesystem nodes
248        // 5. `proc_pid_directory_cache`: Drops `FsNodeHandle` to remove /proc/<pid> nodes
249        //
250        // `files`, `mm` and `fs` are released explicitly here rather than by dropping
251        // `running_state`. Other threads may transiently hold a strong reference to
252        // `TaskRunningState` (e.g. `Task::interrupt()`), and if such a thread ends up dropping the
253        // last reference, it runs the destructors of everything still owned by the
254        // `TaskRunningState`, possibly while holding locks. Dropping `fs` in particular may tear
255        // down an entire mount namespace, which acquires `DirEntry` locks, so it must happen here
256        // on the exiting thread, where no locks are held. `proc_pid_directory_cache` only holds an
257        // `FsNodeHandle`, whose release is already deferred to the delayed releaser.
258
259        if let Some(ref running_state) = self.running_state {
260            *running_state.files.lock() = None;
261            running_state.mm.update(None);
262            running_state.fs.update(&self, None);
263        }
264        self.running_state = None;
265
266        *self.files.borrow_mut() = None;
267        self.mm = None;
268        self.task.running_state.update(None);
269
270        self.trigger_delayed_releaser();
271
272        // We remove from the thread group here because the Weak in the pid
273        // table to this task must be valid until this task is removed from the
274        // thread group, and the code below will invalidate it.
275        // Moreover, this requires an Arc of the task to ensure the tasks of
276        // the thread group are always valid.
277        self.task.thread_group().remove(self.kernel().pids.lock(), &self.task);
278
279        self.ptrace_disconnect();
280    }
281
282    /// Returns the [`TaskRunningState`] for the [`Task`].
283    ///
284    /// # Panics
285    ///
286    /// Calling `running_state()` on a [`CurrentTask`] for which the [`Task`] has no running state
287    /// (i.e. exited tasks) panics. However, such tasks should not have a [`CurrentTask`].
288    ///
289    /// This is primarily a risk in delayed release actions, which receive `&CurrentTask` when its
290    /// delayed releaser is triggered for the final time. At that point the task is mid-exit and its
291    /// [`TaskRunningState`] has been dropped. As such, delayed releases must not use the following
292    /// accessors:
293    ///
294    /// - [`Self::running_state()`]
295    /// - [`Self::files()`]
296    /// - [`Self::fs()`]
297    ///
298    /// If access to [`TaskRunningState`] is required in a delayed release action, use
299    /// [`Task::running_state()`] or an equivalent fallible accessor.
300    #[track_caller]
301    pub fn running_state(&self) -> &Arc<TaskRunningState> {
302        self.running_state.as_ref().expect("CurrentTask must have TaskRunningState")
303    }
304
305    /// Returns the [`FdTable`] for the [`Task`].
306    ///
307    /// # Panics
308    ///
309    /// Calling `files()` on a [`CurrentTask`] for which the [`Task`] has no file descriptor table
310    /// (i.e. exited tasks) panics. However, such tasks should not have a `CurrentTask`.
311    #[track_caller]
312    pub fn files(&self) -> Arc<FdTable> {
313        self.files.borrow().as_ref().expect("CurrentTask must have FdTable").clone()
314    }
315
316    /// Looks up a file descriptor in the cached [`FdTable`] without cloning the [`Arc<FdTable>`].
317    #[inline]
318    pub fn get_file(&self, fd: FdNumber) -> Result<FileHandle, Errno> {
319        self.files.borrow().as_ref().expect("CurrentTask must have FdTable").get(fd)
320    }
321
322    /// Looks up a file descriptor (allowing `O_PATH`) in the cached [`FdTable`] without cloning
323    /// the [`Arc<FdTable>`].
324    #[inline]
325    pub fn get_file_allowing_opath(&self, fd: FdNumber) -> Result<FileHandle, Errno> {
326        self.files.borrow().as_ref().expect("CurrentTask must have FdTable").get_allowing_opath(fd)
327    }
328
329    /// Returns the cached [`MemoryManager`] for the [`CurrentTask`], avoiding RCU read-scope and
330    /// [`Arc`] reference-count traffic on every user memory access.
331    #[inline]
332    pub fn mm(&self) -> Result<&Arc<MemoryManager>, Errno> {
333        self.mm.as_ref().ok_or_else(|| errno!(EINVAL))
334    }
335
336    pub fn set_mm_for_test(&mut self, mm: Arc<MemoryManager>) {
337        self.running_state().mm.update(Some(mm.clone()));
338        self.mm = Some(mm);
339    }
340
341    /// Returns the [`FsContext`] for the [`Task`].
342    ///
343    /// # Panics
344    ///
345    /// Calling `fs()` on a [`CurrentTask`] for which the [`Task`] has no file system context
346    /// (i.e. exited tasks) panics. However, such tasks should not have a `CurrentTask`.
347    #[track_caller]
348    pub fn fs(&self) -> Arc<FsContext> {
349        self.running_state().fs().expect("CurrentTask must have FsContext")
350    }
351
352    /// Returns whether another running task shares this task's [`FsContext`].
353    pub fn has_shared_fs(&self) -> bool {
354        self.fs().is_shared()
355    }
356
357    /// Replaces this task's [`FsContext`] with an unshared copy.
358    pub fn unshare_fs(&self) {
359        let new_fs = self.fs().fork();
360        self.running_state().fs.update(self, new_fs);
361    }
362
363    /// Returns the current subjective credentials of the task.
364    ///
365    /// The subjective credentials are the credentials that are used to check permissions for
366    /// actions performed by the task.
367    pub fn current_creds(&self) -> Ref<'_, Arc<Credentials>> {
368        Ref::map(self.current_creds.borrow(), CurrentCreds::creds)
369    }
370
371    pub fn current_fscred(&self) -> FsCred {
372        self.current_creds().as_fscred()
373    }
374
375    pub fn current_ucred(&self) -> ucred {
376        let creds = self.current_creds();
377        ucred { pid: self.get_pid(), uid: creds.uid, gid: creds.gid }
378    }
379
380    /// Save the current creds and security state, alter them by calling `alter_creds`, then call
381    /// `callback`.
382    /// The creds and security state will be restored to their original values at the end of the
383    /// call. Only the "subjective" state of the CurrentTask, accessed with `current_creds()` and
384    ///  used to check permissions for actions performed by the task, is altered. The "objective"
385    ///  state, accessed through `Task::real_creds()` by other tasks and used to check permissions
386    /// for actions performed on the task, is not altered, and changes to the credentials are not
387    /// externally visible.
388    pub async fn override_creds_async<R>(
389        &self,
390        new_creds: Arc<Credentials>,
391        callback: impl AsyncFnOnce() -> R,
392    ) -> R {
393        let saved = self.current_creds.replace(CurrentCreds::Overridden(new_creds));
394        let result = callback().await;
395        self.current_creds.replace(saved);
396        result
397    }
398
399    /// Save the current creds and security state, alter them by calling `alter_creds`, then call
400    /// `callback`.
401    /// The creds and security state will be restored to their original values at the end of the
402    /// call. Only the "subjective" state of the CurrentTask, accessed with `current_creds()` and
403    ///  used to check permissions for actions performed by the task, is altered. The "objective"
404    ///  state, accessed through `Task::real_creds()` by other tasks and used to check permissions
405    /// for actions performed on the task, is not altered, and changes to the credentials are not
406    /// externally visible.
407    pub fn override_creds<R>(
408        &self,
409        new_creds: Arc<Credentials>,
410        callback: impl FnOnce() -> R,
411    ) -> R {
412        self.override_creds_async(new_creds, async move || callback())
413            .now_or_never()
414            .expect("Future should be ready")
415    }
416
417    pub fn has_overridden_creds(&self) -> bool {
418        matches!(*self.current_creds.borrow(), CurrentCreds::Overridden(_))
419    }
420
421    pub fn trigger_delayed_releaser(&self) {
422        self.kernel().delayed_releaser.apply(self);
423    }
424
425    pub fn weak_task(&self) -> Weak<Task> {
426        Arc::downgrade(&self.task)
427    }
428
429    /// Locks the `CurrentTask`'s credentials for writing, allowing readers to coordinate by using
430    /// `Task::lock_creds()` where necessary.  e.g. This is used to avoid ptrace attachment racing
431    /// with critical security checks affecting the task's `Credentials` during `exec()`.
432    pub fn write_creds(&self) -> CurrentTaskCredentialsWriteGuard {
433        assert!(!self.has_overridden_creds());
434        self.persistent_info.write_current_task_creds()
435    }
436
437    /// Change the current and real creds of the task. This is invalid to call while temporary
438    /// credentials are present.
439    pub fn set_creds(&self, creds: Credentials) {
440        let prev = self.current_creds();
441        let effective_or_fs_ugid_changed = creds.euid != prev.euid
442            || creds.egid != prev.egid
443            || creds.fsuid != prev.fsuid
444            || creds.fsgid != prev.fsgid;
445        std::mem::drop(prev);
446
447        if effective_or_fs_ugid_changed {
448            // From <https://man7.org/linux/man-pages/man2/PR_SET_PDEATHSIG.2const.html>:
449            //
450            //   The parent-death signal setting is also cleared upon changes
451            //   to any of the following thread credentials: effective user ID,
452            //   effective group ID, filesystem user ID, or filesystem group ID.
453            self.thread_group().write().set_parent_death_signal(None);
454
455            // From <https://man7.org/linux/man-pages/man2/PR_SET_DUMPABLE.2const.html>:
456            //
457            //   Normally, the "dumpable" attribute is set to 1. However, it is
458            //   reset to the current value contained in the file
459            //   /proc/sys/fs/suid_dumpable (which by default has the value 0),
460            //   in the following circumstances:
461            //
462            //   - The process's effective user or group ID is changed.
463            //   - The process's filesystem user or group ID is changed (see
464            //     credentials(7)).
465            //
466            // Reset `dumpable` before publishing the new credentials so
467            // concurrent `check_ptrace_access_mode` callers cannot see
468            // downgraded credentials while the address space is still marked
469            // dumpable.
470            if let Ok(mm) = self.mm() {
471                mm.dumpable.store(self.kernel().system_limits.suid_dumpable.load());
472            }
473        }
474
475        let creds = Arc::new(creds);
476        self.write_creds().update(self, creds);
477    }
478
479    #[inline(always)]
480    pub fn release(self, _context: ()) {
481        Releasable::release(self, ());
482    }
483
484    pub fn set_syscall_restart_func<R: Into<SyscallResult>>(
485        &mut self,
486        f: impl FnOnce(&mut CurrentTask) -> Result<R, Errno> + Send + Sync + 'static,
487    ) {
488        self.thread_state.syscall_restart_func =
489            Some(Box::new(|current_task| Ok(f(current_task)?.into())));
490    }
491
492    pub fn add_file(&self, file: FileHandle, flags: FdFlags) -> Result<FdNumber, Errno> {
493        self.files().add(self, file, flags)
494    }
495
496    /// Sets the task's signal mask to `signal_mask` and runs `wait_function`.
497    ///
498    /// Signals are dequeued prior to the original signal mask being restored. This is done by the
499    /// signal machinery in the syscall dispatch loop.
500    ///
501    /// The returned result is the result returned from the wait function.
502    pub fn wait_with_temporary_mask<F, T>(
503        &mut self,
504        signal_mask: SigSet,
505        wait_function: F,
506    ) -> Result<T, Errno>
507    where
508        F: FnOnce(&CurrentTask) -> Result<T, Errno>,
509    {
510        self.write().set_temporary_signal_mask(signal_mask);
511        wait_function(self)
512    }
513
514    /// If waking, promotes from waking to awake.  If not waking, make waiter async
515    /// wait until woken.  Returns true if woken.
516    pub fn wake_or_wait_until_unstopped_async(&self, waiter: &Waiter) -> bool {
517        let group_state = self.thread_group().read();
518        let mut task_state = self.write();
519
520        // Wake up if
521        //   a) we should wake up, meaning:
522        //      i) we're in group stop, and the thread group has exited group stop, or
523        //      ii) we're waking up,
524        //   b) and ptrace isn't stopping us from waking up, but
525        //   c) always wake up if we got a SIGKILL.
526        let task_stop_state = self.load_stopped();
527        let group_stop_state = self.thread_group().load_stopped();
528        if ((task_stop_state == StopState::GroupStopped && group_stop_state.is_waking_or_awake())
529            || task_stop_state.is_waking_or_awake())
530            && (!task_state.is_ptrace_listening() || task_stop_state.is_force())
531        {
532            let new_state = if task_stop_state.is_waking_or_awake() {
533                task_stop_state.finalize()
534            } else {
535                group_stop_state.finalize()
536            };
537            if let Ok(new_state) = new_state {
538                task_state.set_stopped(new_state, None, Some(self), None);
539                drop(group_state);
540                drop(task_state);
541                // It is possible for the stop state to be changed by another
542                // thread between when it is checked above and the following
543                // invocation, but set_stopped does sufficient checking while
544                // holding the lock to make sure that such a change won't result
545                // in corrupted state.
546                self.thread_group().set_stopped(new_state, None, false);
547                return true;
548            }
549        }
550
551        // We will wait.
552        if self.thread_group().load_stopped().is_stopped() || task_stop_state.is_stopped() {
553            // If we've stopped or PTRACE_LISTEN has been sent, wait for a
554            // signal or instructions from the tracer.
555            group_state
556                .lifecycle_waiters
557                .wait_async_value(&waiter, ThreadGroupLifecycleWaitValue::Stopped);
558            task_state.wait_on_ptracer(&waiter);
559        } else if task_state.can_accept_ptrace_commands() {
560            // If we're stopped because a tracer has seen the stop and not taken
561            // further action, wait for further instructions from the tracer.
562            task_state.wait_on_ptracer(&waiter);
563        } else if task_state.is_ptrace_listening() {
564            // A PTRACE_LISTEN is a state where we can get signals and notify a
565            // ptracer, but otherwise remain blocked.
566            if let Some(ptrace) = &mut task_state.ptrace {
567                ptrace.set_last_signal(Some(SignalInfo::kernel(SIGTRAP)));
568                ptrace.set_last_event(Some(PtraceEventData::new_from_event(PtraceEvent::Stop, 0)));
569            }
570            task_state.wait_on_ptracer(&waiter);
571            task_state.notify_ptracers();
572        }
573        false
574    }
575
576    /// Returns whether a deliverable signal or a task/thread-group stop is pending for this task.
577    pub fn is_interrupt_pending(&self) -> bool {
578        self.read().is_interrupt_pending()
579    }
580
581    pub fn is_work_cancelled(&self) -> bool {
582        self.flags().contains(TaskFlags::WORK_CANCELLED)
583    }
584
585    /// Set the RunState for the current task to the given value and then call the given callback.
586    ///
587    /// When the callback is done, the run_state is restored to `RunState::Running`.
588    ///
589    /// This function is typically used just before blocking the current task on some operation.
590    /// The given `run_state` registers the mechanism for interrupting the blocking operation with
591    /// the task and the given `callback` actually blocks the task.
592    ///
593    /// This function can only be called in the `RunState::Running` state and cannot set the
594    /// run state to `RunState::Running` or `RunState::Event` (use [`Self::block_until`] for
595    /// `InterruptibleEvent`). For this reason, this function cannot be reentered.
596    pub fn run_in_state<F, T>(&self, run_state: RunState, callback: F) -> Result<T, Errno>
597    where
598        F: FnOnce() -> Result<T, Errno>,
599    {
600        assert!(!matches!(run_state, RunState::Event(_)), "use block_until for RunState::Event");
601        // SAFETY: `run_state` is not `RunState::Event`.
602        unsafe { self.run_in_state_internal(run_state, callback) }
603    }
604
605    /// Internal implementation of [`Self::run_in_state`] that also accepts [`RunState::Event`].
606    ///
607    /// # Safety
608    /// If `run_state` is `RunState::Event(event_ref)`, `event_ref` must point to a live
609    /// `InterruptibleEvent` that outlives this call.
610    unsafe fn run_in_state_internal<F, T>(
611        &self,
612        run_state: RunState,
613        callback: F,
614    ) -> Result<T, Errno>
615    where
616        F: FnOnce() -> Result<T, Errno>,
617    {
618        assert_ne!(run_state, RunState::Running);
619
620        // Check we do not hold any uninterruptible lock
621        assert_lock_level::<UninterruptibleLock>();
622
623        {
624            let mut state = self.write();
625            assert!(!state.is_blocked());
626
627            // `SIGKILL` and `ThreadGroup::kill` mark tasks `EXITED` synchronously without queueing
628            // a per-task signal, so check `is_exitted()` before blocking.
629            if self.is_exitted() || self.is_work_cancelled() {
630                return error!(EINTR);
631            }
632            if run_state.ignores_signals() {
633                // Tasks frozen or stopped ignore all other signals except SIGKILL.
634                if state.has_signal_pending(SIGKILL) {
635                    return error!(EINTR);
636                }
637            } else if state.is_interrupt_pending() {
638                return error!(EINTR);
639            }
640            // SAFETY: Upheld by the caller of `run_in_state_internal`.
641            let _ = unsafe { state.set_run_state(run_state.clone()) };
642        }
643
644        let _reset_run_state = scopeguard::guard((), |()| {
645            let mut state = self.write();
646            // SAFETY: `RunState::Running` is always valid.
647            let prev_run_state = unsafe { state.set_run_state(RunState::Running) };
648            assert_eq!(prev_run_state, run_state, "SignalState run state changed while waiting!");
649        });
650        let _waiting_guard = crate::task::ThreadLockupDetector::pause_tracking();
651        callback()
652    }
653
654    pub fn block_until(
655        &self,
656        guard: EventWaitGuard<'_>,
657        deadline: zx::MonotonicInstant,
658    ) -> Result<(), Errno> {
659        self.block_with_optional_owner_until(guard, None, deadline)
660    }
661
662    pub fn block_with_owner_until(
663        &self,
664        guard: EventWaitGuard<'_>,
665        new_owner: &zx::Thread,
666        deadline: zx::MonotonicInstant,
667    ) -> Result<(), Errno> {
668        self.block_with_optional_owner_until(guard, Some(new_owner), deadline)
669    }
670
671    pub fn block_with_optional_owner_until(
672        &self,
673        guard: EventWaitGuard<'_>,
674        new_owner: Option<&zx::Thread>,
675        deadline: zx::MonotonicInstant,
676    ) -> Result<(), Errno> {
677        // SAFETY: `guard.event()` outlives this `run_in_state_internal` call, which resets
678        // `run_state` back to `RunState::Running` under `self.write()` (via `scopeguard::guard`)
679        // before returning.
680        unsafe {
681            let run_state = RunState::Event(crate::task::EventRef::new(guard.event()));
682            self.run_in_state_internal(run_state, move || {
683                guard.block_until(new_owner, deadline).map_err(|e| match e {
684                    WakeReason::Interrupted => errno!(EINTR),
685                    WakeReason::DeadlineExpired => errno!(ETIMEDOUT),
686                })
687            })
688        }
689    }
690
691    /// Determine namespace node indicated by the dir_fd.
692    ///
693    /// Returns the namespace node and the path to use relative to that node.
694    pub fn resolve_dir_fd<'a>(
695        &self,
696        dir_fd: FdNumber,
697        mut path: &'a FsStr,
698        flags: ResolveFlags,
699    ) -> Result<(NamespaceNode, &'a FsStr), Errno> {
700        let path_is_absolute = path.starts_with(b"/");
701        if path_is_absolute {
702            if flags.contains(ResolveFlags::BENEATH) {
703                return error!(EXDEV);
704            }
705            path = &path[1..];
706        }
707
708        let dir = if path_is_absolute && !flags.contains(ResolveFlags::IN_ROOT) {
709            self.fs().root()
710        } else if dir_fd == FdNumber::AT_FDCWD {
711            self.fs().cwd()
712        } else {
713            // O_PATH allowed for:
714            //
715            //   Passing the file descriptor as the dirfd argument of
716            //   openat() and the other "*at()" system calls.  This
717            //   includes linkat(2) with AT_EMPTY_PATH (or via procfs
718            //   using AT_SYMLINK_FOLLOW) even if the file is not a
719            //   directory.
720            //
721            // See https://man7.org/linux/man-pages/man2/open.2.html
722            let file = self.get_file_allowing_opath(dir_fd)?;
723            file.name.to_passive()
724        };
725
726        if !path.is_empty() {
727            if !dir.entry.node.is_dir() {
728                return error!(ENOTDIR);
729            }
730            dir.check_access(self, AccessCheck::for_internal(Access::EXEC))?;
731        }
732        Ok((dir, path.into()))
733    }
734
735    /// A convenient wrapper for opening files relative to FdNumber::AT_FDCWD.
736    ///
737    /// Returns a FileHandle but does not install the FileHandle in the FdTable
738    /// for this task.
739    pub fn open_file(&self, path: &FsStr, flags: OpenFlags) -> Result<FileHandle, Errno> {
740        if flags.contains(OpenFlags::CREAT) {
741            // In order to support OpenFlags::CREAT we would need to take a
742            // FileMode argument.
743            return error!(EINVAL);
744        }
745        self.open_file_at(
746            FdNumber::AT_FDCWD,
747            path,
748            flags,
749            FileMode::default(),
750            ResolveFlags::empty(),
751        )
752    }
753
754    /// Opens an executable or interpreter file for binary execution.
755    ///
756    /// This method is intended for opening initial executables, script interpreters (`#!`),
757    /// and ELF dynamic linkers (`PT_INTERP`).
758    ///
759    /// Resolves the target [`NamespaceNode`] and verifies that it is a regular file before opening
760    /// it, avoiding unintended driver initialization on device nodes or blocking on FIFOs. Returns
761    /// [`EACCES`] if the target is not a regular file, or [`ELOOP`] if [`OpenFlags::NOFOLLOW`] was
762    /// specified and the target is a symbolic link.
763    ///
764    /// Opens the file for execution, verifying DAC execute permissions and filesystem mount
765    /// `MS_NOEXEC`.
766    ///
767    /// Returns an [`Arc<FileMapping>`] with an execution write guard.
768    pub fn open_file_for_exec(
769        &self,
770        dir_fd: FdNumber,
771        path: &FsStr,
772        flags: OpenFlags,
773    ) -> Result<Arc<FileMapping>, Errno> {
774        debug_assert!(
775            (flags & !(OpenFlags::RDONLY | OpenFlags::NOFOLLOW)).is_empty(),
776            "unexpected flags passed to open_file_for_exec: {flags:?}"
777        );
778        if !(flags & !(OpenFlags::RDONLY | OpenFlags::NOFOLLOW)).is_empty() {
779            return error!(EINVAL);
780        }
781
782        let (dir, path) = self.resolve_dir_fd(dir_fd, path, ResolveFlags::empty())?;
783        let nofollow = flags.contains(OpenFlags::NOFOLLOW);
784        let mut context =
785            LookupContext::new(if nofollow { SymlinkMode::NoFollow } else { SymlinkMode::Follow });
786        context.update_for_path(path);
787        let name = self.lookup_path(&mut context, dir, path)?;
788
789        // From <https://man7.org/linux/man-pages/man2/execveat.2.html>:
790        //
791        //   ELOOP  flags includes AT_SYMLINK_NOFOLLOW and the file identified by
792        //          dirfd and pathname is a symbolic link.
793        if nofollow && name.entry.node.info().mode.is_lnk() {
794            return error!(ELOOP);
795        }
796
797        // From <https://man7.org/linux/man-pages/man2/execve.2.html>:
798        //
799        //   EACCES The file or a script interpreter is not a regular file.
800        if !name.entry.node.is_reg() {
801            return error!(EACCES);
802        }
803
804        // From <https://man7.org/linux/man-pages/man2/execve.2.html>:
805        //
806        //   EACCES Execute permission is denied for the file or a script or ELF
807        //          interpreter.
808        //
809        //   EACCES The filesystem is mounted noexec.
810        let file = name.open(self, OpenAccessCheck::for_exec())?;
811        FileMapping::new(file, Some(FileWriteGuardMode::ExecMapping))
812    }
813
814    /// Resolves a path for open.
815    ///
816    /// If the final path component points to a symlink, the symlink is followed (as long as
817    /// the symlink traversal limit has not been reached).
818    ///
819    /// If the final path component (after following any symlinks, if enabled) does not exist,
820    /// and `flags` contains `OpenFlags::CREAT`, a new node is created at the location of the
821    /// final path component.
822    ///
823    /// This returns the resolved node, and a boolean indicating whether the node has been created.
824    fn resolve_open_path(
825        &self,
826        context: &mut LookupContext,
827        dir: &NamespaceNode,
828        path: &FsStr,
829        mode: FileMode,
830        flags: OpenFlags,
831    ) -> Result<(NamespaceNode, bool), Errno> {
832        context.update_for_path(path);
833        let mut parent_content = context.with(SymlinkMode::Follow, context.directory_mode);
834        let (parent, basename) = self.lookup_parent(&mut parent_content, dir, path)?;
835        context.remaining_follows = parent_content.remaining_follows;
836
837        let must_create = flags.contains(OpenFlags::CREAT) && flags.contains(OpenFlags::EXCL);
838
839        // Lookup the child, without following a symlink or expecting it to be a directory.
840        let mut child_context = context.with(SymlinkMode::NoFollow, DirectoryMode::AllowAny);
841
842        let child = if flags.contains(OpenFlags::CREAT)
843            && context.directory_mode != DirectoryMode::MustBeDirectory
844            && !DirEntry::is_reserved_name(basename)
845        {
846            // When creating, look up and create the child in a single step under the parent's
847            // children lock, like Linux's lookup_open(). A separate lookup first would just be
848            // repeated under the lock, which costs an extra round trip on remote filesystems.
849            let (child, status) = parent.open_create_node(
850                self,
851                basename,
852                mode.with_type(FileMode::IFREG),
853                DeviceId::NONE,
854            )?;
855            if status == CreationStatus::Created {
856                return Ok((child, true));
857            }
858            // The child already exists. Resolve the node that was found rather than looking it
859            // up again, which would revalidate it a second time. O_EXCL is only checked below,
860            // after mounts have been entered, so that RESOLVE_NO_XDEV takes precedence over
861            // EEXIST, as in Linux.
862            parent.resolve_child(self, &mut child_context, child)
863        } else {
864            parent.lookup_child(self, &mut child_context, basename)
865        };
866
867        match child {
868            Ok(name) => {
869                if name.entry.node.is_lnk() {
870                    if flags.contains(OpenFlags::PATH)
871                        && context.symlink_mode == SymlinkMode::NoFollow
872                    {
873                        // When O_PATH is specified in flags, if pathname is a symbolic link
874                        // and the O_NOFOLLOW flag is also specified, then the call returns
875                        // a file descriptor referring to the symbolic link.
876                        // See https://man7.org/linux/man-pages/man2/openat.2.html
877                        //
878                        // If the trailing component (i.e., basename) of
879                        // pathname is a symbolic link, how.resolve contains
880                        // RESOLVE_NO_SYMLINKS, and how.flags contains both
881                        // O_PATH and O_NOFOLLOW, then an O_PATH file
882                        // descriptor referencing the symbolic link will be
883                        // returned.
884                        // See https://man7.org/linux/man-pages/man2/openat2.2.html
885                        return Ok((name, false));
886                    }
887
888                    if (!flags.contains(OpenFlags::PATH)
889                        && context.symlink_mode == SymlinkMode::NoFollow)
890                        || context.resolve_flags.contains(ResolveFlags::NO_SYMLINKS)
891                        || context.remaining_follows == 0
892                    {
893                        if must_create {
894                            // Since `must_create` is set, and a node was found, this returns EEXIST
895                            // instead of ELOOP.
896                            return error!(EEXIST);
897                        }
898                        // A symlink was found, but one of the following is true:
899                        // * flags specified O_NOFOLLOW but not O_PATH.
900                        // * how.resolve contains RESOLVE_NO_SYMLINKS
901                        // * too many symlink traversals have been attempted
902                        return error!(ELOOP);
903                    }
904
905                    context.remaining_follows -= 1;
906                    match name.readlink(self)? {
907                        SymlinkTarget::Path(path) => {
908                            let dir = if path[0] == b'/' { self.fs().root() } else { parent };
909                            self.resolve_open_path(context, &dir, path.as_ref(), mode, flags)
910                        }
911                        SymlinkTarget::Node(name) => {
912                            if context.resolve_flags.contains(ResolveFlags::NO_MAGICLINKS)
913                                || name.entry.node.is_lnk()
914                            {
915                                error!(ELOOP)
916                            } else {
917                                Ok((name, false))
918                            }
919                        }
920                    }
921                } else {
922                    if must_create {
923                        return error!(EEXIST);
924                    }
925                    Ok((name, false))
926                }
927            }
928            Err(e)
929                if e == errno!(ENOENT)
930                    && flags.contains(OpenFlags::CREAT)
931                    && context.directory_mode == DirectoryMode::MustBeDirectory =>
932            {
933                // A path that must be a directory is not created. Other children that did not
934                // exist were created above.
935                error!(EISDIR)
936            }
937            Err(e) => Err(e),
938        }
939    }
940
941    /// The primary entry point for opening files relative to a task.
942    ///
943    /// Absolute paths are resolve relative to the root of the FsContext for
944    /// this task. Relative paths are resolve relative to dir_fd. To resolve
945    /// relative to the current working directory, pass FdNumber::AT_FDCWD for
946    /// dir_fd.
947    ///
948    /// Returns a FileHandle but does not install the FileHandle in the FdTable
949    /// for this task.
950    pub fn open_file_at(
951        &self,
952        dir_fd: FdNumber,
953        path: &FsStr,
954        flags: impl Into<OpenAccessCheck>,
955        mode: FileMode,
956        resolve_flags: ResolveFlags,
957    ) -> Result<FileHandle, Errno> {
958        if path.is_empty() {
959            return error!(ENOENT);
960        }
961
962        let (dir, path) = self.resolve_dir_fd(dir_fd, path, resolve_flags)?;
963        self.open_namespace_node_at(dir, path, flags, mode, resolve_flags)
964    }
965
966    pub fn open_namespace_node_at(
967        &self,
968        dir: NamespaceNode,
969        path: &FsStr,
970        open_check: impl Into<OpenAccessCheck>,
971        mode: FileMode,
972        mut resolve_flags: ResolveFlags,
973    ) -> Result<FileHandle, Errno> {
974        let open_check = open_check.into();
975        // 64-bit kernels force the O_LARGEFILE flag to be on.
976        let mut flags = open_check.open_flags() | OpenFlags::LARGEFILE;
977        let opath = flags.contains(OpenFlags::PATH);
978        if opath {
979            // When O_PATH is specified in flags, flag bits other than O_CLOEXEC,
980            // O_DIRECTORY, and O_NOFOLLOW are ignored.
981            const ALLOWED_FLAGS: OpenFlags = OpenFlags::from_bits_truncate(
982                OpenFlags::PATH.bits()
983                    | OpenFlags::CLOEXEC.bits()
984                    | OpenFlags::DIRECTORY.bits()
985                    | OpenFlags::NOFOLLOW.bits(),
986            );
987            flags &= ALLOWED_FLAGS;
988        }
989
990        if flags.contains(OpenFlags::TMPFILE) && !flags.can_write() {
991            return error!(EINVAL);
992        }
993
994        let nofollow = flags.contains(OpenFlags::NOFOLLOW);
995        let must_create = flags.contains(OpenFlags::CREAT) && flags.contains(OpenFlags::EXCL);
996
997        let symlink_mode =
998            if nofollow || must_create { SymlinkMode::NoFollow } else { SymlinkMode::Follow };
999
1000        let resolve_base = match (
1001            resolve_flags.contains(ResolveFlags::BENEATH),
1002            resolve_flags.contains(ResolveFlags::IN_ROOT),
1003        ) {
1004            (false, false) => ResolveBase::None,
1005            (true, false) => ResolveBase::Beneath(dir.clone()),
1006            (false, true) => ResolveBase::InRoot(dir.clone()),
1007            (true, true) => return error!(EINVAL),
1008        };
1009
1010        // `RESOLVE_BENEATH` and `RESOLVE_IN_ROOT` imply `RESOLVE_NO_MAGICLINKS`. This matches
1011        // Linux behavior. Strictly speaking it's is not really required, but it's hard to
1012        // implement `BENEATH` and `IN_ROOT` flags correctly otherwise.
1013        if resolve_base != ResolveBase::None {
1014            resolve_flags.insert(ResolveFlags::NO_MAGICLINKS);
1015        }
1016
1017        let mut context = LookupContext {
1018            symlink_mode,
1019            remaining_follows: MAX_SYMLINK_FOLLOWS,
1020            directory_mode: if flags.contains(OpenFlags::DIRECTORY) {
1021                DirectoryMode::MustBeDirectory
1022            } else {
1023                DirectoryMode::AllowAny
1024            },
1025            resolve_flags,
1026            resolve_base,
1027        };
1028        let (name, created) = match self.resolve_open_path(&mut context, &dir, path, mode, flags) {
1029            Ok((n, c)) => (n, c),
1030            Err(e) => {
1031                let mut abs_path = dir.path(&self.fs());
1032                abs_path.extend(&**path);
1033                track_file_not_found(abs_path);
1034                return Err(e);
1035            }
1036        };
1037
1038        let name = if flags.contains(OpenFlags::TMPFILE) {
1039            // `O_TMPFILE` is incompatible with `O_CREAT`
1040            if flags.contains(OpenFlags::CREAT) {
1041                return error!(EINVAL);
1042            }
1043            name.create_tmpfile(self, mode.with_type(FileMode::IFREG), flags)?
1044        } else {
1045            let mode = name.entry.node.info().mode;
1046
1047            // These checks are not needed in the `O_TMPFILE` case because `mode` refers to the
1048            // file we are opening. With `O_TMPFILE`, that file is the regular file we just
1049            // created rather than the node we found by resolving the path.
1050            //
1051            // For example, we do not need to produce `ENOTDIR` when `must_be_directory` is set
1052            // because `must_be_directory` refers to the node we found by resolving the path.
1053            // If that node was not a directory, then `create_tmpfile` will produce an error.
1054            //
1055            // Similarly, we never need to call `truncate` because `O_TMPFILE` is newly created
1056            // and therefor already an empty file.
1057
1058            if !opath && nofollow && mode.is_lnk() {
1059                return error!(ELOOP);
1060            }
1061
1062            if mode.is_dir() {
1063                if flags.can_write()
1064                    || flags.contains(OpenFlags::CREAT)
1065                    || flags.contains(OpenFlags::TRUNC)
1066                {
1067                    return error!(EISDIR);
1068                }
1069                if flags.contains(OpenFlags::DIRECT) {
1070                    return error!(EINVAL);
1071                }
1072            } else if context.directory_mode == DirectoryMode::MustBeDirectory {
1073                return error!(ENOTDIR);
1074            }
1075
1076            if flags.contains(OpenFlags::TRUNC) && mode.is_reg() && !created {
1077                // You might think we should check file.can_write() at this
1078                // point, which is what the docs suggest, but apparently we
1079                // are supposed to truncate the file if this task can write
1080                // to the underlying node, even if we are opening the file
1081                // as read-only. See OpenTest.CanTruncateReadOnly.
1082                name.truncate(self, 0)?;
1083            }
1084
1085            name
1086        };
1087
1088        // If the node has been created, the open operation should not verify access right:
1089        // From <https://man7.org/linux/man-pages/man2/open.2.html>
1090        //
1091        // > Note that mode applies only to future accesses of the newly created file; the
1092        // > open() call that creates a read-only file may well return a  read/write  file
1093        // > descriptor.
1094        let file = if created {
1095            name.open(self, OpenAccessCheck::skip(flags))?
1096        } else {
1097            name.open(self, OpenAccessCheck::new(flags, open_check.access_check()))?
1098        };
1099
1100        // If the new `FileHandle` represents an open file (rather than a handle to a location in
1101        // the virtual file system, as created with `O_PATH`), then LSM permission checks may be
1102        // required.
1103        if !opath {
1104            security::file_open(self, &file)?;
1105        }
1106
1107        Ok(file)
1108    }
1109
1110    /// A wrapper for FsContext::lookup_parent_at that resolves the given
1111    /// dir_fd to a NamespaceNode.
1112    ///
1113    /// Absolute paths are resolve relative to the root of the FsContext for
1114    /// this task. Relative paths are resolve relative to dir_fd. To resolve
1115    /// relative to the current working directory, pass FdNumber::AT_FDCWD for
1116    /// dir_fd.
1117    pub fn lookup_parent_at<'a>(
1118        &self,
1119        context: &mut LookupContext,
1120        dir_fd: FdNumber,
1121        path: &'a FsStr,
1122    ) -> Result<(NamespaceNode, &'a FsStr), Errno> {
1123        let (dir, path) = self.resolve_dir_fd(dir_fd, path, ResolveFlags::empty())?;
1124        self.lookup_parent(context, &dir, path)
1125    }
1126
1127    /// Lookup the parent of a namespace node.
1128    ///
1129    /// Consider using Task::open_file_at or Task::lookup_parent_at rather than
1130    /// calling this function directly.
1131    ///
1132    /// This function resolves all but the last component of the given path.
1133    /// The function returns the parent directory of the last component as well
1134    /// as the last component.
1135    ///
1136    /// If path is empty, this function returns dir and an empty path.
1137    /// Similarly, if path ends with "." or "..", these components will be
1138    /// returned along with the parent.
1139    ///
1140    /// The returned parent might not be a directory.
1141    pub fn lookup_parent<'a>(
1142        &self,
1143        context: &mut LookupContext,
1144        dir: &NamespaceNode,
1145        path: &'a FsStr,
1146    ) -> Result<(NamespaceNode, &'a FsStr), Errno> {
1147        context.update_for_path(path);
1148
1149        let components = split_path(path);
1150        if components.is_empty() {
1151            return Ok((dir.clone(), Default::default()));
1152        }
1153        let result = dir.lookup_children(self, context, &components[0..components.len() - 1])?;
1154        Ok((result, components.last().unwrap()))
1155    }
1156
1157    /// Lookup a namespace node.
1158    ///
1159    /// Consider using Task::open_file_at or Task::lookup_parent_at rather than
1160    /// calling this function directly.
1161    ///
1162    /// This function resolves the component of the given path.
1163    pub fn lookup_path(
1164        &self,
1165        context: &mut LookupContext,
1166        dir: NamespaceNode,
1167        path: &FsStr,
1168    ) -> Result<NamespaceNode, Errno> {
1169        let components = split_path(path);
1170        dir.lookup_children(self, context, &components)
1171    }
1172
1173    /// Lookup a namespace node starting at the root directory.
1174    ///
1175    /// Resolves symlinks.
1176    pub fn lookup_path_from_root(&self, path: &FsStr) -> Result<NamespaceNode, Errno> {
1177        let mut context = LookupContext::default();
1178        self.lookup_path(&mut context, self.fs().root(), path)
1179    }
1180
1181    pub fn exec(
1182        &mut self,
1183        executable: Arc<FileMapping>,
1184        path: CString,
1185        argv: Vec<CString>,
1186        environ: Vec<CString>,
1187    ) -> Result<(), Errno> {
1188        // Serialize against ptrace_attach by holding the credentials write lock.
1189        let writable_creds = self.write_creds();
1190
1191        // Evaluate LSM access checks and domain transitions (`bprm_creds_for_exec`) against the
1192        // initial executable before resolving `#!` scripts, so that script execution transitions
1193        // to the domain determined by the script file rather than its interpreter. Once `#!`
1194        // scripts are resolved to the target ELF binary, apply SUID/SGID and file capabilities
1195        // (`bprm_creds_from_file`) and validate `PT_INTERP` before committing the exec.
1196        let mut resolved_program = ResolvedProgram::new(self, executable, path, argv, environ);
1197        security::bprm_creds_for_exec(self, &mut resolved_program)?;
1198        resolve_executable(self, &mut resolved_program)?;
1199        security::bprm_creds_from_file(self, &mut resolved_program)?;
1200        resolve_elf_interpreter(self, &mut resolved_program)?;
1201
1202        if self.thread_group().read().tasks_count() > 1 {
1203            track_stub!(TODO("https://fxbug.dev/297434895"), "exec on multithread process");
1204            return error!(EINVAL);
1205        }
1206
1207        // Commit the exec. Failures after this point are unrecoverable.
1208        if let Err(err) = self.finish_exec(resolved_program, writable_creds) {
1209            log_warn!("unrecoverable error in exec: {err:?}");
1210
1211            send_standard_signal(self, SignalInfo::forced(SIGSEGV));
1212            return Err(err);
1213        }
1214
1215        let tid = self.get_tid() as u64;
1216        self.ptrace().on_event(PtraceOptions::TRACEEXEC, tid);
1217        self.signal_vfork();
1218        self.task.thread_group.sync_syscall_log_level();
1219
1220        Ok(())
1221    }
1222
1223    /// After the memory is unmapped, any failure in exec is unrecoverable and results in the
1224    /// process crashing. This function is for that second half; any error returned from this
1225    /// function will be considered unrecoverable.
1226    fn finish_exec(
1227        &mut self,
1228        resolved_program: ResolvedProgram,
1229        writable_creds: CurrentTaskCredentialsWriteGuard,
1230    ) -> Result<(), Errno> {
1231        let elf_arch_width = resolved_program.arch_width().ok_or_else(|| errno!(EINVAL))?;
1232
1233        // Now that the exec will definitely finish (or crash), notify owners of
1234        // locked futexes for the current process, which will be impossible to
1235        // update after process image is replaced.  See get_robust_list(2).
1236        self.notify_robust_list();
1237
1238        // Tear down the old address space and create a new one for the resolved ELF.
1239        let new_mm = MemoryManager::exec(
1240            self.thread_group().root_vmar.unowned(),
1241            self.mm().ok().cloned(),
1242            resolved_program.file.name().to_passive(),
1243            elf_arch_width,
1244        )?;
1245
1246        // From <https://man7.org/linux/man-pages/man2/execve.2.html>:
1247        //
1248        //   The process's "dumpable" attribute is set to the value 1,
1249        //   unless a set-user-ID program, a set-group-ID program, or a
1250        //   program with capabilities is being executed, in which case the
1251        //   dumpable flag may instead be reset to the value in
1252        //   /proc/sys/fs/suid_dumpable, in the circumstances described
1253        //   under PR_SET_DUMPABLE in prctl(2).
1254        let dumpable = if resolved_program.secure_exec {
1255            self.kernel().system_limits.suid_dumpable.load()
1256        } else {
1257            DumpPolicy::User
1258        };
1259        new_mm.dumpable.store(dumpable);
1260
1261        self.running_state().mm.update(Some(new_mm.clone()));
1262        self.mm = Some(new_mm);
1263
1264        // From <https://man7.org/linux/man-pages/man2/execve.2.html>:
1265        //
1266        //   All threads other than the calling thread are destroyed during an
1267        //   execve(). Mutual exclusion locks, condition variables, and other
1268        //   pthreads objects are not preserved.
1269        //
1270        // TODO(https://fxbug.dev/297434895): Implement thread destruction.
1271
1272        // Filesystem context sharing (via CLONE_FS with clone(2)) is preserved across
1273        // execve under Linux, as verified by `CloneAndExecTest.ExecDoesNotUnshareCloneFs`.
1274
1275        // From <https://man7.org/linux/man-pages/man2/execve.2.html>:
1276        //
1277        //   If the calling process was sharing its file descriptor table (via
1278        //   the use of CLONE_FILES with clone(2)), then this sharing is undone.
1279        self.running_state().unshare_files(self);
1280        self.files().exec();
1281
1282        // From <https://man7.org/linux/man-pages/man2/PR_SET_PDEATHSIG.2const.html>:
1283        //
1284        //   It is also (since Linux 2.4.36 / 2.6.23) cleared when
1285        //   executing a set-user-ID or set-group-ID binary, or a binary that
1286        //   has associated capabilities (see capabilities(7)); otherwise, this
1287        //   value is preserved across execve(2).
1288        if resolved_program.secure_exec {
1289            self.thread_group().write().set_parent_death_signal(None);
1290        }
1291
1292        {
1293            let mut state = self.write();
1294            state.set_sigaltstack(None);
1295            state.robust_list_head = RobustListHeadPtr::null(self);
1296        }
1297
1298        security::bprm_committing_creds(self, &resolved_program)?;
1299
1300        let new_creds = Arc::new(resolved_program.creds.clone());
1301        writable_creds.update(self, new_creds);
1302
1303        // From <https://man7.org/linux/man-pages/man2/execve.2.html>:
1304        //
1305        //   POSIX timers (timer_create(2)) are not preserved.
1306        self.thread_group().timers.reset_for_exec(self);
1307
1308        self.thread_group().signal_actions.reset_for_exec();
1309        security::bprm_committed_creds(self)?;
1310
1311        let command_name = TaskCommand::from_path_bytes(resolved_program.path().to_bytes());
1312        let start_info = load_executable(self, resolved_program)?;
1313
1314        let regs: zx_restricted_state_t = start_info.into();
1315        self.thread_state.registers.load(regs);
1316        self.thread_state.extended_pstate.reset_with_arch(self.thread_state.arch_width());
1317
1318        // The exit signal (and that of the children) is reset to SIGCHLD.
1319        {
1320            let mut thread_group_state = self.thread_group().write();
1321            thread_group_state.exit_signal = Some(SIGCHLD);
1322            for child in thread_group_state.children() {
1323                // This allow_subclass is safe because locking parent then child strictly
1324                // follows the top-down traversal of the thread group tree, which cannot form
1325                // cycles.
1326                let _token = starnix_sync::allow_subclass();
1327                let mut child_state = child.write();
1328                child_state.exit_signal = Some(SIGCHLD);
1329            }
1330        }
1331
1332        self.thread_group().write().did_exec = true;
1333
1334        self.set_command_name(command_name);
1335
1336        Ok(())
1337    }
1338
1339    pub fn set_command_name(&self, new_name: TaskCommand) {
1340        // set_command_name needs to run before leader_command() in cases where self is the leader.
1341        self.task.set_command_name(new_name.clone());
1342        let leader_command = self.thread_group().read().leader_command();
1343        starnix_logging::set_current_task_info(new_name, leader_command, self.pid.id, self.tid.id);
1344    }
1345
1346    pub fn add_seccomp_filter(
1347        &mut self,
1348        code: Vec<sock_filter>,
1349        flags: u32,
1350    ) -> Result<SyscallResult, Errno> {
1351        let mut notifier = None;
1352        if flags & SECCOMP_FILTER_FLAG_NEW_LISTENER != 0 {
1353            notifier = Some(SeccompFilterContainer::create_notifier());
1354        }
1355
1356        let new_filter = Arc::new(SeccompFilter::from_cbpf(
1357            &code,
1358            self.thread_group().next_seccomp_filter_id.add(1),
1359            flags & SECCOMP_FILTER_FLAG_LOG != 0,
1360            notifier.clone(),
1361        )?);
1362
1363        let mut maybe_fd: Option<FdNumber> = None;
1364        if let Some(notifier) = notifier {
1365            maybe_fd = Some(SeccompFilterContainer::register_listener(self, notifier)?);
1366        }
1367
1368        // We take the process lock here because we can't change any of the threads
1369        // while doing a tsync.  So, you hold the process lock while making any changes.
1370        let state = self.thread_group().write();
1371
1372        if self.seccomp_filter_state.get() == SeccompStateValue::Strict {
1373            return error!(EINVAL);
1374        }
1375
1376        if flags & SECCOMP_FILTER_FLAG_TSYNC != 0 {
1377            // TSYNC synchronizes all filters for all threads in the current process to
1378            // the current thread's
1379
1380            // We collect the filters for the current task upfront to save us acquiring
1381            // the task's lock a lot of times below.
1382            let mut filters: SeccompFilterContainer = self.read().seccomp_filters.clone();
1383
1384            // For TSYNC to work, all of the other thread filters in this process have to
1385            // be a prefix of this thread's filters, and none of them can be in
1386            // strict mode.
1387            let tasks = state.tasks();
1388            for task in &tasks {
1389                if task.tid.id == self.tid.id {
1390                    continue;
1391                }
1392                let other_task_state = task.read();
1393
1394                // Target threads cannot be in SECCOMP_MODE_STRICT
1395                if task.seccomp_filter_state.get() == SeccompStateValue::Strict {
1396                    return Self::seccomp_tsync_error(task.tid.id, flags);
1397                }
1398
1399                // Target threads' filters must be a subsequence of this thread's
1400                if !other_task_state.seccomp_filters.can_sync_to(&filters) {
1401                    return Self::seccomp_tsync_error(task.tid.id, flags);
1402                }
1403            }
1404
1405            // Now that we're sure we're allowed to do so, add the filter to all threads.
1406            filters.add_filter(new_filter, code.len() as u16)?;
1407
1408            for task in &tasks {
1409                let mut other_task_state = task.write();
1410
1411                other_task_state.enable_no_new_privs();
1412                other_task_state.seccomp_filters = filters.clone();
1413                task.seccomp_filter_state.set_always_allow(&filters.always_allow);
1414                task.set_seccomp_state(SeccompStateValue::UserDefined)?;
1415            }
1416        } else {
1417            let mut task_state = self.task.write();
1418
1419            task_state.seccomp_filters.add_filter(new_filter, code.len() as u16)?;
1420            let always_allow = task_state.seccomp_filters.always_allow;
1421            self.seccomp_filter_state.set_always_allow(&always_allow);
1422            self.set_seccomp_state(SeccompStateValue::UserDefined)?;
1423        }
1424
1425        if let Some(fd) = maybe_fd { Ok(fd.into()) } else { Ok(().into()) }
1426    }
1427
1428    #[inline]
1429    pub fn run_seccomp_filters(
1430        &mut self,
1431        syscall: &Syscall,
1432    ) -> Option<Result<SyscallResult, Errno>> {
1433        if !self.is_arch32()
1434            && self.seccomp_filter_state.is_syscall_always_allowed(syscall.decl.number)
1435        {
1436            return None;
1437        }
1438        self.run_seccomp_filters_slow(syscall)
1439    }
1440
1441    #[cold]
1442    #[inline(never)]
1443    fn run_seccomp_filters_slow(
1444        &mut self,
1445        syscall: &Syscall,
1446    ) -> Option<Result<SyscallResult, Errno>> {
1447        // Implementation of SECCOMP_FILTER_STRICT, which has slightly different semantics
1448        // from user-defined seccomp filters.
1449        if self.seccomp_filter_state.get() == SeccompStateValue::Strict {
1450            return SeccompState::do_strict(self, syscall);
1451        }
1452
1453        // Run user-defined seccomp filters
1454        let result = self.task.read().seccomp_filters.run_all(self, syscall);
1455
1456        SeccompState::do_user_defined(result, self, syscall)
1457    }
1458
1459    fn seccomp_tsync_error(id: i32, flags: u32) -> Result<SyscallResult, Errno> {
1460        // By default, TSYNC indicates failure state by returning the first thread
1461        // id not to be able to sync, rather than by returning -1 and setting
1462        // errno.  However, if TSYNC_ESRCH is set, it returns ESRCH.  This
1463        // prevents conflicts with fact that SECCOMP_FILTER_FLAG_NEW_LISTENER
1464        // makes seccomp return an fd.
1465        if flags & SECCOMP_FILTER_FLAG_TSYNC_ESRCH != 0 { error!(ESRCH) } else { Ok(id.into()) }
1466    }
1467
1468    // Notify all futexes in robust list.  The robust list is in user space, so we
1469    // are very careful about walking it, and there are a lot of quiet returns if
1470    // we fail to walk it.
1471    // TODO(https://fxbug.dev/42079081): This only sets the FUTEX_OWNER_DIED bit; it does
1472    // not wake up a waiter.
1473    pub fn notify_robust_list(&self) {
1474        let task_state = self.write();
1475        let robust_list_addr = task_state.robust_list_head.addr();
1476        if robust_list_addr == UserAddress::NULL {
1477            // No one has called set_robust_list.
1478            return;
1479        }
1480        let robust_list_res = self.read_multi_arch_object(task_state.robust_list_head);
1481
1482        let head = if let Ok(head) = robust_list_res {
1483            head
1484        } else {
1485            return;
1486        };
1487
1488        let offset = head.futex_offset;
1489
1490        let mut entries_count = 0;
1491        let mut curr_ptr = head.list.next;
1492        while curr_ptr.addr() != robust_list_addr.into() && entries_count < ROBUST_LIST_LIMIT {
1493            let curr_ref = self.read_multi_arch_object(curr_ptr);
1494
1495            let curr = if let Ok(curr) = curr_ref {
1496                curr
1497            } else {
1498                return;
1499            };
1500
1501            let Some(futex_base) = curr_ptr.addr().checked_add_signed(offset) else {
1502                return;
1503            };
1504
1505            let futex_addr = match FutexAddress::try_from(futex_base) {
1506                Ok(addr) => addr,
1507                Err(_) => {
1508                    return;
1509                }
1510            };
1511
1512            let Ok(mm) = self.mm() else {
1513                log_error!("Asked to notify robust list futexes in system task.");
1514                return;
1515            };
1516            let futex = if let Ok(futex) = mm.atomic_load_u32_relaxed(futex_addr) {
1517                futex
1518            } else {
1519                return;
1520            };
1521
1522            if (futex & FUTEX_TID_MASK) as i32 == self.tid.id {
1523                let owner_died = FUTEX_OWNER_DIED | futex;
1524                if mm.atomic_store_u32_relaxed(futex_addr, owner_died).is_err() {
1525                    return;
1526                }
1527            }
1528            curr_ptr = curr.next;
1529            entries_count += 1;
1530        }
1531    }
1532
1533    pub(crate) fn handle_page_fault(
1534        &self,
1535        decoded: PageFaultExceptionReport,
1536        status: zx::Status,
1537    ) -> ExceptionResult {
1538        if let Ok(mm) = self.mm() {
1539            mm.handle_page_fault(decoded, status)
1540        } else {
1541            panic!(
1542                "system task is handling a major page fault status={:?}, report={:?}",
1543                status, decoded
1544            );
1545        }
1546    }
1547
1548    /// Processes a Zircon exception associated with this task.
1549    pub fn process_exception(&self, report: &zx::ExceptionReport) -> ExceptionResult {
1550        if let Some(result) = handle_hardware_exception(self, report) {
1551            return result;
1552        }
1553
1554        match report.ty {
1555            zx::ExceptionType::General => {
1556                log_error!("Unrecognized general exception: {:?}", report);
1557                ExceptionResult::Signal(SignalInfo::kernel(SIGILL))
1558            }
1559            zx::ExceptionType::ProcessNameChanged => {
1560                log_error!("Received unexpected process name changed exception");
1561                ExceptionResult::Handled
1562            }
1563            zx::ExceptionType::ProcessStarting
1564            | zx::ExceptionType::ThreadStarting
1565            | zx::ExceptionType::ThreadExiting => {
1566                log_error!("Received unexpected task lifecycle exception");
1567                ExceptionResult::Signal(SignalInfo::kernel(SIGSYS))
1568            }
1569            zx::ExceptionType::PolicyError(policy_code) => {
1570                log_error!(policy_code:?; "Received Zircon policy error exception");
1571                ExceptionResult::Signal(SignalInfo::kernel(SIGSYS))
1572            }
1573            zx::ExceptionType::UnknownUserGenerated { code, data } => {
1574                log_error!(code:?, data:?; "Received unexpected unknown user generated exception");
1575                ExceptionResult::Signal(SignalInfo::kernel(SIGSYS))
1576            }
1577            zx::ExceptionType::Unknown { ty, code, data } => {
1578                log_error!(ty:?, code:?, data:?; "Received unexpected exception");
1579                ExceptionResult::Signal(SignalInfo::kernel(SIGSYS))
1580            }
1581            _ => {
1582                log_error!("Received unknown zircon exception: {:?}", report.ty);
1583                ExceptionResult::Signal(SignalInfo::kernel(SIGSYS))
1584            }
1585        }
1586    }
1587
1588    /// Clone this task.
1589    ///
1590    /// Creates a new task object that shares some state with this task
1591    /// according to the given flags.
1592    ///
1593    /// Used by the clone() syscall to create both processes and threads.
1594    ///
1595    /// The exit signal is broken out from the flags parameter like clone3() rather than being
1596    /// bitwise-ORed like clone().
1597    pub fn clone_task(
1598        &self,
1599        flags: u64,
1600        child_exit_signal: Option<Signal>,
1601        user_parent_tid: UserRef<pid_t>,
1602        user_child_tid: UserRef<pid_t>,
1603        user_pidfd: UserRef<FdNumber>,
1604    ) -> Result<TaskBuilder, Errno> {
1605        const IMPLEMENTED_FLAGS: u64 = ((CLONE_VM
1606            | CLONE_FS
1607            | CLONE_FILES
1608            | CLONE_SIGHAND
1609            | CLONE_THREAD
1610            | CLONE_SYSVSEM
1611            | CLONE_SETTLS
1612            | CLONE_PARENT
1613            | CLONE_PARENT_SETTID
1614            | CLONE_PIDFD
1615            | CLONE_CHILD_CLEARTID
1616            | CLONE_CHILD_SETTID
1617            | CLONE_VFORK
1618            | CLONE_NEWUTS
1619            | CLONE_PTRACE) as u64)
1620            | CLONE_CLEAR_SIGHAND;
1621
1622        // A mask with all valid flags set, because we want to return a different error code for an
1623        // invalid flag vs an unimplemented flag. Subtracting 1 from the largest valid flag gives a
1624        // mask with all flags below it set. Shift up by one to make sure the largest flag is also
1625        // set.
1626        const VALID_FLAGS: u64 = (CLONE_INTO_CGROUP << 1) - 1;
1627
1628        // CLONE_SETTLS is implemented by sys_clone.
1629
1630        let clone_files = flags & (CLONE_FILES as u64) != 0;
1631        let clone_fs = flags & (CLONE_FS as u64) != 0;
1632        let clone_parent = flags & (CLONE_PARENT as u64) != 0;
1633        let clone_parent_settid = flags & (CLONE_PARENT_SETTID as u64) != 0;
1634        let clone_pidfd = flags & (CLONE_PIDFD as u64) != 0;
1635        let clone_child_cleartid = flags & (CLONE_CHILD_CLEARTID as u64) != 0;
1636        let clone_child_settid = flags & (CLONE_CHILD_SETTID as u64) != 0;
1637        let clone_sysvsem = flags & (CLONE_SYSVSEM as u64) != 0;
1638        let clone_ptrace = flags & (CLONE_PTRACE as u64) != 0;
1639        let clone_thread = flags & (CLONE_THREAD as u64) != 0;
1640        let clone_vm = flags & (CLONE_VM as u64) != 0;
1641        let clone_sighand = flags & (CLONE_SIGHAND as u64) != 0;
1642        let clone_vfork = flags & (CLONE_VFORK as u64) != 0;
1643        let clone_newuts = flags & (CLONE_NEWUTS as u64) != 0;
1644        let clone_into_cgroup = flags & CLONE_INTO_CGROUP != 0;
1645        let clone_clear_sighand = flags & (CLONE_CLEAR_SIGHAND as u64) != 0;
1646
1647        if clone_ptrace {
1648            track_stub!(TODO("https://fxbug.dev/322874630"), "CLONE_PTRACE");
1649        }
1650
1651        if clone_sysvsem {
1652            track_stub!(TODO("https://fxbug.dev/322875185"), "CLONE_SYSVSEM");
1653        }
1654
1655        if clone_into_cgroup {
1656            track_stub!(TODO("https://fxbug.dev/403612570"), "CLONE_INTO_CGROUP");
1657        }
1658
1659        if clone_sighand && !clone_vm {
1660            return error!(EINVAL);
1661        }
1662        if clone_clear_sighand && clone_sighand {
1663            return error!(EINVAL);
1664        }
1665        if clone_thread && !clone_sighand {
1666            return error!(EINVAL);
1667        }
1668
1669        if clone_pidfd && clone_thread {
1670            return error!(EINVAL);
1671        }
1672        if clone_pidfd && clone_parent_settid && user_parent_tid.addr() == user_pidfd.addr() {
1673            // `clone()` uses the same out-argument for these, so error out if they have the same
1674            // user address.
1675            return error!(EINVAL);
1676        }
1677
1678        if flags & !VALID_FLAGS != 0 {
1679            return error!(EINVAL);
1680        }
1681
1682        if clone_vm && !clone_thread {
1683            // TODO(https://fxbug.dev/42066087) Implement CLONE_VM for child processes (not just child
1684            // threads). Currently this executes CLONE_VM (explicitly passed to clone() or as
1685            // used by vfork()) as a fork (the VM in the child is copy-on-write) which is almost
1686            // always OK.
1687            //
1688            // CLONE_VM is primarily as an optimization to avoid making a copy-on-write version of a
1689            // process' VM that will be immediately replaced with a call to exec(). The main users
1690            // (libc and language runtimes) don't actually rely on the memory being shared between
1691            // the two processes. And the vfork() man page explicitly allows vfork() to be
1692            // implemented as fork() which is what we do here.
1693            if !clone_vfork {
1694                track_stub!(
1695                    TODO("https://fxbug.dev/322875227"),
1696                    "CLONE_VM without CLONE_THREAD or CLONE_VFORK"
1697                );
1698            }
1699        } else if clone_thread && !clone_vm {
1700            track_stub!(TODO("https://fxbug.dev/322875167"), "CLONE_THREAD without CLONE_VM");
1701            return error!(ENOSYS);
1702        }
1703
1704        if flags & !IMPLEMENTED_FLAGS != 0 {
1705            track_stub!(
1706                TODO("https://fxbug.dev/322875130"),
1707                "clone unknown flags",
1708                flags & !IMPLEMENTED_FLAGS
1709            );
1710            return error!(ENOSYS);
1711        }
1712
1713        let fs = if clone_fs { self.fs() } else { self.fs().fork() };
1714        let files = if clone_files {
1715            self.running_state().share_files()
1716        } else {
1717            self.running_state().fork_files()
1718        }
1719        .expect("Task must have FdTable");
1720
1721        let kernel = self.kernel();
1722
1723        let mut pids = kernel.pids.lock();
1724
1725        // Lock the cgroup process hierarchy so that the parent process cannot move to a different
1726        // cgroup while a new task or thread_group is created. This may be unnecessary if
1727        // CLONE_INTO_CGROUP is implemented and passed in.
1728        let mut cgroup2_pid_table = kernel.cgroups.lock_cgroup2_pid_table();
1729        // Create a `KernelSignal::Freeze` to put onto the new task, if the cgroup is frozen.
1730        let child_kernel_signals = cgroup2_pid_table
1731            .maybe_create_freeze_signal(&self.pid)
1732            .into_iter()
1733            .collect::<VecDeque<_>>();
1734
1735        let pid;
1736        let command;
1737        let creds;
1738        let scheduler_state;
1739        let no_new_privs;
1740        let seccomp_filters;
1741        let seccomp_state;
1742        let robust_list_head = RobustListHeadPtr::null(self);
1743        let child_signal_mask;
1744        let timerslack_ns;
1745        let uts_ns;
1746
1747        let TaskInfo { thread_group, memory_manager } = {
1748            // These variables hold the original parent in case we need to switch the parent of the
1749            // new task because of CLONE_PARENT.
1750            let weak_original_parent;
1751            let original_parent;
1752            // Whether this process may create processes during shutdown. Determined before
1753            // CLONE_PARENT switches to the original parent's state.
1754            let create_during_shutdown;
1755
1756            // Make sure to drop these locks ASAP to avoid inversion
1757            let (thread_group_state, creator_task) = {
1758                let thread_group_state = self.thread_group().write();
1759                create_during_shutdown = if thread_group_state.is_deferred_shutdown_process() {
1760                    CreateDuringShutdown::UntilDeadline
1761                } else {
1762                    CreateDuringShutdown::Never
1763                };
1764                if clone_parent {
1765                    // With the CLONE_PARENT flag, the parent of the new task is our parent
1766                    // instead of ourselves.
1767                    weak_original_parent =
1768                        thread_group_state.parent.clone().ok_or_else(|| errno!(EINVAL))?;
1769                    let creator_task = weak_original_parent.creator_task().cloned();
1770                    std::mem::drop(thread_group_state);
1771                    original_parent = weak_original_parent.upgrade();
1772                    (original_parent.write(), creator_task)
1773                } else {
1774                    (thread_group_state, Some(self.weak_task()))
1775                }
1776            };
1777
1778            scheduler_state = self.scheduler_state.lock().fork();
1779            let state = self.read();
1780
1781            no_new_privs = state.no_new_privs();
1782            seccomp_filters = state.seccomp_filters.clone();
1783            // Capture the seccomp state while holding the task lock so that it stays consistent
1784            // with `seccomp_filters`. A concurrent `SECCOMP_FILTER_FLAG_TSYNC` from a sibling
1785            // thread updates both under this task's write lock.
1786            seccomp_state = SeccompState::from(&self.seccomp_filter_state);
1787            child_signal_mask = state.signal_mask();
1788
1789            pid = pids.allocate_pid()?;
1790            command = self.command();
1791            creds = self.current_creds().clone();
1792            timerslack_ns = state.timerslack_ns;
1793
1794            uts_ns = if clone_newuts {
1795                security::check_task_capable(self, CAP_SYS_ADMIN)?;
1796                state.uts_ns.read().fork()
1797            } else {
1798                state.uts_ns.clone()
1799            };
1800
1801            if clone_thread {
1802                TaskInfo {
1803                    thread_group: self.thread_group().clone(),
1804                    memory_manager: self.mm().ok().cloned(),
1805                }
1806            } else {
1807                // Drop the lock on this task before entering `create_zircon_process`, because it will
1808                // take a lock on the new thread group, and locks on thread groups have a higher
1809                // priority than locks on the task in the thread group.
1810                std::mem::drop(state);
1811                let signal_actions = if clone_sighand {
1812                    self.thread_group().signal_actions.clone()
1813                } else if clone_clear_sighand {
1814                    let actions = self.thread_group().signal_actions.fork();
1815                    actions.reset_for_exec();
1816                    actions
1817                } else {
1818                    self.thread_group().signal_actions.fork()
1819                };
1820                let task_info = {
1821                    fuchsia_trace::duration!(CATEGORY_STARNIX, "create_zircon_process");
1822                    create_zircon_process(
1823                        kernel,
1824                        Some(thread_group_state),
1825                        pid.clone(),
1826                        child_exit_signal,
1827                        signal_actions,
1828                        command.clone(),
1829                        create_during_shutdown,
1830                    )?
1831                };
1832
1833                if let Some(parent) = &mut task_info.thread_group.write().parent {
1834                    parent.set_creator_task(creator_task);
1835                }
1836
1837                cgroup2_pid_table.inherit_cgroup(self.thread_group(), &task_info.thread_group);
1838
1839                task_info
1840            }
1841        };
1842
1843        // Drop the lock on the cgroup pid_table before creating the TaskBuilder.
1844        // If the TaskBuilder creation fails, the TaskBuilder is dropped, which calls
1845        // ThreadGroup::remove. ThreadGroup::remove takes the cgroup pid_table lock, causing
1846        // a cyclic lock dependency.
1847        std::mem::drop(cgroup2_pid_table);
1848
1849        // Only create the vfork event when the caller requested CLONE_VFORK.
1850        let vfork_event = if clone_vfork { Some(Arc::new(zx::Event::create())) } else { None };
1851
1852        // Clone running state in a nested scope to ensure that the RCU read scope is not held
1853        // across the release_on_error block.
1854        let abstract_socket_namespace;
1855        let abstract_vsock_namespace;
1856        {
1857            let running_state = self.running_state();
1858            abstract_socket_namespace = running_state.abstract_socket_namespace.clone();
1859            abstract_vsock_namespace = running_state.abstract_vsock_namespace.clone();
1860        }
1861
1862        let sid_pid = thread_group.read().session.clone();
1863
1864        let mut child = TaskBuilder::new(Task::new(
1865            pid,
1866            command,
1867            thread_group,
1868            files,
1869            memory_manager,
1870            fs,
1871            creds,
1872            abstract_socket_namespace,
1873            abstract_vsock_namespace,
1874            child_signal_mask,
1875            child_kernel_signals,
1876            vfork_event,
1877            scheduler_state,
1878            uts_ns,
1879            no_new_privs,
1880            seccomp_state,
1881            seccomp_filters,
1882            robust_list_head,
1883            timerslack_ns,
1884        ));
1885        let parent_cpuset_path = self.read().cpuset_path.clone();
1886        child.task.write().cpuset_path = parent_cpuset_path;
1887
1888        release_on_error!(child, {
1889            // Drop the pids lock as soon as possible after creating the child. Destroying the child
1890            // and removing it from the pids table itself requires the pids lock, so an early exit
1891            // would cause a self deadlock.
1892            pids.add_task(Arc::clone(&child.task));
1893
1894            // Child lock must be taken before this lock. Drop the lock on the task, take a writable
1895            // lock on the child and take the current state back.
1896
1897            #[cfg(any(test, debug_assertions))]
1898            {
1899                // Take the lock on the thread group and its child in the correct order to ensure
1900                // any wrong ordering will trigger the tracing-mutex at the right call site.
1901                if !clone_thread {
1902                    let _l1 = self.thread_group().read();
1903                    // This allow_subclass is safe because locking parent then child strictly
1904                    // follows the top-down traversal of the thread group tree, which cannot form
1905                    // cycles.
1906                    let _token = starnix_sync::allow_subclass();
1907                    let _l2 = child.thread_group().read();
1908                }
1909            }
1910
1911            if clone_thread {
1912                self.thread_group().add(Arc::clone(&child.task))?;
1913                std::mem::drop(pids);
1914            } else {
1915                child.thread_group().add(Arc::clone(&child.task))?;
1916                pids.attach_pgid(&child.thread_group().pgid(), child.thread_group());
1917                pids.attach_sid(&sid_pid, child.thread_group());
1918                std::mem::drop(pids);
1919
1920                // Inherit `controlling_terminal` from the parent now that `child` is attached to
1921                // `sid_pid`. Holding `child.thread_group().write()` across `terminal.read()`
1922                // ensures any concurrent terminal disassociation or steal either already updated
1923                // `terminal.write()` before this check or visits `child` afterward in
1924                // `sid_thread_groups`.
1925                if let Some(ct) = self.thread_group().controlling_terminal() {
1926                    let mut child_state = child.thread_group().write();
1927                    if child_state.session == sid_pid
1928                        && ct.terminal.read().controlling_session() == Some(&sid_pid)
1929                    {
1930                        child_state.controlling_terminal = Some(ct);
1931                    }
1932                }
1933
1934                // These manipulations of the signal handling state appear to be related to
1935                // CLONE_SIGHAND and CLONE_VM rather than CLONE_THREAD. However, Starnix does not
1936                // support all combinations of these flags, so performing these operations here
1937                // might be sufficient unless a test requires moving this logic.
1938                let (sigaltstack, signal_mask) = {
1939                    let state = self.read();
1940                    (state.sigaltstack(), state.signal_mask())
1941                };
1942                let mut child_state = child.write();
1943                child_state.set_sigaltstack(sigaltstack);
1944                child_state.set_signal_mask(signal_mask);
1945            }
1946
1947            if !clone_vm {
1948                // Running threads in the same process with different MemoryManagers is not
1949                // supported.
1950                assert!(!clone_thread);
1951                let child_mm = MemoryManager::snapshot_of(
1952                    self.mm()?,
1953                    child.thread_group.root_vmar.unowned(),
1954                    self.thread_state.arch_width(),
1955                )?;
1956                child.running_state()?.mm.update(Some(child_mm));
1957            }
1958
1959            if clone_parent_settid {
1960                self.write_object(user_parent_tid, &child.tid.id)?;
1961            }
1962
1963            if clone_child_cleartid {
1964                child.write().clear_child_tid = user_child_tid;
1965            }
1966
1967            if clone_child_settid {
1968                child.write_object(user_child_tid, &child.tid.id)?;
1969            }
1970
1971            if clone_pidfd {
1972                let file = new_pidfd(self, child.pid.clone(), OpenFlags::empty())?;
1973                let pidfd = self.add_file(file, FdFlags::CLOEXEC)?;
1974                self.write_object(user_pidfd, &pidfd)?;
1975            }
1976
1977            // TODO(https://fxbug.dev/42066087): We do not support running different processes with
1978            // the same MemoryManager. Instead, we implement a rough approximation of that behavior
1979            // by making a copy-on-write clone of the memory from the original process.
1980            if clone_vm && !clone_thread {
1981                let child_mm = MemoryManager::snapshot_of(
1982                    self.mm()?,
1983                    child.thread_group.root_vmar.unowned(),
1984                    self.thread_state.arch_width(),
1985                )?;
1986                child.running_state()?.mm.update(Some(child_mm));
1987            }
1988
1989            child.thread_state = self.thread_state.snapshot::<HeapRegs>();
1990            Ok(())
1991        });
1992
1993        // Take the lock on thread group and task in the correct order to ensure any wrong ordering
1994        // will trigger the tracing-mutex at the right call site.
1995        #[cfg(any(test, debug_assertions))]
1996        {
1997            let _l1 = child.thread_group().read();
1998            let _l2 = child.read();
1999        }
2000
2001        Ok(child)
2002    }
2003
2004    /// Sets the stop state (per set_stopped), and also notifies all listeners,
2005    /// including the parent process and the tracer if appropriate.
2006    pub fn set_stopped_and_notify(&self, stopped: StopState, siginfo: Option<SignalInfo>) {
2007        let maybe_signal_info = {
2008            let mut state = self.write();
2009            state.set_stopped(stopped, siginfo, Some(self), None);
2010            state.prepare_signal_info(stopped)
2011        };
2012
2013        if let Some((tracer, signal_info)) = maybe_signal_info {
2014            if let Some(tracer) = tracer.upgrade() {
2015                tracer.write().send_signal(signal_info);
2016            }
2017        }
2018
2019        if !stopped.is_in_progress() {
2020            let parent = self.thread_group().read().parent.clone();
2021            if let Some(parent) = parent {
2022                parent
2023                    .upgrade()
2024                    .write()
2025                    .lifecycle_waiters
2026                    .notify_value(ThreadGroupLifecycleWaitValue::ChildStatus);
2027            }
2028        }
2029    }
2030
2031    /// Finalizes the stop state of the task, and if the task should be stopped,
2032    /// blocks the execution of `current_task` as long as the task is stopped and
2033    /// not terminated.
2034    ///
2035    /// Returns true if the task was stopped and blocked (and has now woken up),
2036    /// or false if it was not stopped and returned immediately.
2037    pub fn block_if_stopped(&mut self) -> bool {
2038        if !self.finalize_stop_state() {
2039            return false;
2040        }
2041        self.block_while_stopped();
2042
2043        // When coming back from a stop, write modified register state to the ThreadState.
2044        let captured_state = self.write().take_captured_state();
2045        if let Some(captured) = captured_state {
2046            if captured.dirty {
2047                self.thread_state.replace_registers(&captured.thread_state);
2048            }
2049        }
2050        true
2051    }
2052
2053    /// If the task is stopping, set it as stopped. Return whether the caller should stop.
2054    fn finalize_stop_state(&self) -> bool {
2055        let stopped = self.load_stopped();
2056
2057        // Stopping because the thread group is stopping.
2058        // Try to flip to GroupStopped - will fail if we shouldn't.
2059        if self.thread_group().set_stopped(StopState::GroupStopped, None, true)
2060            == StopState::GroupStopped
2061        {
2062            let signal = self.thread_group().read().last_signal.clone();
2063            // stopping because the thread group has stopped
2064            let event = Some(PtraceEventData::new_from_event(PtraceEvent::Stop, 0));
2065            self.write().set_stopped(StopState::GroupStopped, signal, Some(self), event);
2066            return true;
2067        }
2068
2069        // Stopping because the task is stopping
2070        if stopped.is_stopping_or_stopped() {
2071            if let Ok(stopped) = stopped.finalize() {
2072                self.set_stopped_and_notify(stopped, None);
2073            }
2074            return true;
2075        }
2076
2077        false
2078    }
2079
2080    /// Block the execution of `current_task` as long as the task is stopped and
2081    /// not terminated.
2082    fn block_while_stopped(&mut self) {
2083        let waiter = Waiter::new();
2084        loop {
2085            // If we've exited, unstop the threads and return without notifying
2086            // waiters.
2087            if self.is_exitted() {
2088                self.thread_group().set_stopped(StopState::ForceAwake, None, false);
2089                self.write().set_stopped(StopState::ForceAwake, None, Some(self), None);
2090                return;
2091            }
2092
2093            if self.wake_or_wait_until_unstopped_async(&waiter) {
2094                return;
2095            }
2096
2097            waiter.stop(self);
2098
2099            // Maybe go from stopping to stopped, if we are currently stopping
2100            // again.
2101            self.finalize_stop_state();
2102        }
2103    }
2104
2105    /// Causes the current thread's thread group to exit, terminating sibling
2106    /// tasks before notifying any ptracer of this task's exit.
2107    pub fn kill_thread_group(&mut self, exit_status: ExitStatus) {
2108        Arc::clone(self.thread_group()).kill(exit_status, Some(self));
2109    }
2110
2111    /// The flags indicates only the flags as in clone3(), and does not use the low 8 bits for the
2112    /// exit signal as in clone().
2113    pub fn clone_task_builder_for_test(
2114        &self,
2115        flags: u64,
2116        exit_signal: Option<Signal>,
2117    ) -> TaskBuilder {
2118        let result = self
2119            .clone_task(
2120                flags,
2121                exit_signal,
2122                UserRef::default(),
2123                UserRef::default(),
2124                UserRef::default(),
2125            )
2126            .expect("failed to create task in test");
2127        result.task.write().set_spawned();
2128        result
2129    }
2130
2131    /// The flags indicates only the flags as in clone3(), and does not use the low 8 bits for the
2132    /// exit signal as in clone().
2133    pub fn clone_task_for_test(
2134        &self,
2135        flags: u64,
2136        exit_signal: Option<Signal>,
2137    ) -> crate::testing::AutoReleasableTask {
2138        self.clone_task_builder_for_test(flags, exit_signal).into()
2139    }
2140
2141    // See "Ptrace access mode checking" in https://man7.org/linux/man-pages/man2/ptrace.2.html
2142    pub fn check_ptrace_access_mode(
2143        &self,
2144        mode: PtraceAccessMode,
2145        target: &Task,
2146    ) -> Result<(), Errno> {
2147        // (1)  If the calling thread and the target thread are in the same
2148        //      thread group, access is always allowed.
2149        if self.pid == target.pid {
2150            return Ok(());
2151        }
2152
2153        // (2)  If the access mode specifies PTRACE_MODE_FSCREDS, then, for
2154        //      the check in the next step, employ the caller's filesystem
2155        //      UID and GID.  (As noted in credentials(7), the filesystem
2156        //      UID and GID almost always have the same values as the
2157        //      corresponding effective IDs.)
2158        //
2159        //      Otherwise, the access mode specifies PTRACE_MODE_REALCREDS,
2160        //      so use the caller's real UID and GID for the checks in the
2161        //      next step.  (Most APIs that check the caller's UID and GID
2162        //      use the effective IDs.  For historical reasons, the
2163        //      PTRACE_MODE_REALCREDS check uses the real IDs instead.)
2164        let (uid, gid) = if mode.contains(PTRACE_MODE_FSCREDS) {
2165            let fscred = self.current_creds().as_fscred();
2166            (fscred.uid, fscred.gid)
2167        } else if mode.contains(PTRACE_MODE_REALCREDS) {
2168            let creds = self.current_creds();
2169            (creds.uid, creds.gid)
2170        } else {
2171            unreachable!();
2172        };
2173
2174        // (3)  Deny access if neither of the following is true:
2175        //
2176        //      -  The real, effective, and saved-set user IDs of the target
2177        //         match the caller's user ID, and the real, effective, and
2178        //         saved-set group IDs of the target match the caller's
2179        //         group ID.
2180        //
2181        //      -  The caller has the CAP_SYS_PTRACE capability in the user
2182        //         namespace of the target.
2183        let creds_match = {
2184            let check = |target_creds: &Credentials| {
2185                target_creds.uid == uid
2186                    && target_creds.euid == uid
2187                    && target_creds.saved_uid == uid
2188                    && target_creds.gid == gid
2189                    && target_creds.egid == gid
2190                    && target_creds.saved_gid == gid
2191            };
2192            if mode.contains(PtraceAccessMode::ATTACH) {
2193                check(&target.persistent_info.lock_creds())
2194            } else {
2195                check(&target.real_creds())
2196            }
2197        };
2198        if !creds_match {
2199            security::check_task_ptrace_capable(self, mode)?;
2200        }
2201
2202        // (4)  Deny access if the target process "dumpable" attribute has a
2203        //      value other than 1 (SUID_DUMP_USER; see the discussion of
2204        //      PR_SET_DUMPABLE in prctl(2)), and the caller does not have
2205        //      the CAP_SYS_PTRACE capability in the user namespace of the
2206        //      target process.
2207        //      Kernel threads and zombies do not have an `mm`, and are treated
2208        //      as dumpable like in Linux's `__ptrace_may_access`.
2209        if let Ok(mm) = target.mm() {
2210            let dumpable = mm.dumpable.load();
2211            match dumpable {
2212                DumpPolicy::User => (),
2213                DumpPolicy::Disable => {
2214                    security::check_task_ptrace_capable(self, mode)?;
2215                }
2216            }
2217        }
2218
2219        // (5)  The kernel LSM security_ptrace_access_check() interface is
2220        //      invoked to see if ptrace access is permitted.
2221        security::ptrace_access_check(self, target, mode)?;
2222
2223        // (6)  If access has not been denied by any of the preceding steps,
2224        //      then access is allowed.
2225        Ok(())
2226    }
2227
2228    pub fn can_signal(
2229        &self,
2230        target: &Task,
2231        unchecked_signal: UncheckedSignal,
2232    ) -> Result<(), Errno> {
2233        // If both the tasks share a thread group the signal can be sent. This is not documented
2234        // in kill(2) because kill does not support task-level granularity in signal sending.
2235        if self.thread_group == target.thread_group {
2236            return Ok(());
2237        }
2238
2239        let self_creds = self.current_creds();
2240        let target_creds = target.real_creds();
2241        // From https://man7.org/linux/man-pages/man2/kill.2.html:
2242        //
2243        // > For a process to have permission to send a signal, it must either be
2244        // > privileged (under Linux: have the CAP_KILL capability in the user
2245        // > namespace of the target process), or the real or effective user ID of
2246        // > the sending process must equal the real or saved set- user-ID of the
2247        // > target process.
2248        //
2249        // Returns true if the credentials are considered to have the same user ID.
2250        if self_creds.euid == target_creds.saved_uid
2251            || self_creds.euid == target_creds.uid
2252            || self_creds.uid == target_creds.uid
2253            || self_creds.uid == target_creds.saved_uid
2254        {
2255            return Ok(());
2256        }
2257
2258        if Signal::try_from(unchecked_signal) == Ok(SIGCONT) {
2259            let target_session = target.thread_group().read().session.clone();
2260            let self_session = self.thread_group().read().session.clone();
2261            if target_session == self_session {
2262                return Ok(());
2263            }
2264        }
2265
2266        security::check_task_capable(self, CAP_KILL)
2267    }
2268}
2269
2270impl ArchSpecific for CurrentTask {
2271    fn is_arch32(&self) -> bool {
2272        self.thread_state.is_arch32()
2273    }
2274}
2275
2276impl MemoryAccessor for CurrentTask {
2277    fn read_memory<'a>(
2278        &self,
2279        addr: UserAddress,
2280        bytes: &'a mut [MaybeUninit<u8>],
2281    ) -> Result<&'a mut [u8], Errno> {
2282        self.mm()?.unified_read_memory(self, addr, bytes)
2283    }
2284
2285    fn read_memory_partial_until_null_byte<'a>(
2286        &self,
2287        addr: UserAddress,
2288        bytes: &'a mut [MaybeUninit<u8>],
2289    ) -> Result<&'a mut [u8], Errno> {
2290        self.mm()?.unified_read_memory_partial_until_null_byte(self, addr, bytes)
2291    }
2292
2293    fn read_memory_partial<'a>(
2294        &self,
2295        addr: UserAddress,
2296        bytes: &'a mut [MaybeUninit<u8>],
2297    ) -> Result<&'a mut [u8], Errno> {
2298        self.mm()?.unified_read_memory_partial(self, addr, bytes)
2299    }
2300
2301    fn write_memory(&self, addr: UserAddress, bytes: &[u8]) -> Result<usize, Errno> {
2302        self.mm()?.unified_write_memory(self, addr, bytes)
2303    }
2304
2305    fn write_memory_partial(&self, addr: UserAddress, bytes: &[u8]) -> Result<usize, Errno> {
2306        self.mm()?.unified_write_memory_partial(self, addr, bytes)
2307    }
2308
2309    fn zero(&self, addr: UserAddress, length: usize) -> Result<usize, Errno> {
2310        self.mm()?.unified_zero(self, addr, length)
2311    }
2312}
2313
2314impl TaskMemoryAccessor for CurrentTask {
2315    fn maximum_valid_address(&self) -> Option<UserAddress> {
2316        self.mm().ok().map(|mm| mm.maximum_valid_user_address)
2317    }
2318
2319    fn ensure_buffers_mapped_in_user_vmar(
2320        &self,
2321        buffers: &[UserBuffer],
2322        access: MappingAccess,
2323    ) -> Result<(), Errno> {
2324        let mut ranges = buffers
2325            .iter()
2326            .filter(|b| !b.is_empty())
2327            .map(|b| (b.address, Some(b.length)))
2328            .peekable();
2329        if ranges.peek().is_some() {
2330            self.mm()?.ensure_ranges_mapped_in_user_vmar_for_access(ranges, access)?;
2331        }
2332        Ok(())
2333    }
2334}
2335
2336pub enum ExceptionResult {
2337    /// The exception was handled and no further action is required.
2338    Handled,
2339
2340    // The exception generated a signal that should be delivered.
2341    Signal(SignalInfo),
2342}
2343
2344fn split_path(path: &FsStr) -> LookupVec<&FsStr> {
2345    path.split(|c| *c == b'/').filter(|p| !p.is_empty()).map(<&FsStr>::from).collect()
2346}
2347
2348#[cfg(test)]
2349mod tests {
2350    use super::*;
2351    use crate::ptrace::{PtraceAttachType, ptrace_attach};
2352    use crate::testing::{create_task, spawn_kernel_and_run};
2353    use starnix_uapi::CLONE_FS;
2354    use starnix_uapi::auth::{Credentials, PTRACE_MODE_READ_FSCREDS};
2355    use std::sync::Arc;
2356
2357    // This test will run `override_creds` and check it doesn't crash. This ensures that the
2358    // delegation to `override_creds_async` is correct.
2359    #[::fuchsia::test]
2360    async fn test_override_creds_can_delegate_to_async_version() {
2361        spawn_kernel_and_run(async move |current_task| {
2362            assert_eq!(current_task.override_creds(Credentials::root(), || 0), 0);
2363        })
2364        .await;
2365    }
2366
2367    // Another thread may hold a transient strong reference to the `TaskRunningState` of a task
2368    // while it exits (e.g. `Task::interrupt()`). The `FsContext` must still be released by
2369    // `exit()` itself rather than by whoever drops the last `TaskRunningState` reference, since
2370    // dropping it can tear down a whole mount namespace and acquire `DirEntry` locks.
2371    #[::fuchsia::test]
2372    async fn test_exit_releases_fs_while_running_state_is_referenced() {
2373        spawn_kernel_and_run(async move |current_task| {
2374            let task = create_task(current_task.kernel(), "task");
2375            let running_state = task.task.running_state().expect("task should be running");
2376            let fs = Arc::downgrade(&task.fs());
2377
2378            // Releasing the `AutoReleasableTask` calls `CurrentTask::exit()`.
2379            std::mem::drop(task);
2380
2381            assert!(running_state.fs().is_err());
2382            assert!(fs.upgrade().is_none(), "FsContext should be dropped by exit()");
2383        })
2384        .await;
2385    }
2386
2387    #[::fuchsia::test]
2388    async fn test_has_shared_fs_ignores_transient_refs() {
2389        spawn_kernel_and_run(async move |current_task| {
2390            assert!(!current_task.has_shared_fs());
2391
2392            let transient_fs = current_task.fs();
2393            assert!(!current_task.has_shared_fs());
2394            std::mem::drop(transient_fs);
2395        })
2396        .await;
2397    }
2398
2399    #[::fuchsia::test]
2400    async fn test_has_shared_fs_clone_and_unshare() {
2401        spawn_kernel_and_run(async move |current_task| {
2402            let child = current_task.clone_task_for_test(CLONE_FS as u64, Some(SIGCHLD));
2403            assert!(current_task.has_shared_fs());
2404            assert!(child.has_shared_fs());
2405
2406            child.unshare_fs();
2407            assert!(!current_task.has_shared_fs());
2408            assert!(!child.has_shared_fs());
2409        })
2410        .await;
2411    }
2412
2413    #[::fuchsia::test]
2414    async fn test_has_shared_fs_cleared_on_peer_exit() {
2415        spawn_kernel_and_run(async move |current_task| {
2416            let child = current_task.clone_task_for_test(CLONE_FS as u64, Some(SIGCHLD));
2417            let child_running_state =
2418                child.task.running_state().expect("child task should be running");
2419            assert!(current_task.has_shared_fs());
2420
2421            std::mem::drop(child);
2422            assert!(!current_task.has_shared_fs());
2423            std::mem::drop(child_running_state);
2424        })
2425        .await;
2426    }
2427
2428    #[::fuchsia::test]
2429    async fn test_check_ptrace_access_mode() {
2430        spawn_kernel_and_run(async move |current_task| {
2431            let system_tg = current_task.kernel().kthreads.system_thread_group();
2432            let system_task = system_tg.leader.get_task().unwrap();
2433            let mode = PTRACE_MODE_READ_FSCREDS;
2434
2435            // Even root cannot ptrace_attach to the kernel system_task (which has no mm).
2436            assert_eq!(
2437                ptrace_attach(
2438                    current_task,
2439                    &system_tg.leader,
2440                    PtraceAttachType::Attach,
2441                    UserAddress::NULL
2442                ),
2443                error!(EPERM)
2444            );
2445
2446            // Root has CAP_SYS_PTRACE and passes check_ptrace_access_mode on a kernel thread.
2447            assert_eq!(current_task.check_ptrace_access_mode(mode, &system_task), Ok(()));
2448
2449            // Unprivileged caller cannot access a root-owned kernel thread.
2450            let unpriv_creds = Arc::new(Credentials::with_ids(1000, 1000));
2451            let res = current_task.override_creds(unpriv_creds.clone(), || {
2452                current_task.check_ptrace_access_mode(mode, &system_task)
2453            });
2454            assert_eq!(res, error!(EPERM));
2455
2456            // Non-dumpable target requires CAP_SYS_PTRACE even with matching UID/GID.
2457            // Changing effective/filesystem UID/GID should have reset `dumpable` to
2458            // `DumpPolicy::Disable`.
2459            let target_task = create_task(&current_task.kernel(), "target");
2460            target_task.set_creds(Credentials::with_ids(1000, 1000));
2461            assert_eq!(target_task.mm().unwrap().dumpable.load(), DumpPolicy::Disable);
2462
2463            let res = current_task.override_creds(unpriv_creds.clone(), || {
2464                current_task.check_ptrace_access_mode(mode, &target_task)
2465            });
2466            assert_eq!(res, error!(EPERM));
2467
2468            assert_eq!(current_task.check_ptrace_access_mode(mode, &target_task), Ok(()));
2469
2470            // Non-running (exited/zombie) task has no `mm` and is treated as dumpable.
2471            let exited_task_ref = Arc::clone(&target_task.task);
2472            std::mem::drop(target_task);
2473            assert!(exited_task_ref.mm().is_err());
2474
2475            let res = current_task.override_creds(unpriv_creds, || {
2476                current_task.check_ptrace_access_mode(mode, &exited_task_ref)
2477            });
2478            assert_eq!(res, Ok(()));
2479
2480            let other_creds = Arc::new(Credentials::with_ids(2000, 2000));
2481            let res = current_task.override_creds(other_creds, || {
2482                current_task.check_ptrace_access_mode(mode, &exited_task_ref)
2483            });
2484            assert_eq!(res, error!(EPERM));
2485
2486            assert_eq!(current_task.check_ptrace_access_mode(mode, &exited_task_ref), Ok(()));
2487        })
2488        .await;
2489    }
2490}