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