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