Skip to main content

starnix_core/security/
hooks.rs

1// Copyright 2024 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
5// TODO(https://github.com/rust-lang/rust/issues/39371): remove
6#![allow(non_upper_case_globals)]
7
8use super::selinux_hooks::audit::Auditable;
9use super::{
10    BinderConnectionState, BpfMapState, BpfProgState, FileObjectState, FileSystemState,
11    KernelState, PerfEventState, common_cap, selinux_hooks, yama,
12};
13use crate::mm::{Mapping, MappingOptions, ProtectionFlags};
14use crate::perf::PerfEventFile;
15use crate::security::selinux_hooks::current_task_state;
16use crate::task::loader::ResolvedElf;
17use crate::task::{CurrentTask, Kernel, Task};
18use crate::vfs::fs_args::MountParams;
19use crate::vfs::socket::{
20    Socket, SocketAddress, SocketDomain, SocketFile, SocketPeer, SocketProtocol,
21    SocketShutdownFlags, SocketType,
22};
23use crate::vfs::{
24    DirEntryHandle, DowncastedFile, FileHandle, FileObject, FileSystem, FileSystemHandle,
25    FileSystemOps, FsNode, FsStr, FsString, Mount, NamespaceNode, ValueOrSize, XattrOp,
26};
27use ebpf::MapFlags;
28use linux_uapi::{
29    perf_event_attr, perf_type_id, perf_type_id_PERF_TYPE_BREAKPOINT,
30    perf_type_id_PERF_TYPE_HARDWARE, perf_type_id_PERF_TYPE_HW_CACHE, perf_type_id_PERF_TYPE_RAW,
31    perf_type_id_PERF_TYPE_SOFTWARE, perf_type_id_PERF_TYPE_TRACEPOINT,
32};
33use selinux::{FileSystemMountOptions, InitialSid, SecurityPermission, SecurityServer, TaskAttrs};
34use starnix_logging::{CATEGORY_STARNIX_SECURITY, log_debug};
35use starnix_uapi::arc_key::WeakKey;
36use starnix_uapi::auth::{Credentials, PtraceAccessMode};
37use starnix_uapi::device_id::DeviceId;
38use starnix_uapi::errors::Errno;
39use starnix_uapi::file_mode::{Access, FileMode};
40use starnix_uapi::mount_flags::MountFlags;
41use starnix_uapi::open_flags::OpenFlags;
42use starnix_uapi::signals::Signal;
43use starnix_uapi::syslog::SyslogAction;
44use starnix_uapi::unmount_flags::UnmountFlags;
45use starnix_uapi::user_address::UserAddress;
46use starnix_uapi::{bpf_cmd, error, rlimit};
47use std::ops::Range;
48use std::sync::Arc;
49use syncio::zxio_node_attr_has_t;
50use zerocopy::FromBytes;
51
52macro_rules! track_hook_duration {
53    ($cname:literal) => {
54        fuchsia_trace::duration!(CATEGORY_STARNIX_SECURITY, $cname);
55    };
56}
57
58bitflags::bitflags! {
59    /// The flags about which permissions should be checked when opening an FsNode. Used in the
60    /// `fs_node_permission()` hook.
61    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
62    pub struct PermissionFlags: u32 {
63        const EXEC = 1 as u32;
64        const WRITE = 2 as u32;
65        const READ = 4 as u32;
66        const APPEND = 8 as u32;
67
68        // Internal flag used to indicate that the check is being made on behalf of userspace e.g.
69        // via the `access()` syscall.
70        const ACCESS = 16 as u32;
71    }
72}
73
74impl PermissionFlags {
75    pub fn as_access(&self) -> Access {
76        let mut access = Access::empty();
77        if self.contains(PermissionFlags::READ) {
78            access |= Access::READ;
79        }
80        if self.contains(PermissionFlags::WRITE) {
81            // `APPEND` only modifies the behaviour of `WRITE` if set, so it is sufficient to only
82            // consider whether `WRITE` is set, to calculate the `Access` flags.
83            access |= Access::WRITE;
84        }
85        if self.contains(PermissionFlags::EXEC) {
86            access |= Access::EXEC;
87        }
88        access
89    }
90}
91
92impl From<Access> for PermissionFlags {
93    fn from(access: Access) -> Self {
94        // Note that `Access` doesn't have an `append` bit.
95        let mut permissions = PermissionFlags::empty();
96        if access.contains(Access::READ) {
97            permissions |= PermissionFlags::READ;
98        }
99        if access.contains(Access::WRITE) {
100            permissions |= PermissionFlags::WRITE;
101        }
102        if access.contains(Access::EXEC) {
103            permissions |= PermissionFlags::EXEC;
104        }
105        permissions
106    }
107}
108
109impl From<ProtectionFlags> for PermissionFlags {
110    fn from(protection_flags: ProtectionFlags) -> Self {
111        let mut flags = PermissionFlags::empty();
112        if protection_flags.contains(ProtectionFlags::READ) {
113            flags |= PermissionFlags::READ;
114        }
115        if protection_flags.contains(ProtectionFlags::WRITE) {
116            flags |= PermissionFlags::WRITE;
117        }
118        if protection_flags.contains(ProtectionFlags::EXEC) {
119            flags |= PermissionFlags::EXEC;
120        }
121        flags
122    }
123}
124
125impl From<OpenFlags> for PermissionFlags {
126    fn from(flags: OpenFlags) -> Self {
127        let mut permissions = PermissionFlags::empty();
128        if flags.can_read() {
129            permissions |= PermissionFlags::READ;
130        }
131        if flags.can_write() {
132            permissions |= PermissionFlags::WRITE;
133            if flags.contains(OpenFlags::APPEND) {
134                permissions |= PermissionFlags::APPEND;
135            }
136        }
137        permissions
138    }
139}
140
141impl From<MapFlags> for PermissionFlags {
142    fn from(bpf_flags: MapFlags) -> Self {
143        if bpf_flags.contains(MapFlags::SyscallReadOnly) {
144            PermissionFlags::READ
145        } else if bpf_flags.contains(MapFlags::SyscallWriteOnly) {
146            PermissionFlags::WRITE
147        } else {
148            PermissionFlags::READ | PermissionFlags::WRITE
149        }
150    }
151}
152
153/// The flags about the PerfEvent types.
154#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
155pub enum PerfEventType {
156    Hardware,
157    Software,
158    Tracepoint,
159    Raw,
160    HwCache,
161    Breakpoint,
162}
163
164// TODO(https://github.com/rust-lang/rust/issues/39371): remove
165#[allow(non_upper_case_globals)]
166impl TryFrom<perf_type_id> for PerfEventType {
167    type Error = Errno;
168
169    fn try_from(type_id: perf_type_id) -> Result<Self, Errno> {
170        match type_id {
171            perf_type_id_PERF_TYPE_HARDWARE => Ok(Self::Hardware),
172            perf_type_id_PERF_TYPE_SOFTWARE => Ok(Self::Software),
173            perf_type_id_PERF_TYPE_TRACEPOINT => Ok(Self::Tracepoint),
174            perf_type_id_PERF_TYPE_RAW => Ok(Self::Raw),
175            perf_type_id_PERF_TYPE_HW_CACHE => Ok(Self::HwCache),
176            perf_type_id_PERF_TYPE_BREAKPOINT => Ok(Self::Breakpoint),
177            _ => {
178                return error!(ENOTSUP);
179            }
180        }
181    }
182}
183
184/// The target task type. Used in the `check_perf_event_open_access` LSM hook.
185#[derive(PartialEq, Eq)]
186pub enum TargetTaskType<'a> {
187    /// Monitor all tasks/activities.
188    AllTasks,
189    /// Only monitor the current task.
190    CurrentTask,
191    /// Only monitor a specific task.
192    Task(&'a Task),
193}
194
195/// Executes the `hook` closure if SELinux is enabled, and has a policy loaded.
196/// If SELinux is not enabled, or has no policy loaded, then the `default` closure is executed,
197/// and its result returned.
198fn if_selinux_else<F, R, D>(task: &Task, hook: F, default: D) -> R
199where
200    F: FnOnce(&Arc<SecurityServer>) -> R,
201    D: Fn() -> R,
202{
203    if let Some(state) = task.kernel().security_state.state.as_ref() {
204        if state.has_policy() { hook(&state.server) } else { default() }
205    } else {
206        default()
207    }
208}
209
210/// Specialization of `if_selinux_else(...)` for hooks which return a `Result<..., Errno>`, that
211/// arranges to return a default `Ok(...)` result value if SELinux is not enabled, or not yet
212/// configured with a policy.
213fn if_selinux_else_default_ok<R, F>(task: &Task, hook: F) -> Result<R, Errno>
214where
215    F: FnOnce(&Arc<SecurityServer>) -> Result<R, Errno>,
216    R: Default,
217{
218    if_selinux_else(task, hook, || Ok(R::default()))
219}
220
221/// Returns the security state structure for the kernel, based on the supplied "selinux" argument
222/// contents.
223pub fn kernel_init_security(
224    enabled: bool,
225    options: String,
226    exceptions: Vec<String>,
227    inspect_node: &fuchsia_inspect::Node,
228) -> KernelState {
229    track_hook_duration!("security.hooks.kernel_init_security");
230    KernelState {
231        state: enabled
232            .then(|| selinux_hooks::kernel_init_security(options, exceptions, inspect_node)),
233    }
234}
235
236/// Checks whether the given `current_task` can become the binder context manager.
237/// Corresponds to the `binder_set_context_mgr` hook.
238pub fn binder_set_context_mgr(current_task: &CurrentTask) -> Result<(), Errno> {
239    track_hook_duration!("security.hooks.binder_set_context_mgr");
240    if_selinux_else_default_ok(current_task, |security_server| {
241        selinux_hooks::binder::binder_set_context_mgr(security_server, current_task)
242    })
243}
244
245/// Checks whether the given `current_task` can perform a transaction to `target_task`.
246/// Corresponds to the `binder_transaction` hook.
247pub fn binder_transaction(
248    current_task: &CurrentTask,
249    target_task: &Task,
250    connection_state: &BinderConnectionState,
251) -> Result<(), Errno> {
252    track_hook_duration!("security.hooks.binder_transaction");
253    if_selinux_else_default_ok(current_task, |security_server| {
254        selinux_hooks::binder::binder_transaction(
255            security_server,
256            &connection_state.state,
257            current_task,
258            target_task,
259        )
260    })
261}
262
263/// Checks whether the given `current_task` can transfer Binder objects to `target_task`.
264/// Corresponds to the `binder_transfer_binder` hook.
265pub fn binder_transfer_binder(current_task: &CurrentTask, target_task: &Task) -> Result<(), Errno> {
266    track_hook_duration!("security.hooks.binder_transfer_binder");
267    if_selinux_else_default_ok(current_task, |security_server| {
268        selinux_hooks::binder::binder_transfer_binder(security_server, current_task, target_task)
269    })
270}
271
272/// Checks whether the given `receiving_task` can receive `file` in a Binder transaction.
273/// Corresponds to the `binder_transfer_file` hook.
274pub fn binder_transfer_file(
275    current_task: &CurrentTask,
276    receiving_task: &Task,
277    file: &FileObject,
278) -> Result<(), Errno> {
279    track_hook_duration!("security.hooks.binder_transfer_file");
280    if_selinux_else_default_ok(current_task, |security_server| {
281        selinux_hooks::binder::binder_transfer_file(
282            security_server,
283            current_task,
284            receiving_task,
285            file,
286        )
287    })
288}
289
290/// Returns the serialized Security Context associated with the specified state.
291/// If the state's SID cannot be resolved then None is returned.
292pub fn binder_get_context(
293    current_task: &CurrentTask,
294    connection_state: &BinderConnectionState,
295) -> Option<Vec<u8>> {
296    track_hook_duration!("security.hooks.binder_get_context");
297    if_selinux_else(
298        current_task,
299        |security_server| {
300            selinux_hooks::binder::binder_get_context(&security_server, &connection_state.state)
301        },
302        || None,
303    )
304}
305
306/// Consumes the mount options from the supplied `MountParams` and returns the security mount
307/// options for the given `MountParams`.
308/// Corresponds to the `sb_eat_lsm_opts` hook.
309pub fn sb_eat_lsm_opts(
310    kernel: &Kernel,
311    mount_params: &mut MountParams,
312) -> Result<FileSystemMountOptions, Errno> {
313    track_hook_duration!("security.hooks.sb_eat_lsm_opts");
314    if kernel.security_state.state.is_some() {
315        return selinux_hooks::superblock::sb_eat_lsm_opts(mount_params);
316    }
317    Ok(FileSystemMountOptions::default())
318}
319
320/// Returns security state to associate with a filesystem based on the supplied mount options.
321/// This sits somewhere between `fs_context_parse_param()` and `sb_set_mnt_opts()` in function.
322pub fn file_system_init_security(
323    mount_options: &FileSystemMountOptions,
324    ops: &dyn FileSystemOps,
325) -> Result<FileSystemState, Errno> {
326    track_hook_duration!("security.hooks.file_system_init_security");
327    Ok(FileSystemState {
328        state: selinux_hooks::superblock::file_system_init_security(mount_options, ops)?,
329    })
330}
331
332/// Gives the hooks subsystem an opportunity to note that the new `file_system` needs labeling, if
333/// SELinux is enabled, but no policy has yet been loaded.
334// TODO: https://fxbug.dev/366405587 - Merge this logic into `file_system_resolve_security()` and
335// remove this extra hook.
336pub fn file_system_post_init_security(kernel: &Kernel, file_system: &FileSystemHandle) {
337    track_hook_duration!("security.hooks.file_system_post_init_security");
338    if let Some(state) = &kernel.security_state.state {
339        if !state.has_policy() {
340            // TODO: https://fxbug.dev/367585803 - Revise locking to guard against a policy load
341            // sneaking in, in-between `has_policy()` and this `insert()`.
342            log_debug!("Queuing {} FileSystem for labeling", file_system.name());
343            state.pending_file_systems.lock().insert(WeakKey::from(&file_system));
344        }
345    }
346}
347
348/// Resolves the labeling scheme and arguments for the `file_system`, based on the loaded policy.
349/// If no policy has yet been loaded then no work is done, and the `file_system` will instead be
350/// labeled when a policy is first loaded.
351/// If the `file_system` was already labeled then no further work is done.
352pub fn file_system_resolve_security(
353    current_task: &CurrentTask,
354    file_system: &FileSystemHandle,
355) -> Result<(), Errno> {
356    track_hook_duration!("security.hooks.file_system_resolve_security");
357    if_selinux_else_default_ok(current_task, |security_server| {
358        selinux_hooks::superblock::file_system_resolve_security(
359            security_server,
360            current_task,
361            file_system,
362        )
363    })
364}
365
366/// Used to return an extended attribute name and value to apply to a [`crate::vfs::FsNode`].
367pub struct FsNodeSecurityXattr {
368    pub name: &'static FsStr,
369    pub value: FsString,
370}
371
372/// Checks whether the `current_task` is allowed to mmap `file` or memory using the given
373/// [`ProtectionFlags`] and [`MappingOptions`].
374/// Corresponds to the `mmap_file()` LSM hook.
375pub fn mmap_file(
376    current_task: &CurrentTask,
377    file: Option<&FileHandle>,
378    protection_flags: ProtectionFlags,
379    options: MappingOptions,
380) -> Result<(), Errno> {
381    track_hook_duration!("security.hooks.mmap_file");
382    if_selinux_else_default_ok(current_task, |security_server| {
383        selinux_hooks::file::mmap_file(
384            security_server,
385            current_task,
386            file,
387            protection_flags,
388            options,
389        )
390    })
391}
392
393/// Checks whether `current_task` is allowed to request setting the memory protection of
394/// `mapping` to `prot`.
395/// Corresponds to the `file_mprotect` LSM hook.
396pub fn file_mprotect(
397    current_task: &CurrentTask,
398    range: &Range<UserAddress>,
399    mapping: &Mapping,
400    prot: ProtectionFlags,
401) -> Result<(), Errno> {
402    track_hook_duration!("security.hooks.file_mprotect");
403    if_selinux_else_default_ok(current_task, |security_server| {
404        selinux_hooks::file::file_mprotect(security_server, current_task, range, mapping, prot)
405    })
406}
407
408/// Checks whether the `current_task` has the specified `permission_flags` to the `file`.
409/// Corresponds to the `file_permission()` LSM hook.
410pub fn file_permission(
411    current_task: &CurrentTask,
412    file: &FileObject,
413    permission_flags: PermissionFlags,
414) -> Result<(), Errno> {
415    track_hook_duration!("security.hooks.file_permission");
416    if_selinux_else_default_ok(current_task, |security_server| {
417        selinux_hooks::file::file_permission(security_server, current_task, file, permission_flags)
418    })
419}
420
421/// Checks whether the `current_task` is allowed to open `file`.
422/// Corresponds to the `file_open()` LSM hook.
423pub fn file_open(current_task: &CurrentTask, file: &FileObject) -> Result<(), Errno> {
424    track_hook_duration!("security.hooks.file_open");
425    if_selinux_else_default_ok(current_task, |security_server| {
426        selinux_hooks::file::file_open(security_server, current_task, file)
427    })
428}
429
430/// Called by the VFS to initialize the security state for an `FsNode` that is being linked at
431/// `dir_entry`.
432/// If the `FsNode` security state had already been initialized, or no policy is yet loaded, then
433/// this is a no-op.
434/// Corresponds to the `d_instantiate()` LSM hook.
435pub fn fs_node_init_with_dentry(
436    current_task: &CurrentTask,
437    dir_entry: &DirEntryHandle,
438) -> Result<(), Errno> {
439    track_hook_duration!("security.hooks.fs_node_init_with_dentry");
440    // TODO: https://fxbug.dev/367585803 - Don't use `if_selinux_else()` here, because the `has_policy()`
441    // check is racey, so doing non-trivial work in the "else" path is unsafe. Instead, call the SELinux
442    // hook implementation, and let it label, or queue, the `FsNode` based on the `FileSystem` label
443    // state, thereby ensuring safe ordering.
444    if let Some(state) = &current_task.kernel().security_state.state {
445        selinux_hooks::fs_node::fs_node_init_with_dentry(
446            &state.server,
447            current_task,
448            dir_entry,
449            /* read_xaddr = */
450            true,
451        )
452    } else {
453        Ok(())
454    }
455}
456
457pub fn fs_node_init_with_dentry_no_xattr(
458    current_task: &CurrentTask,
459    dir_entry: &DirEntryHandle,
460) -> Result<(), Errno> {
461    track_hook_duration!("security.hooks.fs_node_init_with_dentry_no_xattr");
462    // TODO: https://fxbug.dev/367585803 - Don't use `if_selinux_else()` here, because the `has_policy()`
463    // check is racey, so doing non-trivial work in the "else" path is unsafe. Instead, call the SELinux
464    // hook implementation, and let it label, or queue, the `FsNode` based on the `FileSystem` label
465    // state, thereby ensuring safe ordering.
466    if let Some(state) = &current_task.kernel().security_state.state {
467        // Sockets are currently implemented using `Anon` nodes, and may be kernel-private, in
468        // which case delegate to the anonymous node initializer to apply a placeholder label.
469        if dir_entry.node.is_private() {
470            return selinux_hooks::fs_node::fs_node_init_anon(
471                &state.server,
472                current_task,
473                &dir_entry.node,
474                "",
475            );
476        }
477
478        selinux_hooks::fs_node::fs_node_init_with_dentry(
479            &state.server,
480            current_task,
481            dir_entry,
482            /* read_xaddr = */
483            false,
484        )
485    } else {
486        Ok(())
487    }
488}
489
490// Temporary work-around for lack of a `CurrentTask` during creation of `DirEntry`s for some initial
491// file-systems.
492// TODO: https://fxbug.dev/455771186 - Clean up with-DirEntry initialization and remove this.
493pub fn fs_node_init_with_dentry_deferred(kernel: &Kernel, dir_entry: &DirEntryHandle) {
494    track_hook_duration!("security.hooks.fs_node_init_with_dentry_no_xattr");
495    if kernel.security_state.state.is_some() {
496        selinux_hooks::fs_node::fs_node_init_with_dentry_deferred(dir_entry);
497    }
498}
499
500/// Applies the given label to the given node without checking any permissions.
501/// Used by file-system implementations to set the label for a node, for example when it has
502/// prefetched the label in the xattr rather than letting it get fetched by
503/// `fs_node_init_with_dentry` later. Calling this doesn't need to exclude the use of
504/// `fs_node_init_with_dentry`, it will just turn that call into a fast no-op.
505/// Corresponds to the `inode_notifysecctx` LSM hook.
506pub fn fs_node_notify_security_context(
507    current_task: &CurrentTask,
508    fs_node: &FsNode,
509    context: &FsStr,
510) -> Result<(), Errno> {
511    track_hook_duration!("security.hooks.fs_node_notify_security_context");
512    if_selinux_else(
513        current_task,
514        |security_server| {
515            selinux_hooks::fs_node::fs_node_notify_security_context(
516                security_server,
517                fs_node,
518                context,
519            )
520        },
521        || error!(ENOTSUP),
522    )
523}
524
525/// Called by file-system implementations when creating the `FsNode` for a new file, to determine the
526/// correct label based on the `CurrentTask` and `parent` node, and the policy-defined transition
527/// rules, and to initialize the `FsNode`'s security state accordingly.
528/// If no policy has yet been loaded then this is a no-op; if the `FsNode` corresponds to an xattr-
529/// labeled file then it will receive the file-system's "default" label once a policy is loaded.
530/// Returns an extended attribute value to set on the newly-created file if the labeling scheme is
531/// `fs_use_xattr`. For other labeling schemes (e.g. `fs_use_trans`, mountpoint-labeling) a label
532/// is set on the `FsNode` security state, but no extended attribute is set nor returned.
533/// The `name` with which the new node is being created allows name-conditional `type_transition`
534/// rules to be applied when determining the label for the `new_node`.
535/// Corresponds to the `inode_init_security()` LSM hook.
536pub fn fs_node_init_on_create(
537    current_task: &CurrentTask,
538    new_node: &FsNode,
539    parent: &FsNode,
540    name: &FsStr,
541) -> Result<Option<FsNodeSecurityXattr>, Errno> {
542    track_hook_duration!("security.hooks.fs_node_init_on_create");
543    if_selinux_else_default_ok(current_task, |security_server| {
544        selinux_hooks::fs_node::fs_node_init_on_create(
545            security_server,
546            current_task,
547            new_node,
548            Some(parent),
549            name,
550        )
551    })
552}
553
554/// Called by specialist file-system implementations before creating a new `FsNode`, to obtain the
555/// SID with which the code will be labeled, in advance.
556///
557/// The computed SID will be applied to the `fscreate_sid` field of the supplied `new_creds`, which
558/// may then be used with `CurrentTask::override_creds()` to later create the new node.
559///
560/// Corresponds to the `dentry_create_files_as()` LSM hook.
561pub fn dentry_create_files_as(
562    current_task: &CurrentTask,
563    parent: &FsNode,
564    new_node_mode: FileMode,
565    new_node_name: &FsStr,
566    new_creds: &mut Credentials,
567) -> Result<(), Errno> {
568    track_hook_duration!("security.hooks.dentry_create_files_as");
569    if_selinux_else_default_ok(current_task, |security_server| {
570        selinux_hooks::fs_node::dentry_create_files_as(
571            security_server,
572            current_task,
573            parent,
574            new_node_mode,
575            new_node_name,
576            new_creds,
577        )
578    })
579}
580
581/// Called on creation of anonymous [`crate::vfs::FsNode`]s. APIs that create file-descriptors that
582/// are not linked into any filesystem directory structure create anonymous nodes, labeled by this
583/// hook rather than `fs_node_init_on_create()` above.
584/// Corresponds to the `inode_init_security_anon()` LSM hook.
585pub fn fs_node_init_anon(
586    current_task: &CurrentTask,
587    new_node: &FsNode,
588    node_type: &str,
589) -> Result<(), Errno> {
590    track_hook_duration!("security.hooks.fs_node_init_anon");
591    if let Some(state) = current_task.kernel().security_state.state.as_ref() {
592        selinux_hooks::fs_node::fs_node_init_anon(&state.server, current_task, new_node, node_type)
593    } else {
594        Ok(())
595    }
596}
597
598/// Validate that `current_task` has permission to create a regular file in the `parent` directory,
599/// with the specified file `mode`.
600/// Corresponds to the `inode_create()` LSM hook.
601pub fn check_fs_node_create_access(
602    current_task: &CurrentTask,
603    parent: &FsNode,
604    mode: FileMode,
605    name: &FsStr,
606) -> Result<(), Errno> {
607    track_hook_duration!("security.hooks.check_fs_node_create_access");
608    if_selinux_else_default_ok(current_task, |security_server| {
609        selinux_hooks::fs_node::check_fs_node_create_access(
610            security_server,
611            current_task,
612            parent,
613            mode,
614            name,
615        )
616    })
617}
618
619/// Validate that `current_task` has permission to create a symlink to `old_path` in the `parent`
620/// directory.
621/// Corresponds to the `inode_symlink()` LSM hook.
622pub fn check_fs_node_symlink_access(
623    current_task: &CurrentTask,
624    parent: &FsNode,
625    name: &FsStr,
626    old_path: &FsStr,
627) -> Result<(), Errno> {
628    track_hook_duration!("security.hooks.check_fs_node_symlink_access");
629    if_selinux_else_default_ok(current_task, |security_server| {
630        selinux_hooks::fs_node::check_fs_node_symlink_access(
631            security_server,
632            current_task,
633            parent,
634            name,
635            old_path,
636        )
637    })
638}
639
640/// Validate that `current_task` has permission to create a new directory in the `parent` directory,
641/// with the specified file `mode`.
642/// Corresponds to the `inode_mkdir()` LSM hook.
643pub fn check_fs_node_mkdir_access(
644    current_task: &CurrentTask,
645    parent: &FsNode,
646    mode: FileMode,
647    name: &FsStr,
648) -> Result<(), Errno> {
649    track_hook_duration!("security.hooks.check_fs_node_mkdir_access");
650    if_selinux_else_default_ok(current_task, |security_server| {
651        selinux_hooks::fs_node::check_fs_node_mkdir_access(
652            security_server,
653            current_task,
654            parent,
655            mode,
656            name,
657        )
658    })
659}
660
661/// Validate that `current_task` has permission to create a new special file, socket or pipe, in the
662/// `parent` directory, and with the specified file `mode` and `device_id`.
663/// For consistency any calls to `mknod()` with a file `mode` specifying a regular file will be
664/// validated by `check_fs_node_create_access()` rather than by this hook.
665/// Corresponds to the `inode_mknod()` LSM hook.
666pub fn check_fs_node_mknod_access(
667    current_task: &CurrentTask,
668    parent: &FsNode,
669    mode: FileMode,
670    name: &FsStr,
671    device_id: DeviceId,
672) -> Result<(), Errno> {
673    track_hook_duration!("security.hooks.check_fs_node_mknod_access");
674    assert!(!mode.is_reg());
675
676    if_selinux_else_default_ok(current_task, |security_server| {
677        selinux_hooks::fs_node::check_fs_node_mknod_access(
678            security_server,
679            current_task,
680            parent,
681            mode,
682            name,
683            device_id,
684        )
685    })
686}
687
688/// Validate that `current_task` has  the permission to create a new hard link to a file.
689/// Corresponds to the `inode_link()` LSM hook.
690pub fn check_fs_node_link_access(
691    current_task: &CurrentTask,
692    parent: &FsNode,
693    child: &FsNode,
694) -> Result<(), Errno> {
695    track_hook_duration!("security.hooks.check_fs_node_link_access");
696    if_selinux_else_default_ok(current_task, |security_server| {
697        selinux_hooks::fs_node::check_fs_node_link_access(
698            security_server,
699            current_task,
700            parent,
701            child,
702        )
703    })
704}
705
706/// Validate that `current_task` has the permission to remove a hard link to a file.
707/// Corresponds to the `inode_unlink()` LSM hook.
708pub fn check_fs_node_unlink_access(
709    current_task: &CurrentTask,
710    parent: &FsNode,
711    child: &FsNode,
712    name: &FsStr,
713) -> Result<(), Errno> {
714    track_hook_duration!("security.hooks.check_fs_node_unlink_access");
715    if_selinux_else_default_ok(current_task, |security_server| {
716        selinux_hooks::fs_node::check_fs_node_unlink_access(
717            security_server,
718            current_task,
719            parent,
720            child,
721            name,
722        )
723    })
724}
725
726/// Validate that `current_task` has the permission to remove a directory.
727/// Corresponds to the `inode_rmdir()` LSM hook.
728pub fn check_fs_node_rmdir_access(
729    current_task: &CurrentTask,
730    parent: &FsNode,
731    child: &FsNode,
732    name: &FsStr,
733) -> Result<(), Errno> {
734    track_hook_duration!("security.hooks.check_fs_node_rmdir_access");
735    if_selinux_else_default_ok(current_task, |security_server| {
736        selinux_hooks::fs_node::check_fs_node_rmdir_access(
737            security_server,
738            current_task,
739            parent,
740            child,
741            name,
742        )
743    })
744}
745
746/// Checks whether the `current_task` can rename the file or directory `moving_node`.
747/// If the rename replaces an existing node, `replaced_node` must contain a reference to the
748/// existing node.
749/// Corresponds to the `inode_rename()` LSM hook.
750pub fn check_fs_node_rename_access(
751    current_task: &CurrentTask,
752    old_parent: &FsNode,
753    moving_node: &FsNode,
754    new_parent: &FsNode,
755    replaced_node: Option<&FsNode>,
756    old_basename: &FsStr,
757    new_basename: &FsStr,
758) -> Result<(), Errno> {
759    track_hook_duration!("security.hooks.check_fs_node_rename_access");
760    if_selinux_else_default_ok(current_task, |security_server| {
761        selinux_hooks::fs_node::check_fs_node_rename_access(
762            security_server,
763            current_task,
764            old_parent,
765            moving_node,
766            new_parent,
767            replaced_node,
768            old_basename,
769            new_basename,
770        )
771    })
772}
773
774/// Checks whether the `current_task` can read the symbolic link in `fs_node`.
775/// Corresponds to the `inode_readlink()` LSM hook.
776pub fn check_fs_node_read_link_access(
777    current_task: &CurrentTask,
778    fs_node: &FsNode,
779) -> Result<(), Errno> {
780    track_hook_duration!("security.hooks.check_fs_node_read_link_access");
781    if_selinux_else_default_ok(current_task, |security_server| {
782        selinux_hooks::fs_node::check_fs_node_read_link_access(
783            security_server,
784            current_task,
785            fs_node,
786        )
787    })
788}
789
790/// Checks whether the `current_task` can access an inode.
791/// Corresponds to the `inode_permission()` LSM hook.
792pub fn fs_node_permission(
793    current_task: &CurrentTask,
794    fs_node: &FsNode,
795    permission_flags: PermissionFlags,
796    audit_context: Auditable<'_>,
797) -> Result<(), Errno> {
798    track_hook_duration!("security.hooks.fs_node_permission");
799    if_selinux_else_default_ok(current_task, |security_server| {
800        selinux_hooks::fs_node::fs_node_permission(
801            security_server,
802            current_task,
803            fs_node,
804            permission_flags,
805            audit_context,
806        )
807    })
808}
809
810/// Returns whether the `current_task` can receive `file` via a socket IPC.
811/// Corresponds to the `file_receive()` LSM hook.
812pub fn file_receive(current_task: &CurrentTask, file: &FileObject) -> Result<(), Errno> {
813    track_hook_duration!("security.hooks.file_receive");
814    if_selinux_else_default_ok(current_task, |security_server| {
815        let receiving_sid = current_task_state(current_task).current_sid;
816        selinux_hooks::file::file_receive(security_server, current_task, receiving_sid, file)
817    })
818}
819
820/// Returns the security state for a new file object created by `current_task`.
821/// Corresponds to the `file_alloc_security()` LSM hook.
822pub fn file_alloc_security(current_task: &CurrentTask) -> FileObjectState {
823    track_hook_duration!("security.hooks.file_alloc_security");
824    FileObjectState { state: selinux_hooks::file::file_alloc_security(current_task) }
825}
826
827/// Returns the security context to be assigned to a BinderConnection, based on the task that
828/// creates it.
829pub fn binder_connection_alloc(current_task: &CurrentTask) -> BinderConnectionState {
830    track_hook_duration!("security.hooks.binder_connection_alloc");
831    BinderConnectionState { state: selinux_hooks::binder::binder_connection_alloc(current_task) }
832}
833
834/// Returns the security context to be assigned to a BPM map object, based on the task that
835/// creates it.
836/// Corresponds to the `bpf_map_alloc_security()` LSM hook.
837pub fn bpf_map_alloc(current_task: &CurrentTask) -> BpfMapState {
838    track_hook_duration!("security.hooks.bpf_map_alloc");
839    BpfMapState { state: selinux_hooks::bpf::bpf_map_alloc(current_task) }
840}
841
842/// Returns the security context to be assigned to a BPM program object, based on the task
843/// that creates it.
844/// Corresponds to the `bpf_prog_alloc_security()` LSM hook.
845pub fn bpf_prog_alloc(current_task: &CurrentTask) -> BpfProgState {
846    track_hook_duration!("security.hooks.bpf_prog_alloc");
847    BpfProgState { state: selinux_hooks::bpf::bpf_prog_alloc(current_task) }
848}
849
850/// Returns whether `current_task` can issue an ioctl to `file`.
851/// Corresponds to the `file_ioctl()` LSM hook.
852pub fn check_file_ioctl_access(
853    current_task: &CurrentTask,
854    file: &FileObject,
855    request: u32,
856) -> Result<(), Errno> {
857    track_hook_duration!("security.hooks.check_file_ioctl_access");
858    if_selinux_else_default_ok(current_task, |security_server| {
859        selinux_hooks::file::check_file_ioctl_access(security_server, current_task, file, request)
860    })
861}
862
863/// Updates the supplied `new_creds` with the necessary FS and LSM credentials to correctly label
864/// a new `FsNode` on copy-up, to match the existing `fs_node`.
865///
866/// - fs_node: The "lower" filesystem node that is to be copied-up.
867/// - fs: The OverlayFS instance performing the copy-up operation.
868// TODO: https://fxbug.dev/398696739 - Revise this API to accept the overlay FsNode for which
869// copy-up is being performed, rather than separate "lower" `fs_node` and overlay `fs`.
870///
871/// Corresponds to the `security_inode_copy_up()` LSM hook.
872pub fn fs_node_copy_up(
873    current_task: &CurrentTask,
874    fs_node: &FsNode,
875    fs: &FileSystem,
876    new_creds: &mut Credentials,
877) {
878    if_selinux_else(
879        current_task,
880        |_security_server| {
881            selinux_hooks::fs_node::fs_node_copy_up(current_task, fs_node, fs, new_creds)
882        },
883        || {},
884    )
885}
886
887/// This hook is called by the `flock` syscall. Returns whether `current_task` can perform
888/// a lock operation on the given file.
889///
890/// See also `check_file_fcntl_access()` for `lock` permission checks performed after an
891/// fcntl lock request.
892///
893/// Corresponds to the `file_lock()` LSM hook.
894pub fn check_file_lock_access(current_task: &CurrentTask, file: &FileObject) -> Result<(), Errno> {
895    track_hook_duration!("security.hooks.check_file_lock_access");
896    if_selinux_else_default_ok(current_task, |security_server| {
897        selinux_hooks::file::check_file_lock_access(security_server, current_task, file)
898    })
899}
900
901/// Returns whether `current_task` has the permissions to execute this fcntl syscall.
902/// Corresponds to the `file_fcntl()` LSM hook.
903pub fn check_file_fcntl_access(
904    current_task: &CurrentTask,
905    file: &FileObject,
906    fcntl_cmd: u32,
907    fcntl_arg: u64,
908) -> Result<(), Errno> {
909    track_hook_duration!("security.hooks.check_file_fcntl_access");
910    if_selinux_else_default_ok(current_task, |security_server| {
911        selinux_hooks::file::check_file_fcntl_access(
912            security_server,
913            current_task,
914            file,
915            fcntl_cmd,
916            fcntl_arg,
917        )
918    })
919}
920
921/// Checks whether `current_task` can set attributes on `node`.
922/// Corresponds to the `inode_setattr()` LSM hook.
923pub fn check_fs_node_setattr_access(
924    current_task: &CurrentTask,
925    node: &FsNode,
926    attributes: &zxio_node_attr_has_t,
927) -> Result<(), Errno> {
928    track_hook_duration!("security.hooks.check_fs_node_setattr_access");
929    if_selinux_else_default_ok(current_task, |security_server| {
930        selinux_hooks::fs_node::check_fs_node_setattr_access(
931            security_server,
932            current_task,
933            node,
934            attributes,
935        )
936    })
937}
938
939/// Return the default initial `TaskAttrs` for kernel tasks.
940/// Corresponds to the `task_alloc()` LSM hook, in the special case when current_task is null.
941pub fn task_alloc_for_kernel() -> TaskAttrs {
942    track_hook_duration!("security.hooks.task_alloc_for_kernel");
943    TaskAttrs::for_kernel()
944}
945
946/// Labels an [`crate::vfs::FsNode`], by attaching a pseudo-label to the `fs_node`, which allows
947/// indirect resolution of the effective label. Makes the security attributes of `fs_node` track the
948/// `task`'s security attributes, even if the task's security attributes change. Called for the
949/// /proc/<pid> `FsNode`s when they are created.
950/// Corresponds to the `task_to_inode` LSM hook.
951pub fn task_to_fs_node(current_task: &CurrentTask, task: &Task, fs_node: &FsNode) {
952    track_hook_duration!("security.hooks.task_to_fs_node");
953    // The fs_node_init_with_task hook doesn't require any policy-specific information. Only check
954    // if SElinux is enabled before running it.
955    if current_task.kernel().security_state.state.is_some() {
956        selinux_hooks::task::fs_node_init_with_task(task, &fs_node);
957    }
958}
959
960/// Returns `TaskAttrs` for a new `Task`, based on that of the provided `context`.
961/// The effect is similar to combining the `task_alloc()` and `setprocattr()` LSM hooks, with the
962/// difference that no access-checks are performed, and the "#<name>" syntax may be used to
963/// have the `Task` assigned one of the "initial" Security Contexts, to allow components to be run
964/// prior to a policy being loaded.
965pub fn task_for_context(task: &Task, context: &FsStr) -> Result<TaskAttrs, Errno> {
966    track_hook_duration!("security.hooks.task_for_context");
967    Ok(if let Some(kernel_state) = task.kernel().security_state.state.as_ref() {
968        selinux_hooks::task::task_alloc_from_context(&kernel_state.server, context)
969    } else {
970        Ok(TaskAttrs::for_selinux_disabled())
971    }?)
972}
973
974/// Returns true if there exits a `dontaudit` rule for `current_task` access to `fs_node`, which
975/// includes the `audit_access` pseudo-permission.
976/// This appears to be handled via additional options & flags in other hooks, by LSM.
977pub fn has_dontaudit_access(current_task: &CurrentTask, fs_node: &FsNode) -> bool {
978    track_hook_duration!("security.hooks.has_dontaudit_access");
979    if_selinux_else(
980        current_task,
981        |security_server| {
982            selinux_hooks::fs_node::has_dontaudit_access(security_server, current_task, fs_node)
983        },
984        || false,
985    )
986}
987
988/// Returns true if a task has the specified `capability`.
989/// Corresponds to the `capable()` LSM hook invoked with a no-audit flag set.
990pub fn is_task_capable_noaudit(
991    current_task: &CurrentTask,
992    capability: starnix_uapi::auth::Capabilities,
993) -> bool {
994    track_hook_duration!("security.hooks.is_task_capable_noaudit");
995    return common_cap::capable(current_task, capability).is_ok()
996        && if_selinux_else(
997            current_task,
998            |security_server| {
999                selinux_hooks::task::is_task_capable_noaudit(
1000                    &selinux_hooks::build_permission_check(current_task, security_server),
1001                    &current_task,
1002                    capability,
1003                )
1004            },
1005            || true,
1006        );
1007}
1008
1009/// Checks if a task has the specified `capability`.
1010/// Corresponds to the `capable()` LSM hook.
1011pub fn check_creds_capable(
1012    current_task: &CurrentTask,
1013    creds: &Credentials,
1014    capability: starnix_uapi::auth::Capabilities,
1015) -> Result<(), Errno> {
1016    track_hook_duration!("security.hooks.check_creds_capable");
1017    common_cap::creds_capable(creds, capability)?;
1018    if_selinux_else_default_ok(current_task, |security_server| {
1019        selinux_hooks::task::check_creds_capable(
1020            &selinux_hooks::build_permission_check(current_task, security_server),
1021            &current_task,
1022            creds,
1023            capability,
1024        )
1025    })
1026}
1027
1028/// Checks if a task has the specified `capability`.
1029/// Corresponds to the `capable()` LSM hook.
1030pub fn check_task_capable(
1031    current_task: &CurrentTask,
1032    capability: starnix_uapi::auth::Capabilities,
1033) -> Result<(), Errno> {
1034    check_creds_capable(current_task, &**current_task.current_creds(), capability)
1035}
1036
1037/// Checks if creating a task is allowed.
1038/// Corresponds to the `task_alloc()` LSM hook, except this hook doesn't modify the task's label.
1039pub fn check_task_create_access(current_task: &CurrentTask) -> Result<(), Errno> {
1040    track_hook_duration!("security.hooks.check_task_create_access");
1041    if_selinux_else_default_ok(current_task, |security_server| {
1042        selinux_hooks::task::check_task_create_access(
1043            &selinux_hooks::build_permission_check(current_task, security_server),
1044            current_task,
1045        )
1046    })
1047}
1048
1049/// Checks if creating a socket is allowed.
1050/// Corresponds to the `socket_create()` LSM hook.
1051pub fn check_socket_create_access(
1052    current_task: &CurrentTask,
1053    domain: SocketDomain,
1054    socket_type: SocketType,
1055    protocol: SocketProtocol,
1056    kernel_private: bool,
1057) -> Result<(), Errno> {
1058    track_hook_duration!("security.hooks.socket_create");
1059    if_selinux_else_default_ok(current_task, |security_server| {
1060        selinux_hooks::socket::check_socket_create_access(
1061            &security_server,
1062            current_task,
1063            domain,
1064            socket_type,
1065            protocol,
1066            kernel_private,
1067        )
1068    })
1069}
1070
1071/// Sets the peer security context for each socket in the pair.
1072/// Corresponds to the `socket_socketpair()` LSM hook.
1073pub fn socket_socketpair(
1074    current_task: &CurrentTask,
1075    left: DowncastedFile<'_, SocketFile>,
1076    right: DowncastedFile<'_, SocketFile>,
1077) -> Result<(), Errno> {
1078    track_hook_duration!("security.hooks.socket_socketpair");
1079    if_selinux_else_default_ok(current_task, |_| {
1080        selinux_hooks::socket::socket_socketpair(left, right)
1081    })
1082}
1083
1084/// Computes and updates the socket security class associated with a new socket.
1085/// Corresponds to the `socket_post_create()` LSM hook.
1086pub fn socket_post_create(current_task: &CurrentTask, socket: &Socket) {
1087    track_hook_duration!("security.hooks.socket_post_create");
1088    if let Some(state) = &current_task.kernel().security_state.state {
1089        selinux_hooks::socket::socket_post_create(&state.server, socket);
1090    }
1091}
1092
1093/// Checks if the `current_task` is allowed to perform a bind operation for this `socket`.
1094/// Corresponds to the `socket_bind()` LSM hook.
1095pub fn check_socket_bind_access(
1096    current_task: &CurrentTask,
1097    socket: &Socket,
1098    socket_address: &SocketAddress,
1099) -> Result<(), Errno> {
1100    track_hook_duration!("security.hooks.check_socket_bind_access");
1101    if_selinux_else_default_ok(current_task, |security_server| {
1102        selinux_hooks::socket::check_socket_bind_access(
1103            &security_server,
1104            current_task,
1105            socket,
1106            socket_address,
1107        )
1108    })
1109}
1110
1111/// Checks if the `current_task` is allowed to initiate a connection with `socket`.
1112/// Corresponds to the `socket_connect()` LSM hook.
1113pub fn check_socket_connect_access(
1114    current_task: &CurrentTask,
1115    socket: DowncastedFile<'_, SocketFile>,
1116    socket_peer: &SocketPeer,
1117) -> Result<(), Errno> {
1118    track_hook_duration!("security.hooks.check_socket_connect_access");
1119    if_selinux_else_default_ok(current_task, |security_server| {
1120        selinux_hooks::socket::check_socket_connect_access(
1121            &security_server,
1122            current_task,
1123            socket,
1124            socket_peer,
1125        )
1126    })
1127}
1128
1129/// Checks if the `current_task` is allowed to listen on `socket_node`.
1130/// Corresponds to the `socket_listen()` LSM hook.
1131pub fn check_socket_listen_access(
1132    current_task: &CurrentTask,
1133    socket: &Socket,
1134    backlog: i32,
1135) -> Result<(), Errno> {
1136    track_hook_duration!("security.hooks.check_socket_listen_access");
1137    if_selinux_else_default_ok(current_task, |security_server| {
1138        selinux_hooks::socket::check_socket_listen_access(
1139            &security_server,
1140            current_task,
1141            socket,
1142            backlog,
1143        )
1144    })
1145}
1146
1147/// Checks if the `current_task` is allowed to accept connections on `listening_socket`. Sets
1148/// the security label and SID for the accepted socket to match those of the listening socket.
1149/// Corresponds to the `socket_accept()` LSM hook.
1150pub fn socket_accept(
1151    current_task: &CurrentTask,
1152    listening_socket: DowncastedFile<'_, SocketFile>,
1153    accepted_socket: DowncastedFile<'_, SocketFile>,
1154) -> Result<(), Errno> {
1155    track_hook_duration!("security.hooks.check_socket_getname_access");
1156    if_selinux_else_default_ok(current_task, |security_server| {
1157        selinux_hooks::socket::socket_accept(
1158            &security_server,
1159            current_task,
1160            listening_socket,
1161            accepted_socket,
1162        )
1163    })
1164}
1165
1166/// Checks if the `current_task` is allowed to get socket options on `socket`.
1167/// Corresponds to the `socket_getsockopt()` LSM hook.
1168pub fn check_socket_getsockopt_access(
1169    current_task: &CurrentTask,
1170    socket: &Socket,
1171    level: u32,
1172    optname: u32,
1173) -> Result<(), Errno> {
1174    track_hook_duration!("security.hooks.check_socket_getsockopt_access");
1175    if_selinux_else_default_ok(current_task, |security_server| {
1176        selinux_hooks::socket::check_socket_getsockopt_access(
1177            &security_server,
1178            current_task,
1179            socket,
1180            level,
1181            optname,
1182        )
1183    })
1184}
1185
1186/// Checks if the `current_task` is allowed to set socket options on `socket`.
1187/// Corresponds to the `socket_getsockopt()` LSM hook.
1188pub fn check_socket_setsockopt_access(
1189    current_task: &CurrentTask,
1190    socket: &Socket,
1191    level: u32,
1192    optname: u32,
1193) -> Result<(), Errno> {
1194    track_hook_duration!("security.hooks.check_socket_setsockopt_access");
1195    if_selinux_else_default_ok(current_task, |security_server| {
1196        selinux_hooks::socket::check_socket_setsockopt_access(
1197            &security_server,
1198            current_task,
1199            socket,
1200            level,
1201            optname,
1202        )
1203    })
1204}
1205
1206/// Checks if the `current_task` is allowed to send a message on `socket`.
1207/// Corresponds to the `socket_sendmsg()` LSM hook.
1208pub fn check_socket_sendmsg_access(
1209    current_task: &CurrentTask,
1210    socket: &Socket,
1211) -> Result<(), Errno> {
1212    track_hook_duration!("security.hooks.check_socket_sendmsg_access");
1213    if_selinux_else_default_ok(current_task, |security_server| {
1214        selinux_hooks::socket::check_socket_sendmsg_access(&security_server, current_task, socket)
1215    })
1216}
1217
1218/// Checks if the `current_task` is allowed to receive a message on `socket`.
1219/// Corresponds to the `socket_recvmsg()` LSM hook.
1220pub fn check_socket_recvmsg_access(
1221    current_task: &CurrentTask,
1222    socket: &Socket,
1223) -> Result<(), Errno> {
1224    track_hook_duration!("security.hooks.check_socket_recvmsg_access");
1225    if_selinux_else_default_ok(current_task, |security_server| {
1226        selinux_hooks::socket::check_socket_recvmsg_access(&security_server, current_task, socket)
1227    })
1228}
1229
1230/// Checks if the `current_task` is allowed to get the local name of `socket`.
1231/// Corresponds to the `socket_getsockname()` LSM hook.
1232pub fn check_socket_getsockname_access(
1233    current_task: &CurrentTask,
1234    socket: &Socket,
1235) -> Result<(), Errno> {
1236    track_hook_duration!("security.hooks.check_socket_getname_access");
1237    if_selinux_else_default_ok(current_task, |security_server| {
1238        selinux_hooks::socket::check_socket_getname_access(&security_server, current_task, socket)
1239    })
1240}
1241
1242/// Checks if the `current_task` is allowed to get the remote name of `socket`.
1243/// Corresponds to the `socket_getpeername()` LSM hook.
1244pub fn check_socket_getpeername_access(
1245    current_task: &CurrentTask,
1246    socket: &Socket,
1247) -> Result<(), Errno> {
1248    track_hook_duration!("security.hooks.check_socket_getname_access");
1249    if_selinux_else_default_ok(current_task, |security_server| {
1250        selinux_hooks::socket::check_socket_getname_access(&security_server, current_task, socket)
1251    })
1252}
1253
1254/// Checks if the `current_task` is allowed to shutdown `socket`.
1255/// Corresponds to the `socket_shutdown()` LSM hook.
1256pub fn check_socket_shutdown_access(
1257    current_task: &CurrentTask,
1258    socket: &Socket,
1259    how: SocketShutdownFlags,
1260) -> Result<(), Errno> {
1261    track_hook_duration!("security.hooks.check_socket_shutdown_access");
1262    if_selinux_else_default_ok(current_task, |security_server| {
1263        selinux_hooks::socket::check_socket_shutdown_access(
1264            &security_server,
1265            current_task,
1266            socket,
1267            how,
1268        )
1269    })
1270}
1271
1272/// Returns the Security Context with which the [`crate::vfs::Socket`]'s peer is labeled.
1273/// Corresponds to the `socket_getpeersec_stream()` LSM hook.
1274pub fn socket_getpeersec_stream(
1275    current_task: &CurrentTask,
1276    socket: &Socket,
1277) -> Result<Vec<u8>, Errno> {
1278    track_hook_duration!("security.hooks.socket_getpeersec_stream");
1279    if_selinux_else_default_ok(current_task, |security_server| {
1280        selinux_hooks::socket::socket_getpeersec_stream(&security_server, current_task, socket)
1281    })
1282}
1283
1284/// Returns the Security Context with which the [`crate::vfs::Socket`]'s is labeled, to return to
1285/// the recipient via `SCM_SECURITY` auxiliary data, if `SO_PASSSEC` is set.
1286/// Corresponds to the `socket_getpeersec_dgram()` LSM hook.
1287pub fn socket_getpeersec_dgram(current_task: &CurrentTask, socket: &Socket) -> Vec<u8> {
1288    track_hook_duration!("security.hooks.socket_getpeersec_dgram");
1289    if_selinux_else(
1290        current_task,
1291        |security_server| {
1292            selinux_hooks::socket::socket_getpeersec_dgram(&security_server, current_task, socket)
1293        },
1294        Vec::default,
1295    )
1296}
1297
1298/// Checks if the Unix domain `sending_socket` is allowed to send a message to the
1299/// `receiving_socket`.
1300/// Corresponds to the `unix_may_send()` LSM hook.
1301pub fn unix_may_send(
1302    current_task: &CurrentTask,
1303    sending_socket: &Socket,
1304    receiving_socket: &Socket,
1305) -> Result<(), Errno> {
1306    track_hook_duration!("security.hooks.unix_may_send");
1307    if_selinux_else_default_ok(current_task, |security_server| {
1308        selinux_hooks::socket::unix_may_send(
1309            &security_server,
1310            current_task,
1311            sending_socket,
1312            receiving_socket,
1313        )
1314    })
1315}
1316
1317/// Checks if the Unix domain `client_socket` is allowed to connect to `listening_socket`, and
1318/// initialises the peer information in the client and server sockets.
1319/// Corresponds to the `unix_stream_connect()` LSM hook.
1320pub fn unix_stream_connect(
1321    current_task: &CurrentTask,
1322    client_socket: &Socket,
1323    listening_socket: &Socket,
1324    server_socket: &Socket,
1325) -> Result<(), Errno> {
1326    track_hook_duration!("security.hooks.unix_stream_connect");
1327    if_selinux_else_default_ok(current_task, |security_server| {
1328        selinux_hooks::socket::unix_stream_connect(
1329            &security_server,
1330            current_task,
1331            client_socket,
1332            listening_socket,
1333            server_socket,
1334        )
1335    })
1336}
1337
1338/// Checks if the `current_task` is allowed to send a message of `message_type` on the Netlink
1339/// `socket`.
1340/// Corresponds to the `netlink_send()` LSM hook.
1341pub fn check_netlink_send_access(
1342    current_task: &CurrentTask,
1343    socket: &Socket,
1344    message_type: u16,
1345) -> Result<(), Errno> {
1346    track_hook_duration!("security.hooks.check_netlink_send_access");
1347    if_selinux_else_default_ok(current_task, |security_server| {
1348        selinux_hooks::netlink_socket::check_netlink_send_access(
1349            &security_server,
1350            current_task,
1351            socket,
1352            message_type,
1353        )
1354    })
1355}
1356
1357/// Checks if the `current_task` has permission to create a new TUN device.
1358/// Corresponds to the `tun_dev_create()` LSM hook.
1359pub fn check_tun_dev_create_access(current_task: &CurrentTask) -> Result<(), Errno> {
1360    track_hook_duration!("security.hooks.check_tun_dev_create_access");
1361    if_selinux_else_default_ok(current_task, |security_server| {
1362        selinux_hooks::socket::check_tun_dev_create_access(&security_server, current_task)
1363    })
1364}
1365
1366/// Updates credentials based on the executable file (e.g., SUID/SGID, capabilities).
1367///
1368/// Corresponds to the `bprm_creds_from_file` LSM hook.
1369pub fn bprm_creds_from_file(
1370    current_task: &CurrentTask,
1371    elf_state: &mut ResolvedElf,
1372) -> Result<(), Errno> {
1373    track_hook_duration!("security.hooks.bprm_creds_from_file");
1374
1375    let (no_new_privs, is_ptraced) = {
1376        let state = current_task.read();
1377        (state.no_new_privs(), state.is_ptraced())
1378    };
1379
1380    let enable_suid = current_task.kernel().features.enable_suid && !no_new_privs && !is_ptraced;
1381    if enable_suid {
1382        elf_state.file.name.apply_suid_and_sgid(&mut elf_state.creds);
1383    }
1384
1385    // On exec, the filesystem UIDs are always reset to the effective UIDs.
1386    elf_state.creds.fsuid = elf_state.creds.euid;
1387    elf_state.creds.fsgid = elf_state.creds.egid;
1388
1389    // The effective user ID of the process is copied to the saved set-
1390    // user-ID; similarly, the effective group ID is copied to the saved
1391    // set-group-ID. This copying takes place after any effective ID
1392    // changes that occur because of the set-user-ID and set-group-ID
1393    // mode bits.
1394    elf_state.creds.saved_uid = elf_state.creds.euid;
1395    elf_state.creds.saved_gid = elf_state.creds.egid;
1396
1397    let prev = current_task.current_creds();
1398    let file_is_privileged = elf_state.creds.euid != prev.euid || elf_state.creds.egid != prev.egid;
1399    let is_secure_exec = file_is_privileged
1400        || elf_state.creds.uid != elf_state.creds.euid
1401        || elf_state.creds.gid != elf_state.creds.egid;
1402
1403    elf_state.secure_exec |= is_secure_exec;
1404
1405    common_cap::bprm_creds_from_file(current_task, elf_state)?;
1406
1407    Ok(())
1408}
1409
1410/// Checks if exec is allowed and if so, checks permissions related to the transition
1411/// (if any) from the pre-exec security context to the post-exec context. Updates the `Credentials`
1412/// in the `elf_state` with the appropriate security state.
1413///
1414/// Corresponds to the `bprm_creds_for_exec()` LSM hook.
1415pub fn bprm_creds_for_exec(
1416    current_task: &CurrentTask,
1417    executable: &NamespaceNode,
1418    elf_state: &mut ResolvedElf,
1419) -> Result<(), Errno> {
1420    track_hook_duration!("security.hooks.bprm_creds_for_exec");
1421    if let Some(state) = &current_task.kernel().security_state.state {
1422        if state.has_policy() {
1423            return selinux_hooks::task::bprm_creds_for_exec(
1424                &state.server,
1425                current_task,
1426                executable,
1427                elf_state,
1428            );
1429        } else {
1430            // SELinux is enabled but not yet configured, so apply the "init" SID.
1431            let previous_sid = current_task.current_creds().security_state.current_sid;
1432            elf_state.creds.security_state =
1433                TaskAttrs::for_transition(InitialSid::Init.into(), previous_sid);
1434        }
1435    }
1436    Ok(())
1437}
1438
1439/// Called during `exec()`, immediately before the `elf_state.creds` are applied to the calling
1440/// process.  This is typically used to apply restrictions on the calling process, such as closing
1441/// file descriptors to which the new security domain will not have access.
1442///
1443/// Corresponds to the `bprm_committing_creds()` LSM hook.
1444pub fn bprm_committing_creds(
1445    current_task: &CurrentTask,
1446    elf_state: &ResolvedElf,
1447) -> Result<(), Errno> {
1448    track_hook_duration!("security.hooks.bprm_committing_creds");
1449    if_selinux_else_default_ok(current_task, |security_server| {
1450        selinux_hooks::task::bprm_committing_creds(security_server, current_task, elf_state);
1451        Ok(())
1452    })
1453}
1454
1455/// Called immediately after new credentials have been applied to the process during `exec()`.
1456///
1457/// Corresponds to the `bprm_committed_creds()` LSM hook.
1458pub fn bprm_committed_creds(current_task: &CurrentTask) -> Result<(), Errno> {
1459    track_hook_duration!("security.hooks.bprm_committed_creds");
1460    if_selinux_else_default_ok(current_task, |security_server| {
1461        selinux_hooks::task::bprm_committed_creds(security_server, current_task);
1462        Ok(())
1463    })
1464}
1465
1466/// Checks if `source` may exercise the "getsched" permission on `target`.
1467/// Corresponds to the `task_getscheduler()` LSM hook.
1468pub fn check_task_getscheduler_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1469    track_hook_duration!("security.hooks.task_getscheduler");
1470    if_selinux_else_default_ok(source, |security_server| {
1471        selinux_hooks::task::check_getsched_access(
1472            &selinux_hooks::build_permission_check(source, security_server),
1473            &source,
1474            &target,
1475        )
1476    })
1477}
1478
1479/// Checks if setsched is allowed.
1480/// Corresponds to the `task_setscheduler()` LSM hook.
1481pub fn check_task_setscheduler_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1482    track_hook_duration!("security.hooks.task_setscheduler");
1483    if_selinux_else_default_ok(source, |security_server| {
1484        selinux_hooks::task::check_setsched_access(
1485            &selinux_hooks::build_permission_check(source, security_server),
1486            &source,
1487            &target,
1488        )
1489    })
1490}
1491
1492/// Checks if setting nice value is allowed.
1493/// Corresponds to the `task_setnice()` LSM hook.
1494pub fn check_task_setnice_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1495    track_hook_duration!("security.hooks.task_setnice");
1496    if_selinux_else_default_ok(source, |security_server| {
1497        selinux_hooks::task::check_setsched_access(
1498            &selinux_hooks::build_permission_check(source, security_server),
1499            &source,
1500            &target,
1501        )
1502    })
1503}
1504
1505/// Checks if getpgid is allowed.
1506/// Corresponds to the `task_getpgid()` LSM hook.
1507pub fn check_getpgid_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1508    track_hook_duration!("security.hooks.check_getpgid_access");
1509    if_selinux_else_default_ok(source, |security_server| {
1510        selinux_hooks::task::check_getpgid_access(
1511            &selinux_hooks::build_permission_check(source, security_server),
1512            &source,
1513            &target,
1514        )
1515    })
1516}
1517
1518/// Checks if setpgid is allowed.
1519/// Corresponds to the `task_setpgid()` LSM hook.
1520pub fn check_setpgid_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1521    track_hook_duration!("security.hooks.check_setpgid_access");
1522    if_selinux_else_default_ok(source, |security_server| {
1523        selinux_hooks::task::check_setpgid_access(
1524            &selinux_hooks::build_permission_check(source, security_server),
1525            &source,
1526            &target,
1527        )
1528    })
1529}
1530
1531/// Called when the current task queries the session Id of the `target` task.
1532/// Corresponds to the `task_getsid()` LSM hook.
1533pub fn check_task_getsid(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1534    track_hook_duration!("security.hooks.check_task_getsid");
1535    if_selinux_else_default_ok(source, |security_server| {
1536        selinux_hooks::task::check_task_getsid(
1537            &selinux_hooks::build_permission_check(source, security_server),
1538            &source,
1539            &target,
1540        )
1541    })
1542}
1543
1544/// Called when the current task queries the Linux capabilities of the `target` task.
1545/// Corresponds to the `capget()` LSM hook.
1546pub fn check_getcap_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1547    track_hook_duration!("security.hooks.check_getcap_access");
1548    if_selinux_else_default_ok(source, |security_server| {
1549        selinux_hooks::task::check_getcap_access(
1550            &selinux_hooks::build_permission_check(source, security_server),
1551            &source,
1552            &target,
1553        )
1554    })
1555}
1556
1557/// Called when the current task attempts to set the Linux capabilities of the `target`
1558/// task.
1559/// Corresponds to the `capset()` LSM hook.
1560pub fn check_setcap_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1561    track_hook_duration!("security.hooks.check_setcap_access");
1562    if_selinux_else_default_ok(source, |security_server| {
1563        selinux_hooks::task::check_setcap_access(
1564            &selinux_hooks::build_permission_check(source, security_server),
1565            &source,
1566            &target,
1567        )
1568    })
1569}
1570
1571/// Checks if sending a signal is allowed.
1572/// Corresponds to the `task_kill()` LSM hook.
1573pub fn check_signal_access(
1574    source: &CurrentTask,
1575    target: &Task,
1576    signal: Signal,
1577) -> Result<(), Errno> {
1578    track_hook_duration!("security.hooks.check_signal_access");
1579    if_selinux_else_default_ok(source, |security_server| {
1580        selinux_hooks::task::check_signal_access(
1581            &selinux_hooks::build_permission_check(source, security_server),
1582            &source,
1583            &target,
1584            signal,
1585        )
1586    })
1587}
1588
1589/// Checks if a particular syslog action is allowed.
1590/// Corresponds to the `task_syslog()` LSM hook.
1591pub fn check_syslog_access(source: &CurrentTask, action: SyslogAction) -> Result<(), Errno> {
1592    track_hook_duration!("security.hooks.check_syslog_access");
1593    if_selinux_else_default_ok(source, |security_server| {
1594        selinux_hooks::task::check_syslog_access(
1595            &selinux_hooks::build_permission_check(source, security_server),
1596            &source,
1597            action,
1598        )
1599    })
1600}
1601
1602/// Checks whether the `parent_tracer_task` is allowed to trace the `current_task`.
1603/// Corresponds to the `ptrace_traceme()` LSM hook.
1604pub fn ptrace_traceme(current_task: &CurrentTask, parent_tracer_task: &Task) -> Result<(), Errno> {
1605    track_hook_duration!("security.hooks.ptrace_traceme");
1606    yama::ptrace_traceme(current_task, parent_tracer_task)?;
1607    common_cap::ptrace_traceme(current_task, parent_tracer_task)?;
1608    if_selinux_else_default_ok(current_task, |security_server| {
1609        selinux_hooks::task::ptrace_traceme(
1610            &selinux_hooks::build_permission_check(current_task, security_server),
1611            current_task,
1612            parent_tracer_task,
1613        )
1614    })
1615}
1616
1617/// Checks whether the current `current_task` is allowed to trace `tracee_task`.
1618/// Corresponds to the `ptrace_access_check()` LSM hook.
1619pub fn ptrace_access_check(
1620    current_task: &CurrentTask,
1621    tracee_task: &Task,
1622    mode: PtraceAccessMode,
1623) -> Result<(), Errno> {
1624    track_hook_duration!("security.hooks.ptrace_access_check");
1625    yama::ptrace_access_check(current_task, tracee_task, mode)?;
1626    common_cap::ptrace_access_check(current_task, tracee_task, mode)?;
1627    if_selinux_else_default_ok(current_task, |security_server| {
1628        selinux_hooks::task::ptrace_access_check(
1629            &selinux_hooks::build_permission_check(current_task, security_server),
1630            current_task,
1631            tracee_task,
1632            mode,
1633        )
1634    })
1635}
1636
1637/// Called when the current task calls prlimit on a different task.
1638/// Corresponds to the `task_prlimit()` LSM hook.
1639pub fn task_prlimit(
1640    source: &CurrentTask,
1641    target: &Task,
1642    check_get_rlimit: bool,
1643    check_set_rlimit: bool,
1644) -> Result<(), Errno> {
1645    track_hook_duration!("security.hooks.task_prlimit");
1646    if_selinux_else_default_ok(source, |security_server| {
1647        selinux_hooks::task::task_prlimit(
1648            &selinux_hooks::build_permission_check(source, security_server),
1649            &source,
1650            &target,
1651            check_get_rlimit,
1652            check_set_rlimit,
1653        )
1654    })
1655}
1656
1657/// Called before `source` sets the resource limits of `target` from `old_limit` to `new_limit`.
1658/// Corresponds to the `security_task_setrlimit` hook.
1659pub fn task_setrlimit(
1660    source: &CurrentTask,
1661    target: &Task,
1662    old_limit: rlimit,
1663    new_limit: rlimit,
1664) -> Result<(), Errno> {
1665    track_hook_duration!("security.hooks.task_setrlimit");
1666    if_selinux_else_default_ok(source, |security_server| {
1667        selinux_hooks::task::task_setrlimit(
1668            &selinux_hooks::build_permission_check(source, security_server),
1669            &source,
1670            &target,
1671            old_limit,
1672            new_limit,
1673        )
1674    })
1675}
1676
1677/// Check permission before mounting `fs`.
1678/// Corresponds to the `sb_kern_mount()` LSM hook.
1679pub fn sb_kern_mount(current_task: &CurrentTask, fs: &FileSystem) -> Result<(), Errno> {
1680    track_hook_duration!("security.hooks.sb_kern_mount");
1681    if_selinux_else_default_ok(current_task, |security_server| {
1682        selinux_hooks::superblock::sb_kern_mount(
1683            &selinux_hooks::build_permission_check(current_task, security_server),
1684            current_task,
1685            fs,
1686        )
1687    })
1688}
1689
1690/// Check permission before mounting to `path`. `flags` contains the mount flags that determine the
1691/// kind of mount operation done, and therefore the permissions that the caller requires.
1692/// Corresponds to the `sb_mount()` LSM hook.
1693pub fn sb_mount(
1694    current_task: &CurrentTask,
1695    path: &NamespaceNode,
1696    flags: MountFlags,
1697) -> Result<(), Errno> {
1698    track_hook_duration!("security.hooks.sb_mount");
1699    if_selinux_else_default_ok(current_task, |security_server| {
1700        selinux_hooks::superblock::sb_mount(
1701            &selinux_hooks::build_permission_check(current_task, security_server),
1702            current_task,
1703            path,
1704            flags,
1705        )
1706    })
1707}
1708
1709/// Checks permission before remounting `mount` with `new_mount_params`.
1710/// Corresponds to the `sb_remount()` LSM hook.
1711pub fn sb_remount(
1712    current_task: &CurrentTask,
1713    mount: &Mount,
1714    new_mount_options: FileSystemMountOptions,
1715) -> Result<(), Errno> {
1716    track_hook_duration!("security.hooks.sb_remount");
1717    if_selinux_else_default_ok(current_task, |security_server| {
1718        selinux_hooks::superblock::sb_remount(security_server, mount, new_mount_options)
1719    })
1720}
1721
1722/// Returns a `Display` implementation that Writes the LSM mount options of `fs` into `buf`.
1723/// Corresponds to the `sb_show_options` LSM hook.
1724pub fn sb_show_options<'a>(
1725    _kernel: &Kernel,
1726    fs: &'a FileSystem,
1727) -> Result<impl std::fmt::Display + 'a, Errno> {
1728    track_hook_duration!("security.hooks.sb_show_options");
1729    selinux_hooks::superblock::sb_show_options(fs)
1730}
1731
1732/// Checks if `current_task` has the permission to get the filesystem statistics of `fs`.
1733/// Corresponds to the `sb_statfs()` LSM hook.
1734pub fn sb_statfs(current_task: &CurrentTask, fs: &FileSystem) -> Result<(), Errno> {
1735    track_hook_duration!("security.hooks.sb_statfs");
1736    if_selinux_else_default_ok(current_task, |security_server| {
1737        selinux_hooks::superblock::sb_statfs(
1738            &selinux_hooks::build_permission_check(current_task, security_server),
1739            current_task,
1740            fs,
1741        )
1742    })
1743}
1744
1745/// Checks if `current_task` has the permission to unmount the filesystem mounted on
1746/// `node` using the unmount flags `flags`.
1747/// Corresponds to the `sb_umount()` LSM hook.
1748pub fn sb_umount(
1749    current_task: &CurrentTask,
1750    node: &NamespaceNode,
1751    flags: UnmountFlags,
1752) -> Result<(), Errno> {
1753    track_hook_duration!("security.hooks.sb_umount");
1754    if_selinux_else_default_ok(current_task, |security_server| {
1755        selinux_hooks::superblock::sb_umount(
1756            &selinux_hooks::build_permission_check(current_task, security_server),
1757            current_task,
1758            node,
1759            flags,
1760        )
1761    })
1762}
1763
1764/// Checks if `current_task` has the permission to read file attributes for  `fs_node`.
1765/// Corresponds to the `inode_getattr()` hook.
1766pub fn check_fs_node_getattr_access(
1767    current_task: &CurrentTask,
1768    fs_node: &FsNode,
1769) -> Result<(), Errno> {
1770    track_hook_duration!("security.hooks.check_fs_node_getattr_access");
1771    if_selinux_else_default_ok(current_task, |security_server| {
1772        selinux_hooks::fs_node::check_fs_node_getattr_access(security_server, current_task, fs_node)
1773    })
1774}
1775
1776/// Returns true if the security subsystem should skip capability checks on access to the named
1777/// attribute, false otherwise.
1778pub fn fs_node_xattr_skipcap(name: &FsStr) -> bool {
1779    selinux_hooks::fs_node::fs_node_xattr_skipcap(name)
1780}
1781
1782/// This is called by Starnix even for filesystems which support extended attributes, unlike Linux
1783/// LSM.
1784/// Partially corresponds to the `inode_setxattr()` LSM hook: It is equivalent to
1785/// `inode_setxattr()` for non-security xattrs, while `fs_node_setsecurity()` is always called for
1786/// security xattrs. See also [`fs_node_setsecurity()`].
1787pub fn check_fs_node_setxattr_access(
1788    current_task: &CurrentTask,
1789    fs_node: &FsNode,
1790    name: &FsStr,
1791    value: &FsStr,
1792    op: XattrOp,
1793) -> Result<(), Errno> {
1794    track_hook_duration!("security.hooks.check_fs_node_setxattr_access");
1795    common_cap::fs_node_setxattr(current_task, fs_node, name, value, op)?;
1796    if_selinux_else_default_ok(current_task, |security_server| {
1797        selinux_hooks::fs_node::check_fs_node_setxattr_access(
1798            security_server,
1799            current_task,
1800            fs_node,
1801            name,
1802            value,
1803            op,
1804        )
1805    })
1806}
1807
1808/// Corresponds to the `inode_getxattr()` LSM hook.
1809pub fn check_fs_node_getxattr_access(
1810    current_task: &CurrentTask,
1811    fs_node: &FsNode,
1812    name: &FsStr,
1813) -> Result<(), Errno> {
1814    track_hook_duration!("security.hooks.check_fs_node_getxattr_access");
1815    if_selinux_else_default_ok(current_task, |security_server| {
1816        selinux_hooks::fs_node::check_fs_node_getxattr_access(
1817            security_server,
1818            current_task,
1819            fs_node,
1820            name,
1821        )
1822    })
1823}
1824
1825/// Corresponds to the `inode_listxattr()` LSM hook.
1826pub fn check_fs_node_listxattr_access(
1827    current_task: &CurrentTask,
1828    fs_node: &FsNode,
1829) -> Result<(), Errno> {
1830    track_hook_duration!("security.hooks.check_fs_node_listxattr_access");
1831    if_selinux_else_default_ok(current_task, |security_server| {
1832        selinux_hooks::fs_node::check_fs_node_listxattr_access(
1833            security_server,
1834            current_task,
1835            fs_node,
1836        )
1837    })
1838}
1839
1840/// Corresponds to the `inode_removexattr()` LSM hook.
1841pub fn check_fs_node_removexattr_access(
1842    current_task: &CurrentTask,
1843    fs_node: &FsNode,
1844    name: &FsStr,
1845) -> Result<(), Errno> {
1846    track_hook_duration!("security.hooks.check_fs_node_removexattr_access");
1847    common_cap::fs_node_removexattr(current_task, fs_node, name)?;
1848    if_selinux_else_default_ok(current_task, |security_server| {
1849        selinux_hooks::fs_node::check_fs_node_removexattr_access(
1850            security_server,
1851            current_task,
1852            fs_node,
1853            name,
1854        )
1855    })
1856}
1857
1858/// If SELinux is enabled and `fs_node` is in a filesystem without xattr support, returns the xattr
1859/// name for the security label associated with inode. Otherwise returns None.
1860///
1861/// This hook is called from the `listxattr` syscall.
1862///
1863/// Corresponds to the `inode_listsecurity()` LSM hook.
1864pub fn fs_node_listsecurity(current_task: &CurrentTask, fs_node: &FsNode) -> Option<FsString> {
1865    track_hook_duration!("security.hooks.fs_node_listsecurity");
1866    if_selinux_else(
1867        current_task,
1868        |_| selinux_hooks::fs_node::fs_node_listsecurity(fs_node),
1869        || None,
1870    )
1871}
1872
1873/// Returns the value of the specified "security.*" attribute for `fs_node`.
1874/// If SELinux is enabled then requests for the "security.selinux" attribute will return the
1875/// Security Context corresponding to the SID with which `fs_node` has been labeled, even if the
1876/// node's file system does not generally support extended attributes.
1877/// If SELinux is not enabled, or the node is not labeled with a SID, then the call is delegated to
1878/// the [`crate::vfs::FsNodeOps`], so the returned value may not be a valid Security Context.
1879/// Corresponds to the `inode_getsecurity()` LSM hook.
1880pub fn fs_node_getsecurity(
1881    current_task: &CurrentTask,
1882    fs_node: &FsNode,
1883    name: &FsStr,
1884    max_size: usize,
1885) -> Result<ValueOrSize<FsString>, Errno> {
1886    track_hook_duration!("security.hooks.fs_node_getsecurity");
1887    if_selinux_else(
1888        current_task,
1889        |security_server| {
1890            selinux_hooks::fs_node::fs_node_getsecurity(
1891                security_server,
1892                current_task,
1893                fs_node,
1894                name,
1895                max_size,
1896            )
1897        },
1898        || fs_node.ops().get_xattr(fs_node, current_task, name, max_size),
1899    )
1900}
1901
1902/// Called when an extended attribute with "security."-prefixed `name` is being set, after having
1903/// passed the discretionary and `check_fs_node_setxattr_access()` permission-checks.
1904/// This allows the LSM (e.g. SELinux) to update internal state as necessary for xattr changes.
1905///
1906/// Partially corresponds to the `inode_setsecurity()` and `inode_post_setxattr()` LSM hooks.
1907pub fn fs_node_setsecurity(
1908    current_task: &CurrentTask,
1909    fs_node: &FsNode,
1910    name: &FsStr,
1911    value: &FsStr,
1912    op: XattrOp,
1913) -> Result<(), Errno> {
1914    track_hook_duration!("security.hooks.fs_node_setsecurity");
1915    if_selinux_else(
1916        current_task,
1917        |security_server| {
1918            selinux_hooks::fs_node::fs_node_setsecurity(
1919                security_server,
1920                current_task,
1921                fs_node,
1922                name,
1923                value,
1924                op,
1925            )
1926        },
1927        || fs_node.ops().set_xattr(fs_node, current_task, name, value, op),
1928    )
1929}
1930
1931/// Checks whether `current_task` can perform the given bpf `cmd`. This hook is called from the
1932/// `sys_bpf()` syscall after the attribute is copied into the kernel.
1933/// Corresponds to the `bpf()` LSM hook.
1934pub fn check_bpf_access<Attr: FromBytes>(
1935    current_task: &CurrentTask,
1936    cmd: bpf_cmd,
1937    attr: &Attr,
1938    attr_size: u32,
1939) -> Result<(), Errno> {
1940    track_hook_duration!("security.hooks.check_bpf_access");
1941    if_selinux_else_default_ok(current_task, |security_server| {
1942        selinux_hooks::bpf::check_bpf_access(security_server, current_task, cmd, attr, attr_size)
1943    })
1944}
1945
1946/// Checks whether `current_task` can create a bpf_map. This hook is called from the
1947/// `sys_bpf()` syscall when the kernel tries to generate and return a file descriptor for maps.
1948/// Corresponds to the `bpf_map()` LSM hook.
1949pub fn check_bpf_map_access(
1950    current_task: &CurrentTask,
1951    bpf_map_state: &BpfMapState,
1952    flags: PermissionFlags,
1953) -> Result<(), Errno> {
1954    track_hook_duration!("security.hooks.check_bpf_map_access");
1955    if_selinux_else_default_ok(current_task, |security_server| {
1956        let subject_sid = current_task_state(current_task).current_sid;
1957        selinux_hooks::bpf::check_bpf_map_access(
1958            security_server,
1959            current_task,
1960            subject_sid,
1961            bpf_map_state,
1962            flags,
1963        )
1964    })
1965}
1966
1967/// Checks whether `current_task` can create a bpf_program. This hook is called from the
1968/// `sys_bpf()` syscall when the kernel tries to generate and return a file descriptor for
1969/// programs.
1970/// Corresponds to the `bpf_prog()` LSM hook.
1971pub fn check_bpf_prog_access(
1972    current_task: &CurrentTask,
1973    bpf_program_state: &BpfProgState,
1974) -> Result<(), Errno> {
1975    track_hook_duration!("security.hooks.check_bpf_prog_access");
1976    if_selinux_else_default_ok(current_task, |security_server| {
1977        let subject_sid = current_task_state(current_task).current_sid;
1978        selinux_hooks::bpf::check_bpf_prog_access(
1979            security_server,
1980            current_task,
1981            subject_sid,
1982            bpf_program_state,
1983        )
1984    })
1985}
1986
1987/// Checks whether `current_task` has the correct permissions to monitor the given target task or
1988/// tasks.
1989/// Corresponds to the `perf_event_open` LSM hook.
1990pub fn check_perf_event_open_access(
1991    current_task: &CurrentTask,
1992    target_task_type: TargetTaskType<'_>,
1993    attr: &perf_event_attr,
1994    event_type: PerfEventType,
1995) -> Result<(), Errno> {
1996    track_hook_duration!("security.hooks.check_perf_event_open_access");
1997    if_selinux_else_default_ok(current_task, |security_server| {
1998        selinux_hooks::perf_event::check_perf_event_open_access(
1999            security_server,
2000            current_task,
2001            target_task_type,
2002            attr,
2003            event_type,
2004        )
2005    })
2006}
2007
2008/// Returns the security context to be assigned to a PerfEventFileState, based on the task that
2009/// creates it.
2010/// Corresponds to the `perf_event_alloc` LSM hook.
2011pub fn perf_event_alloc(current_task: &CurrentTask) -> PerfEventState {
2012    track_hook_duration!("security.hooks.perf_event_alloc");
2013    PerfEventState { state: selinux_hooks::perf_event::perf_event_alloc(current_task) }
2014}
2015
2016/// Checks whether `current_task` has the correct permissions to read the given `perf_event_file`
2017/// Corresponds to the `perf_event_read` LSM hook.
2018pub fn check_perf_event_read_access(
2019    current_task: &CurrentTask,
2020    perf_event_file: &PerfEventFile,
2021) -> Result<(), Errno> {
2022    track_hook_duration!("security.hooks.check_perf_event_read_access");
2023    if_selinux_else_default_ok(current_task, |security_server| {
2024        selinux_hooks::perf_event::check_perf_event_read_access(
2025            security_server,
2026            current_task,
2027            perf_event_file,
2028        )
2029    })
2030}
2031
2032/// Checks whether `current_task` has the correct permissions to write to the given `perf_event_file`.
2033/// Corresponds to the `perf_event_write` LSM hook.
2034pub fn check_perf_event_write_access(
2035    current_task: &CurrentTask,
2036    perf_event_file: &PerfEventFile,
2037) -> Result<(), Errno> {
2038    track_hook_duration!("security.hooks.check_perf_event_write_access");
2039    if_selinux_else_default_ok(current_task, |security_server| {
2040        selinux_hooks::perf_event::check_perf_event_write_access(
2041            security_server,
2042            current_task,
2043            perf_event_file,
2044        )
2045    })
2046}
2047
2048/// Identifies one of the Security Context attributes associated with a task.
2049#[derive(Debug, Clone, Copy, PartialEq)]
2050pub enum ProcAttr {
2051    Current,
2052    Exec,
2053    FsCreate,
2054    KeyCreate,
2055    Previous,
2056    SockCreate,
2057}
2058
2059/// Returns the Security Context associated with the `name`ed entry for the specified `target` task.
2060/// Corresponds to the `getprocattr()` LSM hook.
2061pub fn get_procattr(
2062    current_task: &CurrentTask,
2063    target: &Task,
2064    attr: ProcAttr,
2065) -> Result<Vec<u8>, Errno> {
2066    track_hook_duration!("security.hooks.get_procattr");
2067    if_selinux_else(
2068        current_task,
2069        |security_server| {
2070            selinux_hooks::task::get_procattr(security_server, current_task, target, attr)
2071        },
2072        // If SELinux is disabled then there are no values to return.
2073        || error!(EINVAL),
2074    )
2075}
2076
2077/// Sets the Security Context associated with the `name`ed entry for the current task.
2078/// Corresponds to the `setprocattr()` LSM hook.
2079pub fn set_procattr(
2080    current_task: &CurrentTask,
2081    attr: ProcAttr,
2082    context: &[u8],
2083) -> Result<(), Errno> {
2084    track_hook_duration!("security.hooks.set_procattr");
2085    if_selinux_else(
2086        current_task,
2087        |security_server| {
2088            selinux_hooks::task::set_procattr(security_server, current_task, attr, context)
2089        },
2090        // If SELinux is disabled then no writes are accepted.
2091        || error!(EINVAL),
2092    )
2093}
2094
2095/// Returns true if SELinux is enabled on the kernel for this task.
2096pub fn fs_is_xattr_labeled(fs: FileSystemHandle) -> bool {
2097    fs.security_state.state.supports_xattr()
2098}
2099
2100/// Stashes a reference to the selinuxfs null file for later use by hooks that remap
2101/// inaccessible file descriptors to null.
2102pub fn selinuxfs_init_null(current_task: &CurrentTask, null_fs_node: &FileHandle) {
2103    // Note: No `if_selinux_...` guard because hook is invoked inside selinuxfs initialization code;
2104    // i.e., hook is only invoked when selinux is enabled.
2105    selinux_hooks::selinuxfs::selinuxfs_init_null(current_task, null_fs_node)
2106}
2107
2108/// Called by the "selinuxfs" when a policy has been successfully loaded, to allow policy-dependent
2109/// initialization to be completed. This includes resolving labeling schemes and state for
2110/// file-systems mounted prior to policy load (e.g. the "selinuxfs" itself), and initializing
2111/// security state for any file nodes they may already contain.
2112// TODO: https://fxbug.dev/362917997 - Remove this when SELinux LSM is modularized.
2113pub fn selinuxfs_policy_loaded(current_task: &CurrentTask) {
2114    track_hook_duration!("security.hooks.selinuxfs_policy_loaded");
2115    selinux_hooks::selinuxfs::selinuxfs_policy_loaded(current_task)
2116}
2117
2118/// Used by the "selinuxfs" module to access the SELinux administration API, if enabled.
2119// TODO: https://fxbug.dev/335397745 - Return a more restricted API, or ...
2120// TODO: https://fxbug.dev/362917997 - Remove this when SELinux LSM is modularized.
2121pub fn selinuxfs_get_admin_api(current_task: &CurrentTask) -> Option<Arc<SecurityServer>> {
2122    current_task.kernel().security_state.state.as_ref().map(|state| state.server.clone())
2123}
2124
2125/// Used by the "selinuxfs" module to perform checks on SELinux API file accesses.
2126// TODO: https://fxbug.dev/362917997 - Remove this when SELinux LSM is modularized.
2127pub fn selinuxfs_check_access(
2128    current_task: &CurrentTask,
2129    permission: SecurityPermission,
2130) -> Result<(), Errno> {
2131    track_hook_duration!("security.hooks.selinuxfs_check_access");
2132    if_selinux_else_default_ok(current_task, |security_server| {
2133        selinux_hooks::selinuxfs::selinuxfs_check_access(security_server, current_task, permission)
2134    })
2135}
2136
2137/// Marks the credentials as being used for an internal operation. All SELinux permission checks
2138/// will be skipped on this task.
2139pub fn creds_start_internal_operation(current_task: &CurrentTask) -> Arc<Credentials> {
2140    track_hook_duration!("security.hooks.creds_start_internal_operation");
2141    let mut creds = Credentials::clone(&current_task.current_creds());
2142    creds.security_state.internal_operation = true;
2143    creds.into()
2144}
2145
2146pub mod testing {
2147    use super::{Arc, KernelState, SecurityServer, selinux_hooks};
2148    use starnix_sync::LockDepMutex;
2149    use std::sync::OnceLock;
2150    use std::sync::atomic::AtomicU64;
2151
2152    /// Used by Starnix' `testing.rs` to create `KernelState` wrapping a test-
2153    /// supplied `SecurityServer`.
2154    pub fn kernel_state(security_server: Option<Arc<SecurityServer>>) -> KernelState {
2155        let state = security_server.map(|server| selinux_hooks::KernelState {
2156            server,
2157            pending_file_systems: LockDepMutex::default(),
2158            selinuxfs_null: OnceLock::default(),
2159            access_denial_count: AtomicU64::new(0u64),
2160            has_policy: false.into(),
2161            _inspect_node: fuchsia_inspect::Node::default(),
2162        });
2163        KernelState { state }
2164    }
2165}
2166
2167#[cfg(test)]
2168mod tests {
2169    use super::*;
2170    use crate::security;
2171    use crate::security::selinux_hooks::get_cached_sid;
2172    use crate::security::selinux_hooks::testing::{
2173        self, spawn_kernel_with_selinux_hooks_test_policy_and_run,
2174    };
2175    use crate::testing::{create_task, spawn_kernel_and_run, spawn_kernel_with_selinux_and_run};
2176    use linux_uapi::XATTR_NAME_SELINUX;
2177    use selinux::InitialSid;
2178    use starnix_uapi::auth::PTRACE_MODE_ATTACH;
2179    use starnix_uapi::signals::SIGTERM;
2180
2181    const VALID_SECURITY_CONTEXT: &[u8] = b"u:object_r:test_valid_t:s0";
2182    const VALID_SECURITY_CONTEXT_WITH_NUL: &[u8] = b"u:object_r:test_valid_t:s0\0";
2183
2184    const DIFFERENT_VALID_SECURITY_CONTEXT: &[u8] = b"u:object_r:test_different_valid_t:s0";
2185    const DIFFERENT_VALID_SECURITY_CONTEXT_WITH_NUL: &[u8] =
2186        b"u:object_r:test_different_valid_t:s0\0";
2187
2188    const INVALID_SECURITY_CONTEXT_INTERNAL_NUL: &[u8] = b"u:object_r:test_valid_\0t:s0";
2189
2190    const INVALID_SECURITY_CONTEXT: &[u8] = b"not_a_u:object_r:test_valid_t:s0";
2191
2192    #[derive(Default, Debug, PartialEq)]
2193    enum TestHookResult {
2194        WasRun,
2195        WasNotRun,
2196        #[default]
2197        WasNotRunDefault,
2198    }
2199
2200    #[fuchsia::test]
2201    async fn if_selinux_else_disabled() {
2202        spawn_kernel_and_run(async |current_task| {
2203            assert!(current_task.kernel().security_state.state.is_none());
2204
2205            let check_result =
2206                if_selinux_else_default_ok(current_task, |_| Ok(TestHookResult::WasRun));
2207            assert_eq!(check_result, Ok(TestHookResult::WasNotRunDefault));
2208
2209            let run_else_result = if_selinux_else(
2210                current_task,
2211                |_| TestHookResult::WasRun,
2212                || TestHookResult::WasNotRun,
2213            );
2214            assert_eq!(run_else_result, TestHookResult::WasNotRun);
2215        })
2216        .await;
2217    }
2218
2219    #[fuchsia::test]
2220    async fn if_selinux_else_without_policy() {
2221        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2222            let check_result =
2223                if_selinux_else_default_ok(current_task, |_| Ok(TestHookResult::WasRun));
2224            assert_eq!(check_result, Ok(TestHookResult::WasNotRunDefault));
2225
2226            let run_else_result = if_selinux_else(
2227                current_task,
2228                |_| TestHookResult::WasRun,
2229                || TestHookResult::WasNotRun,
2230            );
2231            assert_eq!(run_else_result, TestHookResult::WasNotRun);
2232        })
2233        .await;
2234    }
2235
2236    #[fuchsia::test]
2237    async fn if_selinux_else_with_policy() {
2238        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2239            let check_result =
2240                if_selinux_else_default_ok(current_task, |_| Ok(TestHookResult::WasRun));
2241            assert_eq!(check_result, Ok(TestHookResult::WasRun));
2242
2243            let run_else_result = if_selinux_else(
2244                current_task,
2245                |_| TestHookResult::WasRun,
2246                || TestHookResult::WasNotRun,
2247            );
2248            assert_eq!(run_else_result, TestHookResult::WasRun);
2249        })
2250        .await;
2251    }
2252
2253    #[fuchsia::test]
2254    async fn task_create_access_allowed_for_selinux_disabled() {
2255        spawn_kernel_and_run(async |current_task| {
2256            assert!(current_task.kernel().security_state.state.is_none());
2257            assert_eq!(check_task_create_access(current_task), Ok(()));
2258        })
2259        .await;
2260    }
2261
2262    #[fuchsia::test]
2263    async fn task_create_access_allowed_for_permissive_mode() {
2264        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2265            security_server.set_enforcing(false);
2266            assert_eq!(check_task_create_access(current_task), Ok(()));
2267        })
2268        .await;
2269    }
2270
2271    #[fuchsia::test]
2272    async fn exec_access_allowed_for_selinux_disabled() {
2273        spawn_kernel_and_run(async |current_task| {
2274            assert!(current_task.kernel().security_state.state.is_none());
2275            let executable = testing::create_test_file(current_task);
2276            let mut resolved_elf = testing::make_resolved_elf(current_task, executable.clone());
2277            assert_eq!(bprm_creds_for_exec(current_task, &executable, &mut resolved_elf), Ok(()));
2278        })
2279        .await;
2280    }
2281
2282    #[fuchsia::test]
2283    async fn exec_access_allowed_for_permissive_mode() {
2284        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2285            security_server.set_enforcing(false);
2286            let executable = testing::create_test_file(current_task);
2287            let mut resolved_elf = testing::make_resolved_elf(current_task, executable.clone());
2288            // Expect that access is granted.
2289            let result = bprm_creds_for_exec(current_task, &executable, &mut resolved_elf);
2290            assert!(result.is_ok());
2291        })
2292        .await;
2293    }
2294
2295    #[fuchsia::test]
2296    async fn exec_no_state_update_for_selinux_disabled() {
2297        spawn_kernel_and_run(async |current_task| {
2298            let target_sid = InitialSid::Unlabeled.into();
2299
2300            assert!(selinux_hooks::current_task_state(current_task).current_sid != target_sid);
2301
2302            // Set exec_sid to cause the hook to apply a transition, to verify if it is updated or not.
2303            testing::mutate_attrs_for_test(current_task, |attrs| {
2304                attrs.exec_sid = Some(target_sid);
2305            });
2306
2307            let executable = testing::create_test_file(current_task);
2308            let mut resolved_elf = testing::make_resolved_elf(current_task, executable.clone());
2309
2310            let before_hook_sid = selinux_hooks::current_task_state(current_task).current_sid;
2311
2312            bprm_creds_for_exec(current_task, &executable, &mut resolved_elf).unwrap();
2313            assert_eq!(resolved_elf.creds.security_state.current_sid, before_hook_sid);
2314        })
2315        .await;
2316    }
2317
2318    #[fuchsia::test]
2319    async fn exec_initial_context_for_selinux_without_policy() {
2320        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2321            let elf_sid = InitialSid::Unlabeled.into();
2322            assert_ne!(selinux_hooks::current_task_state(current_task).current_sid, elf_sid);
2323            assert_ne!(
2324                selinux_hooks::current_task_state(current_task).current_sid,
2325                InitialSid::Init.into()
2326            );
2327
2328            // Set exec_sid to cause the hook to apply a transition, to verify if it is updated or not.
2329            testing::mutate_attrs_for_test(current_task, |attrs| {
2330                attrs.exec_sid = Some(elf_sid);
2331            });
2332
2333            let executable = testing::create_test_file(current_task);
2334            let mut resolved_elf = testing::make_resolved_elf(current_task, executable.clone());
2335
2336            bprm_creds_for_exec(current_task, &executable, &mut resolved_elf).unwrap();
2337
2338            assert_eq!(resolved_elf.creds.security_state.current_sid, InitialSid::Init.into());
2339        })
2340        .await;
2341    }
2342
2343    #[fuchsia::test]
2344    async fn exec_state_update_for_permissive_mode() {
2345        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2346            security_server.set_enforcing(false);
2347            let elf_sid = security_server
2348                .security_context_to_sid(b"u:object_r:fork_no_t:s0".into())
2349                .expect("invalid security context");
2350
2351            assert_ne!(elf_sid, selinux_hooks::current_task_state(current_task).current_sid);
2352
2353            // Set exec_sid to cause the hook to apply a transition, to verify if it is updated or not.
2354            testing::mutate_attrs_for_test(current_task, |attrs| {
2355                attrs.exec_sid = Some(elf_sid);
2356            });
2357
2358            let executable = testing::create_test_file(current_task);
2359            let mut resolved_elf = testing::make_resolved_elf(current_task, executable.clone());
2360
2361            bprm_creds_for_exec(current_task, &executable, &mut resolved_elf).unwrap();
2362            assert_eq!(resolved_elf.creds.security_state.current_sid, elf_sid);
2363        })
2364        .await;
2365    }
2366
2367    #[fuchsia::test]
2368    async fn getsched_access_allowed_for_selinux_disabled() {
2369        spawn_kernel_and_run(async |current_task| {
2370            let another_task = create_task(&current_task.kernel(), "another-task");
2371            assert_eq!(check_task_getscheduler_access(current_task, &another_task), Ok(()));
2372        })
2373        .await;
2374    }
2375
2376    #[fuchsia::test]
2377    async fn getsched_access_allowed_for_permissive_mode() {
2378        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2379            let another_task = create_task(&current_task.kernel(), "another-task");
2380            assert_eq!(check_task_getscheduler_access(current_task, &another_task), Ok(()));
2381        })
2382        .await;
2383    }
2384
2385    #[fuchsia::test]
2386    async fn setsched_access_allowed_for_selinux_disabled() {
2387        spawn_kernel_and_run(async |current_task| {
2388            let another_task = create_task(&current_task.kernel(), "another-task");
2389            assert_eq!(check_task_setscheduler_access(current_task, &another_task), Ok(()));
2390        })
2391        .await;
2392    }
2393
2394    #[fuchsia::test]
2395    async fn setsched_access_allowed_for_permissive_mode() {
2396        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2397            let another_task = create_task(&current_task.kernel(), "another-task");
2398            assert_eq!(check_task_setscheduler_access(current_task, &another_task), Ok(()));
2399        })
2400        .await;
2401    }
2402
2403    #[fuchsia::test]
2404    async fn getpgid_access_allowed_for_selinux_disabled() {
2405        spawn_kernel_and_run(async |current_task| {
2406            let another_task = create_task(&current_task.kernel(), "another-task");
2407            assert_eq!(check_getpgid_access(current_task, &another_task), Ok(()));
2408        })
2409        .await;
2410    }
2411
2412    #[fuchsia::test]
2413    async fn getpgid_access_allowed_for_permissive_mode() {
2414        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2415            let another_task = create_task(&current_task.kernel(), "another-task");
2416            assert_eq!(check_getpgid_access(current_task, &another_task), Ok(()));
2417        })
2418        .await;
2419    }
2420
2421    #[fuchsia::test]
2422    async fn setpgid_access_allowed_for_selinux_disabled() {
2423        spawn_kernel_and_run(async |current_task| {
2424            let another_task = create_task(&current_task.kernel(), "another-task");
2425            assert_eq!(check_setpgid_access(current_task, &another_task), Ok(()));
2426        })
2427        .await;
2428    }
2429
2430    #[fuchsia::test]
2431    async fn setpgid_access_allowed_for_permissive_mode() {
2432        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2433            let another_task = create_task(&current_task.kernel(), "another-task");
2434            assert_eq!(check_setpgid_access(current_task, &another_task), Ok(()));
2435        })
2436        .await;
2437    }
2438
2439    #[fuchsia::test]
2440    async fn task_getsid_allowed_for_selinux_disabled() {
2441        spawn_kernel_and_run(async |current_task| {
2442            let another_task = create_task(&current_task.kernel(), "another-task");
2443            assert_eq!(check_task_getsid(current_task, &another_task), Ok(()));
2444        })
2445        .await;
2446    }
2447
2448    #[fuchsia::test]
2449    async fn task_getsid_allowed_for_permissive_mode() {
2450        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2451            let another_task = create_task(&current_task.kernel(), "another-task");
2452            assert_eq!(check_task_getsid(current_task, &another_task), Ok(()));
2453        })
2454        .await;
2455    }
2456
2457    #[fuchsia::test]
2458    async fn signal_access_allowed_for_selinux_disabled() {
2459        spawn_kernel_and_run(async |current_task| {
2460            let another_task = create_task(&current_task.kernel(), "another-task");
2461            assert_eq!(check_signal_access(current_task, &another_task, SIGTERM), Ok(()));
2462        })
2463        .await;
2464    }
2465
2466    #[fuchsia::test]
2467    async fn signal_access_allowed_for_permissive_mode() {
2468        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2469            let another_task = create_task(&current_task.kernel(), "another-task");
2470            assert_eq!(check_signal_access(current_task, &another_task, SIGTERM), Ok(()));
2471        })
2472        .await;
2473    }
2474
2475    #[fuchsia::test]
2476    async fn ptrace_traceme_access_allowed_for_selinux_disabled() {
2477        spawn_kernel_and_run(async |current_task| {
2478            let another_task = create_task(&current_task.kernel(), "another-task");
2479            assert_eq!(ptrace_traceme(current_task, &another_task), Ok(()));
2480        })
2481        .await;
2482    }
2483
2484    #[fuchsia::test]
2485    async fn ptrace_traceme_access_allowed_for_permissive_mode() {
2486        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2487            let another_task = create_task(&current_task.kernel(), "another-task");
2488            assert_eq!(ptrace_traceme(current_task, &another_task), Ok(()));
2489        })
2490        .await;
2491    }
2492
2493    #[fuchsia::test]
2494    async fn ptrace_attach_access_allowed_for_selinux_disabled() {
2495        spawn_kernel_and_run(async |current_task| {
2496            let another_task = create_task(&current_task.kernel(), "another-task");
2497            assert_eq!(
2498                ptrace_access_check(current_task, &another_task, PTRACE_MODE_ATTACH),
2499                Ok(())
2500            );
2501        })
2502        .await;
2503    }
2504
2505    #[fuchsia::test]
2506    async fn ptrace_attach_access_allowed_for_permissive_mode() {
2507        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2508            let another_task = create_task(&current_task.kernel(), "another-task");
2509            assert_eq!(
2510                ptrace_access_check(current_task, &another_task, PTRACE_MODE_ATTACH),
2511                Ok(())
2512            );
2513        })
2514        .await;
2515    }
2516
2517    #[fuchsia::test]
2518    async fn task_prlimit_access_allowed_for_selinux_disabled() {
2519        spawn_kernel_and_run(async |current_task| {
2520            let another_task = create_task(&current_task.kernel(), "another-task");
2521            assert_eq!(task_prlimit(current_task, &another_task, true, true), Ok(()));
2522        })
2523        .await;
2524    }
2525
2526    #[fuchsia::test]
2527    async fn task_prlimit_access_allowed_for_permissive_mode() {
2528        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2529            let another_task = create_task(&current_task.kernel(), "another-task");
2530            assert_eq!(task_prlimit(current_task, &another_task, true, true), Ok(()));
2531        })
2532        .await;
2533    }
2534
2535    #[fuchsia::test]
2536    async fn fs_node_task_to_fs_node_noop_selinux_disabled() {
2537        spawn_kernel_and_run(async |current_task| {
2538            let node = &testing::create_test_file(current_task).entry.node;
2539            task_to_fs_node(current_task, &current_task.task, &node);
2540            assert_eq!(None, selinux_hooks::get_cached_sid(node));
2541        })
2542        .await;
2543    }
2544
2545    #[fuchsia::test]
2546    async fn fs_node_setsecurity_selinux_disabled_only_sets_xattr() {
2547        spawn_kernel_and_run(async |current_task| {
2548            let node = &testing::create_test_file(current_task).entry.node;
2549
2550            fs_node_setsecurity(
2551                &current_task,
2552                &node,
2553                XATTR_NAME_SELINUX.to_bytes().into(),
2554                VALID_SECURITY_CONTEXT.into(),
2555                XattrOp::Set,
2556            )
2557            .expect("set_xattr(security.selinux) failed");
2558
2559            assert_eq!(None, selinux_hooks::get_cached_sid(node));
2560        })
2561        .await;
2562    }
2563
2564    #[fuchsia::test]
2565    async fn fs_node_setsecurity_selinux_without_policy_only_sets_xattr() {
2566        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2567            let node = &testing::create_test_file(current_task).entry.node;
2568            fs_node_setsecurity(
2569                &current_task,
2570                &node,
2571                XATTR_NAME_SELINUX.to_bytes().into(),
2572                VALID_SECURITY_CONTEXT.into(),
2573                XattrOp::Set,
2574            )
2575            .expect("set_xattr(security.selinux) failed");
2576
2577            assert_eq!(None, selinux_hooks::get_cached_sid(node));
2578        })
2579        .await;
2580    }
2581
2582    #[fuchsia::test]
2583    async fn fs_node_setsecurity_selinux_permissive_sets_xattr_and_label() {
2584        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2585            security_server.set_enforcing(false);
2586            let expected_sid = security_server
2587                .security_context_to_sid(VALID_SECURITY_CONTEXT.into())
2588                .expect("no SID for VALID_SECURITY_CONTEXT");
2589            let node = &testing::create_test_file(&current_task).entry.node;
2590
2591            // Safeguard against a false positive by ensuring `expected_sid` is not already the file's label.
2592            assert_ne!(Some(expected_sid), selinux_hooks::get_cached_sid(node));
2593
2594            fs_node_setsecurity(
2595                &current_task,
2596                &node,
2597                XATTR_NAME_SELINUX.to_bytes().into(),
2598                VALID_SECURITY_CONTEXT.into(),
2599                XattrOp::Set,
2600            )
2601            .expect("set_xattr(security.selinux) failed");
2602
2603            // Verify that the SID now cached on the node is that SID
2604            // corresponding to VALID_SECURITY_CONTEXT.
2605            assert_eq!(Some(expected_sid), selinux_hooks::get_cached_sid(node));
2606        })
2607        .await;
2608    }
2609
2610    #[fuchsia::test]
2611    async fn fs_node_setsecurity_not_selinux_only_sets_xattr() {
2612        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2613            let valid_security_context_sid = security_server
2614                .security_context_to_sid(VALID_SECURITY_CONTEXT.into())
2615                .expect("no SID for VALID_SECURITY_CONTEXT");
2616            let node = &testing::create_test_file(current_task).entry.node;
2617            // The label assigned to the test file on creation must differ from
2618            // VALID_SECURITY_CONTEXT, otherwise this test may return a false
2619            // positive.
2620            let whatever_sid = selinux_hooks::get_cached_sid(node);
2621            assert_ne!(Some(valid_security_context_sid), whatever_sid);
2622
2623            fs_node_setsecurity(
2624                &current_task,
2625                &node,
2626                "security.selinu!".into(), // Note: name != "security.selinux".
2627                VALID_SECURITY_CONTEXT.into(),
2628                XattrOp::Set,
2629            )
2630            .expect("set_xattr(security.selinux) failed");
2631
2632            // Verify that the node's SID (whatever it was) has not changed.
2633            assert_eq!(whatever_sid, selinux_hooks::get_cached_sid(node));
2634        })
2635        .await;
2636    }
2637
2638    #[fuchsia::test]
2639    async fn fs_node_setsecurity_selinux_enforcing_invalid_context_fails() {
2640        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2641            let node = &testing::create_test_file(current_task).entry.node;
2642
2643            let before_sid = selinux_hooks::get_cached_sid(node);
2644            assert_ne!(Some(InitialSid::Unlabeled.into()), before_sid);
2645
2646            assert!(
2647                check_fs_node_setxattr_access(
2648                    &current_task,
2649                    &node,
2650                    XATTR_NAME_SELINUX.to_bytes().into(),
2651                    "!".into(), // Note: Not a valid security context.
2652                    XattrOp::Set,
2653                )
2654                .is_err()
2655            );
2656
2657            assert_eq!(before_sid, selinux_hooks::get_cached_sid(node));
2658        })
2659        .await;
2660    }
2661
2662    #[fuchsia::test]
2663    async fn fs_node_setsecurity_selinux_permissive_invalid_context_sets_xattr_and_label() {
2664        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2665            security_server.set_enforcing(false);
2666            let node = &testing::create_test_file(current_task).entry.node;
2667
2668            assert_ne!(Some(InitialSid::Unlabeled.into()), selinux_hooks::get_cached_sid(node));
2669
2670            fs_node_setsecurity(
2671                &current_task,
2672                &node,
2673                XATTR_NAME_SELINUX.to_bytes().into(),
2674                "!".into(), // Note: Not a valid security context.
2675                XattrOp::Set,
2676            )
2677            .expect("set_xattr(security.selinux) failed");
2678
2679            assert_eq!(Some(InitialSid::Unlabeled.into()), selinux_hooks::get_cached_sid(node));
2680        })
2681        .await;
2682    }
2683
2684    #[fuchsia::test]
2685    async fn fs_node_setsecurity_different_sid_for_different_context() {
2686        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2687            let node = &testing::create_test_file(current_task).entry.node;
2688
2689            fs_node_setsecurity(
2690                &current_task,
2691                &node,
2692                XATTR_NAME_SELINUX.to_bytes().into(),
2693                VALID_SECURITY_CONTEXT.into(),
2694                XattrOp::Set,
2695            )
2696            .expect("set_xattr(security.selinux) failed");
2697
2698            assert!(selinux_hooks::get_cached_sid(node).is_some());
2699
2700            let first_sid = selinux_hooks::get_cached_sid(node).unwrap();
2701            fs_node_setsecurity(
2702                &current_task,
2703                &node,
2704                XATTR_NAME_SELINUX.to_bytes().into(),
2705                DIFFERENT_VALID_SECURITY_CONTEXT.into(),
2706                XattrOp::Set,
2707            )
2708            .expect("set_xattr(security.selinux) failed");
2709
2710            assert!(selinux_hooks::get_cached_sid(node).is_some());
2711
2712            let second_sid = selinux_hooks::get_cached_sid(node).unwrap();
2713
2714            assert_ne!(first_sid, second_sid);
2715        })
2716        .await;
2717    }
2718
2719    #[fuchsia::test]
2720    async fn fs_node_getsecurity_returns_cached_context() {
2721        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2722            let node = &testing::create_test_file(current_task).entry.node;
2723
2724            // Set a mismatched value in `node`'s "security.seliux" attribute.
2725            const TEST_VALUE: &str = "Something Random";
2726            node.ops()
2727                .set_xattr(
2728                    node,
2729                    current_task,
2730                    XATTR_NAME_SELINUX.to_bytes().into(),
2731                    TEST_VALUE.into(),
2732                    XattrOp::Set,
2733                )
2734                .expect("set_xattr(security.selinux) failed");
2735
2736            // Attach a valid SID to the `node`.
2737            let sid = security_server
2738                .security_context_to_sid(VALID_SECURITY_CONTEXT.into())
2739                .expect("security context to SID");
2740            selinux_hooks::set_cached_sid(&node, sid);
2741
2742            // Reading the security attribute should return the Security Context for the SID, rather than delegating.
2743            let result =
2744                fs_node_getsecurity(current_task, node, XATTR_NAME_SELINUX.to_bytes().into(), 4096);
2745            assert_eq!(
2746                result,
2747                Ok(ValueOrSize::Value(FsString::new(VALID_SECURITY_CONTEXT_WITH_NUL.into())))
2748            );
2749        })
2750        .await;
2751    }
2752
2753    #[fuchsia::test]
2754    async fn fs_node_getsecurity_delegates_to_get_xattr() {
2755        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2756            let node = &testing::create_test_file(current_task).entry.node;
2757
2758            // Set an invalid value in `node`'s "security.selinux" attribute.
2759            // This requires SELinux to be in permissive mode, otherwise the "relabelto" permission check will fail.
2760            security_server.set_enforcing(false);
2761            const TEST_VALUE: &str = "Something Random";
2762            fs_node_setsecurity(
2763                &current_task,
2764                node,
2765                XATTR_NAME_SELINUX.to_bytes().into(),
2766                TEST_VALUE.into(),
2767                XattrOp::Set,
2768            )
2769            .expect("set_xattr(security.selinux) failed");
2770            security_server.set_enforcing(true);
2771
2772            // Reading the security attribute should pass-through to read the value from the file system.
2773            let result =
2774                fs_node_getsecurity(current_task, node, XATTR_NAME_SELINUX.to_bytes().into(), 4096);
2775            assert_eq!(result, Ok(ValueOrSize::Value(FsString::new(TEST_VALUE.into()))));
2776        })
2777        .await;
2778    }
2779
2780    #[fuchsia::test]
2781    async fn set_get_procattr() {
2782        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2783            assert_eq!(get_procattr(current_task, current_task, ProcAttr::Exec), Ok(Vec::new()));
2784
2785            assert_eq!(
2786                // Test policy allows "kernel_t" tasks to set the "exec" context.
2787                set_procattr(current_task, ProcAttr::Exec, VALID_SECURITY_CONTEXT.into()),
2788                Ok(())
2789            );
2790
2791            assert_eq!(
2792                // Test policy does not allow "kernel_t" tasks to set the "sockcreate" context.
2793                set_procattr(
2794                    current_task,
2795                    ProcAttr::SockCreate,
2796                    DIFFERENT_VALID_SECURITY_CONTEXT.into()
2797                ),
2798                error!(EACCES)
2799            );
2800
2801            assert_eq!(
2802                // It is never permitted to set the "previous" context.
2803                set_procattr(
2804                    current_task,
2805                    ProcAttr::Previous,
2806                    DIFFERENT_VALID_SECURITY_CONTEXT.into()
2807                ),
2808                error!(EINVAL)
2809            );
2810
2811            assert_eq!(
2812                // Cannot set an invalid context.
2813                set_procattr(current_task, ProcAttr::Exec, INVALID_SECURITY_CONTEXT.into()),
2814                error!(EINVAL)
2815            );
2816
2817            assert_eq!(
2818                get_procattr(current_task, current_task, ProcAttr::Exec),
2819                Ok(VALID_SECURITY_CONTEXT_WITH_NUL.into())
2820            );
2821
2822            assert!(get_procattr(current_task, current_task, ProcAttr::Current).is_ok());
2823        })
2824        .await;
2825    }
2826
2827    #[fuchsia::test]
2828    async fn set_get_procattr_with_nulls() {
2829        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2830            assert_eq!(get_procattr(current_task, current_task, ProcAttr::Exec), Ok(Vec::new()));
2831
2832            assert_eq!(
2833                // Setting a Context with a string with trailing null(s) should work, if the Context is valid.
2834                set_procattr(current_task, ProcAttr::Exec, VALID_SECURITY_CONTEXT_WITH_NUL.into()),
2835                Ok(())
2836            );
2837
2838            assert_eq!(
2839                // Nulls in the middle of an otherwise valid Context truncate it, rendering it invalid.
2840                set_procattr(
2841                    current_task,
2842                    ProcAttr::FsCreate,
2843                    INVALID_SECURITY_CONTEXT_INTERNAL_NUL.into()
2844                ),
2845                error!(EINVAL)
2846            );
2847
2848            assert_eq!(
2849                get_procattr(current_task, current_task, ProcAttr::Exec),
2850                Ok(VALID_SECURITY_CONTEXT_WITH_NUL.into())
2851            );
2852
2853            assert_eq!(
2854                get_procattr(current_task, current_task, ProcAttr::FsCreate),
2855                Ok(Vec::new())
2856            );
2857        })
2858        .await;
2859    }
2860
2861    #[fuchsia::test]
2862    async fn set_get_procattr_clear_context() {
2863        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2864            // Set up the "exec" and "fscreate" Contexts with valid values.
2865            assert_eq!(
2866                set_procattr(current_task, ProcAttr::Exec, VALID_SECURITY_CONTEXT.into()),
2867                Ok(())
2868            );
2869            assert_eq!(
2870                set_procattr(
2871                    current_task,
2872                    ProcAttr::FsCreate,
2873                    DIFFERENT_VALID_SECURITY_CONTEXT.into()
2874                ),
2875                Ok(())
2876            );
2877
2878            // Clear the "exec" context with a write containing a single null octet.
2879            assert_eq!(set_procattr(current_task, ProcAttr::Exec, b"\0"), Ok(()));
2880            assert_eq!(current_task.current_creds().security_state.exec_sid, None);
2881
2882            // Clear the "fscreate" context with a write containing a single newline.
2883            assert_eq!(set_procattr(current_task, ProcAttr::FsCreate, b"\x0a"), Ok(()));
2884            assert_eq!(current_task.current_creds().security_state.fscreate_sid, None);
2885        })
2886        .await;
2887    }
2888
2889    #[fuchsia::test]
2890    async fn set_get_procattr_setcurrent() {
2891        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2892            // Stash the initial "previous" context.
2893            let initial_previous =
2894                get_procattr(current_task, current_task, ProcAttr::Previous).unwrap();
2895
2896            assert_eq!(
2897                // Dynamically transition to a valid new context.
2898                set_procattr(current_task, ProcAttr::Current, VALID_SECURITY_CONTEXT.into()),
2899                Ok(())
2900            );
2901
2902            assert_eq!(
2903                // "current" should report the new context.
2904                get_procattr(current_task, current_task, ProcAttr::Current),
2905                Ok(VALID_SECURITY_CONTEXT_WITH_NUL.into())
2906            );
2907
2908            assert_eq!(
2909                // "prev" should continue to report the original context.
2910                get_procattr(current_task, current_task, ProcAttr::Previous),
2911                Ok(initial_previous.clone())
2912            );
2913
2914            assert_eq!(
2915                // Dynamically transition to a different valid context.
2916                set_procattr(
2917                    current_task,
2918                    ProcAttr::Current,
2919                    DIFFERENT_VALID_SECURITY_CONTEXT.into()
2920                ),
2921                Ok(())
2922            );
2923
2924            assert_eq!(
2925                // "current" should report the different new context.
2926                get_procattr(current_task, current_task, ProcAttr::Current),
2927                Ok(DIFFERENT_VALID_SECURITY_CONTEXT_WITH_NUL.into())
2928            );
2929
2930            assert_eq!(
2931                // "prev" should continue to report the original context.
2932                get_procattr(current_task, current_task, ProcAttr::Previous),
2933                Ok(initial_previous.clone())
2934            );
2935        })
2936        .await;
2937    }
2938
2939    #[fuchsia::test]
2940    async fn set_get_procattr_selinux_permissive() {
2941        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2942            security_server.set_enforcing(false);
2943            assert_eq!(
2944                get_procattr(current_task, &current_task.task, ProcAttr::Exec),
2945                Ok(Vec::new())
2946            );
2947
2948            assert_eq!(
2949                // Test policy allows "kernel_t" tasks to set the "exec" context.
2950                set_procattr(current_task, ProcAttr::Exec, VALID_SECURITY_CONTEXT.into()),
2951                Ok(())
2952            );
2953
2954            assert_eq!(
2955                // Test policy does not allow "kernel_t" tasks to set the "fscreate" context, but
2956                // in permissive mode the setting will be allowed.
2957                set_procattr(
2958                    current_task,
2959                    ProcAttr::FsCreate,
2960                    DIFFERENT_VALID_SECURITY_CONTEXT.into()
2961                ),
2962                Ok(())
2963            );
2964
2965            assert_eq!(
2966                // Setting an invalid context should fail, even in permissive mode.
2967                set_procattr(current_task, ProcAttr::Exec, INVALID_SECURITY_CONTEXT.into()),
2968                error!(EINVAL)
2969            );
2970
2971            assert_eq!(
2972                get_procattr(current_task, &current_task.task, ProcAttr::Exec),
2973                Ok(VALID_SECURITY_CONTEXT_WITH_NUL.into())
2974            );
2975
2976            assert!(get_procattr(current_task, &current_task.task, ProcAttr::Current).is_ok());
2977        })
2978        .await;
2979    }
2980
2981    #[fuchsia::test]
2982    async fn set_get_procattr_selinux_disabled() {
2983        spawn_kernel_and_run(async |current_task| {
2984            assert_eq!(
2985                set_procattr(&current_task, ProcAttr::Exec, VALID_SECURITY_CONTEXT.into()),
2986                error!(EINVAL)
2987            );
2988
2989            assert_eq!(
2990                // Test policy allows "kernel_t" tasks to set the "exec" context.
2991                set_procattr(&current_task, ProcAttr::Exec, VALID_SECURITY_CONTEXT.into()),
2992                error!(EINVAL)
2993            );
2994
2995            assert_eq!(
2996                // Test policy does not allow "kernel_t" tasks to set the "fscreate" context.
2997                set_procattr(&current_task, ProcAttr::FsCreate, VALID_SECURITY_CONTEXT.into()),
2998                error!(EINVAL)
2999            );
3000
3001            assert_eq!(
3002                // Cannot set an invalid context.
3003                set_procattr(&current_task, ProcAttr::Exec, INVALID_SECURITY_CONTEXT.into()),
3004                error!(EINVAL)
3005            );
3006
3007            assert_eq!(
3008                get_procattr(&current_task, &current_task.task, ProcAttr::Current),
3009                error!(EINVAL)
3010            );
3011        })
3012        .await;
3013    }
3014
3015    #[fuchsia::test]
3016    async fn create_file_with_fscreate_sid() {
3017        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
3018            let sid =
3019                security_server.security_context_to_sid(VALID_SECURITY_CONTEXT.into()).unwrap();
3020            let source_node = &testing::create_test_file(current_task).entry.node;
3021
3022            fs_node_setsecurity(
3023                &current_task,
3024                &source_node,
3025                XATTR_NAME_SELINUX.to_bytes().into(),
3026                VALID_SECURITY_CONTEXT.into(),
3027                XattrOp::Set,
3028            )
3029            .expect("set_xattr(security.selinux) failed");
3030
3031            let mut creds = Credentials::clone(&current_task.current_creds());
3032            security::fs_node_copy_up(current_task, source_node, &source_node.fs(), &mut creds);
3033            let dir_entry = current_task
3034                .override_creds(creds.into(), || {
3035                    current_task
3036                        .fs()
3037                        .root()
3038                        .create_node(
3039                            &current_task,
3040                            "test_file2".into(),
3041                            FileMode::IFREG,
3042                            DeviceId::NONE,
3043                        )
3044                        .unwrap()
3045                })
3046                .entry;
3047
3048            assert_eq!(get_cached_sid(&dir_entry.node), Some(sid));
3049        })
3050        .await;
3051    }
3052}