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