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::ResolvedProgram;
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    resolved_program: &mut ResolvedProgram,
1372) -> Result<(), Errno> {
1373    track_hook_duration!("security.hooks.bprm_creds_from_file");
1374
1375    let (no_new_privs, is_ptraced_without_cap_sys_ptrace) = {
1376        let state = current_task.read();
1377        (state.no_new_privs(), state.is_ptraced_without_cap_sys_ptrace())
1378    };
1379
1380    let enable_suid = current_task.kernel().features.enable_suid
1381        && !no_new_privs
1382        && !is_ptraced_without_cap_sys_ptrace;
1383    if enable_suid {
1384        resolved_program.file.name().apply_suid_and_sgid(&mut resolved_program.creds);
1385    }
1386
1387    // On exec, the filesystem UIDs are always reset to the effective UIDs.
1388    resolved_program.creds.fsuid = resolved_program.creds.euid;
1389    resolved_program.creds.fsgid = resolved_program.creds.egid;
1390
1391    // The effective user ID of the process is copied to the saved set-
1392    // user-ID; similarly, the effective group ID is copied to the saved
1393    // set-group-ID. This copying takes place after any effective ID
1394    // changes that occur because of the set-user-ID and set-group-ID
1395    // mode bits.
1396    resolved_program.creds.saved_uid = resolved_program.creds.euid;
1397    resolved_program.creds.saved_gid = resolved_program.creds.egid;
1398
1399    common_cap::bprm_creds_from_file(current_task, resolved_program)?;
1400
1401    Ok(())
1402}
1403
1404/// Checks permissions for `execve`, updating [`ResolvedProgram`] with the post-exec
1405/// security state if allowed.
1406///
1407/// Corresponds to the `bprm_creds_for_exec()` LSM hook.
1408pub fn bprm_creds_for_exec(
1409    current_task: &CurrentTask,
1410    resolved_program: &mut ResolvedProgram,
1411) -> Result<(), Errno> {
1412    track_hook_duration!("security.hooks.bprm_creds_for_exec");
1413    if let Some(state) = &current_task.kernel().security_state.state {
1414        if state.has_policy() {
1415            return selinux_hooks::task::bprm_creds_for_exec(
1416                &state.server,
1417                current_task,
1418                resolved_program,
1419            );
1420        } else {
1421            // SELinux is enabled but not yet configured, so apply the "init" SID.
1422            let previous_sid = current_task.current_creds().security_state.current_sid;
1423            resolved_program.creds.security_state =
1424                TaskAttrs::for_transition(InitialSid::Init.into(), previous_sid);
1425        }
1426    }
1427    Ok(())
1428}
1429
1430/// Applies pre-commit security restrictions (such as revoking inaccessible file descriptors)
1431/// immediately before [`ResolvedProgram::creds`] are committed to the calling task.
1432///
1433/// Corresponds to the `bprm_committing_creds()` LSM hook.
1434pub fn bprm_committing_creds(
1435    current_task: &CurrentTask,
1436    resolved_program: &ResolvedProgram,
1437) -> Result<(), Errno> {
1438    track_hook_duration!("security.hooks.bprm_committing_creds");
1439    if_selinux_else_default_ok(current_task, |security_server| {
1440        selinux_hooks::task::bprm_committing_creds(security_server, current_task, resolved_program);
1441        Ok(())
1442    })
1443}
1444
1445/// Called immediately after new credentials have been applied to the process during `exec()`.
1446///
1447/// Corresponds to the `bprm_committed_creds()` LSM hook.
1448pub fn bprm_committed_creds(current_task: &CurrentTask) -> Result<(), Errno> {
1449    track_hook_duration!("security.hooks.bprm_committed_creds");
1450    if_selinux_else_default_ok(current_task, |security_server| {
1451        selinux_hooks::task::bprm_committed_creds(security_server, current_task);
1452        Ok(())
1453    })
1454}
1455
1456/// Checks if `source` may exercise the "getsched" permission on `target`.
1457/// Corresponds to the `task_getscheduler()` LSM hook.
1458pub fn check_task_getscheduler_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1459    track_hook_duration!("security.hooks.task_getscheduler");
1460    if_selinux_else_default_ok(source, |security_server| {
1461        selinux_hooks::task::check_getsched_access(
1462            &selinux_hooks::build_permission_check(source, security_server),
1463            &source,
1464            &target,
1465        )
1466    })
1467}
1468
1469/// Checks if setsched is allowed.
1470/// Corresponds to the `task_setscheduler()` LSM hook.
1471pub fn check_task_setscheduler_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1472    track_hook_duration!("security.hooks.task_setscheduler");
1473    if_selinux_else_default_ok(source, |security_server| {
1474        selinux_hooks::task::check_setsched_access(
1475            &selinux_hooks::build_permission_check(source, security_server),
1476            &source,
1477            &target,
1478        )
1479    })
1480}
1481
1482/// Checks if setting nice value is allowed.
1483/// Corresponds to the `task_setnice()` LSM hook.
1484pub fn check_task_setnice_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1485    track_hook_duration!("security.hooks.check_task_setnice_access");
1486    if_selinux_else_default_ok(source, |security_server| {
1487        selinux_hooks::task::check_setsched_access(
1488            &selinux_hooks::build_permission_check(source, security_server),
1489            &source,
1490            &target,
1491        )
1492    })
1493}
1494
1495/// Checks if getpgid is allowed.
1496/// Corresponds to the `task_getpgid()` LSM hook.
1497pub fn check_getpgid_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1498    track_hook_duration!("security.hooks.check_getpgid_access");
1499    if_selinux_else_default_ok(source, |security_server| {
1500        selinux_hooks::task::check_getpgid_access(
1501            &selinux_hooks::build_permission_check(source, security_server),
1502            &source,
1503            &target,
1504        )
1505    })
1506}
1507
1508/// Checks if setpgid is allowed.
1509/// Corresponds to the `task_setpgid()` LSM hook.
1510pub fn check_setpgid_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1511    track_hook_duration!("security.hooks.check_setpgid_access");
1512    if_selinux_else_default_ok(source, |security_server| {
1513        selinux_hooks::task::check_setpgid_access(
1514            &selinux_hooks::build_permission_check(source, security_server),
1515            &source,
1516            &target,
1517        )
1518    })
1519}
1520
1521/// Called when the current task queries the session Id of the `target` task.
1522/// Corresponds to the `task_getsid()` LSM hook.
1523pub fn check_task_getsid(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1524    track_hook_duration!("security.hooks.check_task_getsid");
1525    if_selinux_else_default_ok(source, |security_server| {
1526        selinux_hooks::task::check_task_getsid(
1527            &selinux_hooks::build_permission_check(source, security_server),
1528            &source,
1529            &target,
1530        )
1531    })
1532}
1533
1534/// Called when the current task queries the Linux capabilities of the `target` task.
1535/// Corresponds to the `capget()` LSM hook.
1536pub fn check_getcap_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1537    track_hook_duration!("security.hooks.check_getcap_access");
1538    if_selinux_else_default_ok(source, |security_server| {
1539        selinux_hooks::task::check_getcap_access(
1540            &selinux_hooks::build_permission_check(source, security_server),
1541            &source,
1542            &target,
1543        )
1544    })
1545}
1546
1547/// Called when the current task attempts to set the Linux capabilities of the `target`
1548/// task.
1549/// Corresponds to the `capset()` LSM hook.
1550pub fn check_setcap_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
1551    track_hook_duration!("security.hooks.check_setcap_access");
1552    if_selinux_else_default_ok(source, |security_server| {
1553        selinux_hooks::task::check_setcap_access(
1554            &selinux_hooks::build_permission_check(source, security_server),
1555            &source,
1556            &target,
1557        )
1558    })
1559}
1560
1561/// Checks if sending a signal is allowed.
1562/// Corresponds to the `task_kill()` LSM hook.
1563pub fn check_signal_access(
1564    source: &CurrentTask,
1565    target: &Task,
1566    signal: Signal,
1567) -> Result<(), Errno> {
1568    track_hook_duration!("security.hooks.check_signal_access");
1569    if_selinux_else_default_ok(source, |security_server| {
1570        selinux_hooks::task::check_signal_access(
1571            &selinux_hooks::build_permission_check(source, security_server),
1572            &source,
1573            &target,
1574            signal,
1575        )
1576    })
1577}
1578
1579/// Checks if a particular syslog action is allowed.
1580/// Corresponds to the `task_syslog()` LSM hook.
1581pub fn check_syslog_access(source: &CurrentTask, action: SyslogAction) -> Result<(), Errno> {
1582    track_hook_duration!("security.hooks.check_syslog_access");
1583    if_selinux_else_default_ok(source, |security_server| {
1584        selinux_hooks::task::check_syslog_access(
1585            &selinux_hooks::build_permission_check(source, security_server),
1586            &source,
1587            action,
1588        )
1589    })
1590}
1591
1592/// Checks whether the `parent_tracer_task` is allowed to trace the `current_task`.
1593/// Corresponds to the `ptrace_traceme()` LSM hook.
1594pub fn ptrace_traceme(current_task: &CurrentTask, parent_tracer_task: &Task) -> Result<(), Errno> {
1595    track_hook_duration!("security.hooks.ptrace_traceme");
1596    yama::ptrace_traceme(current_task, parent_tracer_task)?;
1597    common_cap::ptrace_traceme(current_task, parent_tracer_task)?;
1598    if_selinux_else_default_ok(current_task, |security_server| {
1599        selinux_hooks::task::ptrace_traceme(
1600            &selinux_hooks::build_permission_check(current_task, security_server),
1601            current_task,
1602            parent_tracer_task,
1603        )
1604    })
1605}
1606
1607/// Checks whether the current `current_task` is allowed to trace `tracee_task`.
1608/// Corresponds to the `ptrace_access_check()` LSM hook.
1609pub fn ptrace_access_check(
1610    current_task: &CurrentTask,
1611    tracee_task: &Task,
1612    mode: PtraceAccessMode,
1613) -> Result<(), Errno> {
1614    track_hook_duration!("security.hooks.ptrace_access_check");
1615    yama::ptrace_access_check(current_task, tracee_task, mode)?;
1616    common_cap::ptrace_access_check(current_task, tracee_task, mode)?;
1617    if_selinux_else_default_ok(current_task, |security_server| {
1618        selinux_hooks::task::ptrace_access_check(
1619            &selinux_hooks::build_permission_check(current_task, security_server),
1620            current_task,
1621            tracee_task,
1622            mode,
1623        )
1624    })
1625}
1626
1627/// Called when the current task calls prlimit on a different task.
1628/// Corresponds to the `task_prlimit()` LSM hook.
1629pub fn task_prlimit(
1630    source: &CurrentTask,
1631    target: &Task,
1632    check_get_rlimit: bool,
1633    check_set_rlimit: bool,
1634) -> Result<(), Errno> {
1635    track_hook_duration!("security.hooks.task_prlimit");
1636    if_selinux_else_default_ok(source, |security_server| {
1637        selinux_hooks::task::task_prlimit(
1638            &selinux_hooks::build_permission_check(source, security_server),
1639            &source,
1640            &target,
1641            check_get_rlimit,
1642            check_set_rlimit,
1643        )
1644    })
1645}
1646
1647/// Called before `source` sets the resource limits of `target` from `old_limit` to `new_limit`.
1648/// Corresponds to the `security_task_setrlimit` hook.
1649pub fn task_setrlimit(
1650    source: &CurrentTask,
1651    target: &Task,
1652    old_limit: rlimit,
1653    new_limit: rlimit,
1654) -> Result<(), Errno> {
1655    track_hook_duration!("security.hooks.task_setrlimit");
1656    if_selinux_else_default_ok(source, |security_server| {
1657        selinux_hooks::task::task_setrlimit(
1658            &selinux_hooks::build_permission_check(source, security_server),
1659            &source,
1660            &target,
1661            old_limit,
1662            new_limit,
1663        )
1664    })
1665}
1666
1667/// Check permission before mounting `fs`.
1668/// Corresponds to the `sb_kern_mount()` LSM hook.
1669pub fn sb_kern_mount(current_task: &CurrentTask, fs: &FileSystem) -> Result<(), Errno> {
1670    track_hook_duration!("security.hooks.sb_kern_mount");
1671    if_selinux_else_default_ok(current_task, |security_server| {
1672        selinux_hooks::superblock::sb_kern_mount(
1673            &selinux_hooks::build_permission_check(current_task, security_server),
1674            current_task,
1675            fs,
1676        )
1677    })
1678}
1679
1680/// Check permission before mounting to `path`. `flags` contains the mount flags that determine the
1681/// kind of mount operation done, and therefore the permissions that the caller requires.
1682/// Corresponds to the `sb_mount()` LSM hook.
1683pub fn sb_mount(
1684    current_task: &CurrentTask,
1685    path: &NamespaceNode,
1686    flags: MountFlags,
1687) -> Result<(), Errno> {
1688    track_hook_duration!("security.hooks.sb_mount");
1689    if_selinux_else_default_ok(current_task, |security_server| {
1690        selinux_hooks::superblock::sb_mount(
1691            &selinux_hooks::build_permission_check(current_task, security_server),
1692            current_task,
1693            path,
1694            flags,
1695        )
1696    })
1697}
1698
1699/// Checks permission before remounting `mount` with `new_mount_params`.
1700/// Corresponds to the `sb_remount()` LSM hook.
1701pub fn sb_remount(
1702    current_task: &CurrentTask,
1703    mount: &Mount,
1704    new_mount_options: FileSystemMountOptions,
1705) -> Result<(), Errno> {
1706    track_hook_duration!("security.hooks.sb_remount");
1707    if_selinux_else_default_ok(current_task, |security_server| {
1708        selinux_hooks::superblock::sb_remount(security_server, mount, new_mount_options)
1709    })
1710}
1711
1712/// Returns a `Display` implementation that Writes the LSM mount options of `fs` into `buf`.
1713/// Corresponds to the `sb_show_options` LSM hook.
1714pub fn sb_show_options<'a>(
1715    _kernel: &Kernel,
1716    fs: &'a FileSystem,
1717) -> Result<impl std::fmt::Display + 'a, Errno> {
1718    track_hook_duration!("security.hooks.sb_show_options");
1719    selinux_hooks::superblock::sb_show_options(fs)
1720}
1721
1722/// Checks if `current_task` has the permission to get the filesystem statistics of `fs`.
1723/// Corresponds to the `sb_statfs()` LSM hook.
1724pub fn sb_statfs(current_task: &CurrentTask, fs: &FileSystem) -> Result<(), Errno> {
1725    track_hook_duration!("security.hooks.sb_statfs");
1726    if_selinux_else_default_ok(current_task, |security_server| {
1727        selinux_hooks::superblock::sb_statfs(
1728            &selinux_hooks::build_permission_check(current_task, security_server),
1729            current_task,
1730            fs,
1731        )
1732    })
1733}
1734
1735/// Checks if `current_task` has the permission to unmount the filesystem mounted on
1736/// `node` using the unmount flags `flags`.
1737/// Corresponds to the `sb_umount()` LSM hook.
1738pub fn sb_umount(
1739    current_task: &CurrentTask,
1740    node: &NamespaceNode,
1741    flags: UnmountFlags,
1742) -> Result<(), Errno> {
1743    track_hook_duration!("security.hooks.sb_umount");
1744    if_selinux_else_default_ok(current_task, |security_server| {
1745        selinux_hooks::superblock::sb_umount(
1746            &selinux_hooks::build_permission_check(current_task, security_server),
1747            current_task,
1748            node,
1749            flags,
1750        )
1751    })
1752}
1753
1754/// Checks if `current_task` has the permission to read file attributes for  `fs_node`.
1755/// Corresponds to the `inode_getattr()` hook.
1756pub fn check_fs_node_getattr_access(
1757    current_task: &CurrentTask,
1758    fs_node: &FsNode,
1759) -> Result<(), Errno> {
1760    track_hook_duration!("security.hooks.check_fs_node_getattr_access");
1761    if_selinux_else_default_ok(current_task, |security_server| {
1762        selinux_hooks::fs_node::check_fs_node_getattr_access(security_server, current_task, fs_node)
1763    })
1764}
1765
1766/// Returns true if the security subsystem should skip capability checks on access to the named
1767/// attribute, false otherwise.
1768pub fn fs_node_xattr_skipcap(name: &FsStr) -> bool {
1769    selinux_hooks::fs_node::fs_node_xattr_skipcap(name)
1770}
1771
1772/// This is called by Starnix even for filesystems which support extended attributes, unlike Linux
1773/// LSM.
1774/// Partially corresponds to the `inode_setxattr()` LSM hook: It is equivalent to
1775/// `inode_setxattr()` for non-security xattrs, while `fs_node_setsecurity()` is always called for
1776/// security xattrs. See also [`fs_node_setsecurity()`].
1777pub fn check_fs_node_setxattr_access(
1778    current_task: &CurrentTask,
1779    fs_node: &FsNode,
1780    name: &FsStr,
1781    value: &FsStr,
1782    op: XattrOp,
1783) -> Result<(), Errno> {
1784    track_hook_duration!("security.hooks.check_fs_node_setxattr_access");
1785    common_cap::fs_node_setxattr(current_task, fs_node, name, value, op)?;
1786    if_selinux_else_default_ok(current_task, |security_server| {
1787        selinux_hooks::fs_node::check_fs_node_setxattr_access(
1788            security_server,
1789            current_task,
1790            fs_node,
1791            name,
1792            value,
1793            op,
1794        )
1795    })
1796}
1797
1798/// Corresponds to the `inode_getxattr()` LSM hook.
1799pub fn check_fs_node_getxattr_access(
1800    current_task: &CurrentTask,
1801    fs_node: &FsNode,
1802    name: &FsStr,
1803) -> Result<(), Errno> {
1804    track_hook_duration!("security.hooks.check_fs_node_getxattr_access");
1805    if_selinux_else_default_ok(current_task, |security_server| {
1806        selinux_hooks::fs_node::check_fs_node_getxattr_access(
1807            security_server,
1808            current_task,
1809            fs_node,
1810            name,
1811        )
1812    })
1813}
1814
1815/// Corresponds to the `inode_listxattr()` LSM hook.
1816pub fn check_fs_node_listxattr_access(
1817    current_task: &CurrentTask,
1818    fs_node: &FsNode,
1819) -> Result<(), Errno> {
1820    track_hook_duration!("security.hooks.check_fs_node_listxattr_access");
1821    if_selinux_else_default_ok(current_task, |security_server| {
1822        selinux_hooks::fs_node::check_fs_node_listxattr_access(
1823            security_server,
1824            current_task,
1825            fs_node,
1826        )
1827    })
1828}
1829
1830/// Corresponds to the `inode_removexattr()` LSM hook.
1831pub fn check_fs_node_removexattr_access(
1832    current_task: &CurrentTask,
1833    fs_node: &FsNode,
1834    name: &FsStr,
1835) -> Result<(), Errno> {
1836    track_hook_duration!("security.hooks.check_fs_node_removexattr_access");
1837    common_cap::fs_node_removexattr(current_task, fs_node, name)?;
1838    if_selinux_else_default_ok(current_task, |security_server| {
1839        selinux_hooks::fs_node::check_fs_node_removexattr_access(
1840            security_server,
1841            current_task,
1842            fs_node,
1843            name,
1844        )
1845    })
1846}
1847
1848/// If SELinux is enabled and `fs_node` is in a filesystem without xattr support, returns the xattr
1849/// name for the security label associated with inode. Otherwise returns None.
1850///
1851/// This hook is called from the `listxattr` syscall.
1852///
1853/// Corresponds to the `inode_listsecurity()` LSM hook.
1854pub fn fs_node_listsecurity(current_task: &CurrentTask, fs_node: &FsNode) -> Option<FsString> {
1855    track_hook_duration!("security.hooks.fs_node_listsecurity");
1856    if_selinux_else(
1857        current_task,
1858        |_| selinux_hooks::fs_node::fs_node_listsecurity(fs_node),
1859        || None,
1860    )
1861}
1862
1863/// Returns the value of the specified "security.*" attribute for `fs_node`.
1864/// If SELinux is enabled then requests for the "security.selinux" attribute will return the
1865/// Security Context corresponding to the SID with which `fs_node` has been labeled, even if the
1866/// node's file system does not generally support extended attributes.
1867/// If SELinux is not enabled, or the node is not labeled with a SID, then the call is delegated to
1868/// the [`crate::vfs::FsNodeOps`], so the returned value may not be a valid Security Context.
1869/// Corresponds to the `inode_getsecurity()` LSM hook.
1870pub fn fs_node_getsecurity(
1871    current_task: &CurrentTask,
1872    fs_node: &FsNode,
1873    name: &FsStr,
1874    max_size: usize,
1875) -> Result<ValueOrSize<FsString>, Errno> {
1876    track_hook_duration!("security.hooks.fs_node_getsecurity");
1877    if_selinux_else(
1878        current_task,
1879        |security_server| {
1880            selinux_hooks::fs_node::fs_node_getsecurity(
1881                security_server,
1882                current_task,
1883                fs_node,
1884                name,
1885                max_size,
1886            )
1887        },
1888        || fs_node.ops().get_xattr(fs_node, current_task, name, max_size),
1889    )
1890}
1891
1892/// Called when an extended attribute with "security."-prefixed `name` is being set, after having
1893/// passed the discretionary and `check_fs_node_setxattr_access()` permission-checks.
1894/// This allows the LSM (e.g. SELinux) to update internal state as necessary for xattr changes.
1895///
1896/// Partially corresponds to the `inode_setsecurity()` and `inode_post_setxattr()` LSM hooks.
1897pub fn fs_node_setsecurity(
1898    current_task: &CurrentTask,
1899    fs_node: &FsNode,
1900    name: &FsStr,
1901    value: &FsStr,
1902    op: XattrOp,
1903) -> Result<(), Errno> {
1904    track_hook_duration!("security.hooks.fs_node_setsecurity");
1905    if_selinux_else(
1906        current_task,
1907        |security_server| {
1908            selinux_hooks::fs_node::fs_node_setsecurity(
1909                security_server,
1910                current_task,
1911                fs_node,
1912                name,
1913                value,
1914                op,
1915            )
1916        },
1917        || fs_node.ops().set_xattr(fs_node, current_task, name, value, op),
1918    )
1919}
1920
1921/// Checks whether `current_task` can perform the given bpf `cmd`. This hook is called from the
1922/// `sys_bpf()` syscall after the attribute is copied into the kernel.
1923/// Corresponds to the `bpf()` LSM hook.
1924pub fn check_bpf_access<Attr: FromBytes>(
1925    current_task: &CurrentTask,
1926    cmd: bpf_cmd,
1927    attr: &Attr,
1928    attr_size: u32,
1929) -> Result<(), Errno> {
1930    track_hook_duration!("security.hooks.check_bpf_access");
1931    if_selinux_else_default_ok(current_task, |security_server| {
1932        selinux_hooks::bpf::check_bpf_access(security_server, current_task, cmd, attr, attr_size)
1933    })
1934}
1935
1936/// Checks whether `current_task` can create a bpf_map. This hook is called from the
1937/// `sys_bpf()` syscall when the kernel tries to generate and return a file descriptor for maps.
1938/// Corresponds to the `bpf_map()` LSM hook.
1939pub fn check_bpf_map_access(
1940    current_task: &CurrentTask,
1941    bpf_map_state: &BpfMapState,
1942    flags: PermissionFlags,
1943) -> Result<(), Errno> {
1944    track_hook_duration!("security.hooks.check_bpf_map_access");
1945    if_selinux_else_default_ok(current_task, |security_server| {
1946        let subject_sid = current_task_state(current_task).current_sid;
1947        selinux_hooks::bpf::check_bpf_map_access(
1948            security_server,
1949            current_task,
1950            subject_sid,
1951            bpf_map_state,
1952            flags,
1953        )
1954    })
1955}
1956
1957/// Checks whether `current_task` can create a bpf_program. This hook is called from the
1958/// `sys_bpf()` syscall when the kernel tries to generate and return a file descriptor for
1959/// programs.
1960/// Corresponds to the `bpf_prog()` LSM hook.
1961pub fn check_bpf_prog_access(
1962    current_task: &CurrentTask,
1963    bpf_program_state: &BpfProgState,
1964) -> Result<(), Errno> {
1965    track_hook_duration!("security.hooks.check_bpf_prog_access");
1966    if_selinux_else_default_ok(current_task, |security_server| {
1967        let subject_sid = current_task_state(current_task).current_sid;
1968        selinux_hooks::bpf::check_bpf_prog_access(
1969            security_server,
1970            current_task,
1971            subject_sid,
1972            bpf_program_state,
1973        )
1974    })
1975}
1976
1977/// Checks whether `current_task` has the correct permissions to monitor the given target task or
1978/// tasks.
1979/// Corresponds to the `perf_event_open` LSM hook.
1980pub fn check_perf_event_open_access(
1981    current_task: &CurrentTask,
1982    target_task_type: TargetTaskType<'_>,
1983    attr: &perf_event_attr,
1984    event_type: PerfEventType,
1985) -> Result<(), Errno> {
1986    track_hook_duration!("security.hooks.check_perf_event_open_access");
1987    if_selinux_else_default_ok(current_task, |security_server| {
1988        selinux_hooks::perf_event::check_perf_event_open_access(
1989            security_server,
1990            current_task,
1991            target_task_type,
1992            attr,
1993            event_type,
1994        )
1995    })
1996}
1997
1998/// Returns the security context to be assigned to a PerfEventFileState, based on the task that
1999/// creates it.
2000/// Corresponds to the `perf_event_alloc` LSM hook.
2001pub fn perf_event_alloc(current_task: &CurrentTask) -> PerfEventState {
2002    track_hook_duration!("security.hooks.perf_event_alloc");
2003    PerfEventState { state: selinux_hooks::perf_event::perf_event_alloc(current_task) }
2004}
2005
2006/// Checks whether `current_task` has the correct permissions to read the given `perf_event_file`
2007/// Corresponds to the `perf_event_read` LSM hook.
2008pub fn check_perf_event_read_access(
2009    current_task: &CurrentTask,
2010    perf_event_file: &PerfEventFile,
2011) -> Result<(), Errno> {
2012    track_hook_duration!("security.hooks.check_perf_event_read_access");
2013    if_selinux_else_default_ok(current_task, |security_server| {
2014        selinux_hooks::perf_event::check_perf_event_read_access(
2015            security_server,
2016            current_task,
2017            perf_event_file,
2018        )
2019    })
2020}
2021
2022/// Checks whether `current_task` has the correct permissions to write to the given `perf_event_file`.
2023/// Corresponds to the `perf_event_write` LSM hook.
2024pub fn check_perf_event_write_access(
2025    current_task: &CurrentTask,
2026    perf_event_file: &PerfEventFile,
2027) -> Result<(), Errno> {
2028    track_hook_duration!("security.hooks.check_perf_event_write_access");
2029    if_selinux_else_default_ok(current_task, |security_server| {
2030        selinux_hooks::perf_event::check_perf_event_write_access(
2031            security_server,
2032            current_task,
2033            perf_event_file,
2034        )
2035    })
2036}
2037
2038/// Identifies one of the Security Context attributes associated with a task.
2039#[derive(Debug, Clone, Copy, PartialEq)]
2040pub enum ProcAttr {
2041    Current,
2042    Exec,
2043    FsCreate,
2044    KeyCreate,
2045    Previous,
2046    SockCreate,
2047}
2048
2049/// Returns the Security Context associated with the `name`ed entry for the specified `target` task.
2050/// Corresponds to the `getprocattr()` LSM hook.
2051pub fn get_procattr(
2052    current_task: &CurrentTask,
2053    target: &Task,
2054    attr: ProcAttr,
2055) -> Result<Vec<u8>, Errno> {
2056    track_hook_duration!("security.hooks.get_procattr");
2057    if_selinux_else(
2058        current_task,
2059        |security_server| {
2060            selinux_hooks::task::get_procattr(security_server, current_task, target, attr)
2061        },
2062        // If SELinux is disabled then there are no values to return.
2063        || error!(EINVAL),
2064    )
2065}
2066
2067/// Sets the Security Context associated with the `name`ed entry for the current task.
2068/// Corresponds to the `setprocattr()` LSM hook.
2069pub fn set_procattr(
2070    current_task: &CurrentTask,
2071    attr: ProcAttr,
2072    context: &[u8],
2073) -> Result<(), Errno> {
2074    track_hook_duration!("security.hooks.set_procattr");
2075    if_selinux_else(
2076        current_task,
2077        |security_server| {
2078            selinux_hooks::task::set_procattr(security_server, current_task, attr, context)
2079        },
2080        // If SELinux is disabled then no writes are accepted.
2081        || error!(EINVAL),
2082    )
2083}
2084
2085/// Returns true if SELinux is enabled on the kernel for this task.
2086pub fn fs_is_xattr_labeled(fs: FileSystemHandle) -> bool {
2087    fs.security_state.state.supports_xattr()
2088}
2089
2090/// Stashes a reference to the selinuxfs null file for later use by hooks that remap
2091/// inaccessible file descriptors to null.
2092pub fn selinuxfs_init_null(current_task: &CurrentTask, null_fs_node: &FileHandle) {
2093    // Note: No `if_selinux_...` guard because hook is invoked inside selinuxfs initialization code;
2094    // i.e., hook is only invoked when selinux is enabled.
2095    selinux_hooks::selinuxfs::selinuxfs_init_null(current_task, null_fs_node)
2096}
2097
2098/// Called by the "selinuxfs" when a policy has been successfully loaded, to allow policy-dependent
2099/// initialization to be completed. This includes resolving labeling schemes and state for
2100/// file-systems mounted prior to policy load (e.g. the "selinuxfs" itself), and initializing
2101/// security state for any file nodes they may already contain.
2102// TODO: https://fxbug.dev/362917997 - Remove this when SELinux LSM is modularized.
2103pub fn selinuxfs_policy_loaded(current_task: &CurrentTask) {
2104    track_hook_duration!("security.hooks.selinuxfs_policy_loaded");
2105    selinux_hooks::selinuxfs::selinuxfs_policy_loaded(current_task)
2106}
2107
2108/// Used by the "selinuxfs" module to access the SELinux administration API, if enabled.
2109// TODO: https://fxbug.dev/335397745 - Return a more restricted API, or ...
2110// TODO: https://fxbug.dev/362917997 - Remove this when SELinux LSM is modularized.
2111pub fn selinuxfs_get_admin_api(current_task: &CurrentTask) -> Option<Arc<SecurityServer>> {
2112    current_task.kernel().security_state.state.as_ref().map(|state| state.server.clone())
2113}
2114
2115/// Used by the "selinuxfs" module to perform checks on SELinux API file accesses.
2116// TODO: https://fxbug.dev/362917997 - Remove this when SELinux LSM is modularized.
2117pub fn selinuxfs_check_access(
2118    current_task: &CurrentTask,
2119    permission: SecurityPermission,
2120) -> Result<(), Errno> {
2121    track_hook_duration!("security.hooks.selinuxfs_check_access");
2122    if_selinux_else_default_ok(current_task, |security_server| {
2123        selinux_hooks::selinuxfs::selinuxfs_check_access(security_server, current_task, permission)
2124    })
2125}
2126
2127/// Marks the credentials as being used for an internal operation. All SELinux permission checks
2128/// will be skipped on this task.
2129pub fn creds_start_internal_operation(current_task: &CurrentTask) -> Arc<Credentials> {
2130    track_hook_duration!("security.hooks.creds_start_internal_operation");
2131    let mut creds = Credentials::clone(&current_task.current_creds());
2132    creds.security_state.internal_operation = true;
2133    creds.into()
2134}
2135
2136pub mod testing {
2137    use super::{Arc, KernelState, SecurityServer, selinux_hooks};
2138    use starnix_sync::LockDepMutex;
2139    use std::sync::OnceLock;
2140    use std::sync::atomic::AtomicU64;
2141
2142    /// Used by Starnix' `testing.rs` to create `KernelState` wrapping a test-
2143    /// supplied `SecurityServer`.
2144    pub fn kernel_state(security_server: Option<Arc<SecurityServer>>) -> KernelState {
2145        let state = security_server.map(|server| selinux_hooks::KernelState {
2146            server,
2147            pending_file_systems: LockDepMutex::default(),
2148            selinuxfs_null: OnceLock::default(),
2149            access_denial_count: AtomicU64::new(0u64),
2150            has_policy: false.into(),
2151            _inspect_node: fuchsia_inspect::Node::default(),
2152        });
2153        KernelState { state }
2154    }
2155}
2156
2157#[cfg(test)]
2158mod tests {
2159    use super::*;
2160    use crate::security;
2161    use crate::security::selinux_hooks::get_cached_sid;
2162    use crate::security::selinux_hooks::testing::{
2163        self, spawn_kernel_with_selinux_hooks_test_policy_and_run,
2164    };
2165    use crate::testing::{create_task, spawn_kernel_and_run, spawn_kernel_with_selinux_and_run};
2166    use linux_uapi::XATTR_NAME_SELINUX;
2167    use selinux::InitialSid;
2168    use starnix_uapi::auth::PTRACE_MODE_ATTACH;
2169    use starnix_uapi::signals::SIGTERM;
2170
2171    const VALID_SECURITY_CONTEXT: &[u8] = b"u:object_r:test_valid_t:s0";
2172    const VALID_SECURITY_CONTEXT_WITH_NUL: &[u8] = b"u:object_r:test_valid_t:s0\0";
2173
2174    const DIFFERENT_VALID_SECURITY_CONTEXT: &[u8] = b"u:object_r:test_different_valid_t:s0";
2175    const DIFFERENT_VALID_SECURITY_CONTEXT_WITH_NUL: &[u8] =
2176        b"u:object_r:test_different_valid_t:s0\0";
2177
2178    const INVALID_SECURITY_CONTEXT_INTERNAL_NUL: &[u8] = b"u:object_r:test_valid_\0t:s0";
2179
2180    const INVALID_SECURITY_CONTEXT: &[u8] = b"not_a_u:object_r:test_valid_t:s0";
2181
2182    #[derive(Default, Debug, PartialEq)]
2183    enum TestHookResult {
2184        WasRun,
2185        WasNotRun,
2186        #[default]
2187        WasNotRunDefault,
2188    }
2189
2190    #[fuchsia::test]
2191    async fn if_selinux_else_disabled() {
2192        spawn_kernel_and_run(async |current_task| {
2193            assert!(current_task.kernel().security_state.state.is_none());
2194
2195            let check_result =
2196                if_selinux_else_default_ok(current_task, |_| Ok(TestHookResult::WasRun));
2197            assert_eq!(check_result, Ok(TestHookResult::WasNotRunDefault));
2198
2199            let run_else_result = if_selinux_else(
2200                current_task,
2201                |_| TestHookResult::WasRun,
2202                || TestHookResult::WasNotRun,
2203            );
2204            assert_eq!(run_else_result, TestHookResult::WasNotRun);
2205        })
2206        .await;
2207    }
2208
2209    #[fuchsia::test]
2210    async fn if_selinux_else_without_policy() {
2211        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2212            let check_result =
2213                if_selinux_else_default_ok(current_task, |_| Ok(TestHookResult::WasRun));
2214            assert_eq!(check_result, Ok(TestHookResult::WasNotRunDefault));
2215
2216            let run_else_result = if_selinux_else(
2217                current_task,
2218                |_| TestHookResult::WasRun,
2219                || TestHookResult::WasNotRun,
2220            );
2221            assert_eq!(run_else_result, TestHookResult::WasNotRun);
2222        })
2223        .await;
2224    }
2225
2226    #[fuchsia::test]
2227    async fn if_selinux_else_with_policy() {
2228        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2229            let check_result =
2230                if_selinux_else_default_ok(current_task, |_| Ok(TestHookResult::WasRun));
2231            assert_eq!(check_result, Ok(TestHookResult::WasRun));
2232
2233            let run_else_result = if_selinux_else(
2234                current_task,
2235                |_| TestHookResult::WasRun,
2236                || TestHookResult::WasNotRun,
2237            );
2238            assert_eq!(run_else_result, TestHookResult::WasRun);
2239        })
2240        .await;
2241    }
2242
2243    #[fuchsia::test]
2244    async fn task_create_access_allowed_for_selinux_disabled() {
2245        spawn_kernel_and_run(async |current_task| {
2246            assert!(current_task.kernel().security_state.state.is_none());
2247            assert_eq!(check_task_create_access(current_task), Ok(()));
2248        })
2249        .await;
2250    }
2251
2252    #[fuchsia::test]
2253    async fn task_create_access_allowed_for_permissive_mode() {
2254        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2255            security_server.set_enforcing(false);
2256            assert_eq!(check_task_create_access(current_task), Ok(()));
2257        })
2258        .await;
2259    }
2260
2261    #[fuchsia::test]
2262    async fn exec_access_allowed_for_selinux_disabled() {
2263        spawn_kernel_and_run(async |current_task| {
2264            assert!(current_task.kernel().security_state.state.is_none());
2265            let executable = testing::create_test_file(current_task);
2266            let file = testing::open_test_file(current_task, &executable);
2267            let mut resolved_program = testing::make_resolved_program(current_task, file);
2268            assert_eq!(bprm_creds_for_exec(current_task, &mut resolved_program), Ok(()));
2269        })
2270        .await;
2271    }
2272
2273    #[fuchsia::test]
2274    async fn exec_access_allowed_for_permissive_mode() {
2275        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2276            security_server.set_enforcing(false);
2277            let executable = testing::create_test_file(current_task);
2278            let file = testing::open_test_file(current_task, &executable);
2279            let mut resolved_program = testing::make_resolved_program(current_task, file);
2280            // Expect that access is granted.
2281            let result = bprm_creds_for_exec(current_task, &mut resolved_program);
2282            assert!(result.is_ok());
2283        })
2284        .await;
2285    }
2286
2287    #[fuchsia::test]
2288    async fn exec_no_state_update_for_selinux_disabled() {
2289        spawn_kernel_and_run(async |current_task| {
2290            let target_sid = InitialSid::Unlabeled.into();
2291
2292            assert!(selinux_hooks::current_task_state(current_task).current_sid != target_sid);
2293
2294            // Set exec_sid to cause the hook to apply a transition, to verify if it is updated or not.
2295            testing::mutate_attrs_for_test(current_task, |attrs| {
2296                attrs.exec_sid = Some(target_sid);
2297            });
2298
2299            let executable = testing::create_test_file(current_task);
2300            let file = testing::open_test_file(current_task, &executable);
2301            let mut resolved_program = testing::make_resolved_program(current_task, file);
2302
2303            let before_hook_sid = selinux_hooks::current_task_state(current_task).current_sid;
2304
2305            bprm_creds_for_exec(current_task, &mut resolved_program).unwrap();
2306            assert_eq!(resolved_program.creds.security_state.current_sid, before_hook_sid);
2307        })
2308        .await;
2309    }
2310
2311    #[fuchsia::test]
2312    async fn exec_initial_context_for_selinux_without_policy() {
2313        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2314            let elf_sid = InitialSid::Unlabeled.into();
2315            assert_ne!(selinux_hooks::current_task_state(current_task).current_sid, elf_sid);
2316            assert_ne!(
2317                selinux_hooks::current_task_state(current_task).current_sid,
2318                InitialSid::Init.into()
2319            );
2320
2321            // Set exec_sid to cause the hook to apply a transition, to verify if it is updated or not.
2322            testing::mutate_attrs_for_test(current_task, |attrs| {
2323                attrs.exec_sid = Some(elf_sid);
2324            });
2325
2326            let executable = testing::create_test_file(current_task);
2327            let file = testing::open_test_file(current_task, &executable);
2328            let mut resolved_program = testing::make_resolved_program(current_task, file);
2329
2330            bprm_creds_for_exec(current_task, &mut resolved_program).unwrap();
2331
2332            assert_eq!(resolved_program.creds.security_state.current_sid, InitialSid::Init.into());
2333        })
2334        .await;
2335    }
2336
2337    #[fuchsia::test]
2338    async fn exec_state_update_for_permissive_mode() {
2339        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2340            security_server.set_enforcing(false);
2341            let elf_sid = security_server
2342                .security_context_to_sid(b"u:object_r:fork_no_t:s0".into())
2343                .expect("invalid security context");
2344
2345            assert_ne!(elf_sid, selinux_hooks::current_task_state(current_task).current_sid);
2346
2347            // Set exec_sid to cause the hook to apply a transition, to verify if it is updated or not.
2348            testing::mutate_attrs_for_test(current_task, |attrs| {
2349                attrs.exec_sid = Some(elf_sid);
2350            });
2351
2352            let executable = testing::create_test_file(current_task);
2353            let file = testing::open_test_file(current_task, &executable);
2354            let mut resolved_program = testing::make_resolved_program(current_task, file);
2355
2356            bprm_creds_for_exec(current_task, &mut resolved_program).unwrap();
2357            assert_eq!(resolved_program.creds.security_state.current_sid, elf_sid);
2358        })
2359        .await;
2360    }
2361
2362    #[fuchsia::test]
2363    async fn getsched_access_allowed_for_selinux_disabled() {
2364        spawn_kernel_and_run(async |current_task| {
2365            let another_task = create_task(&current_task.kernel(), "another-task");
2366            assert_eq!(check_task_getscheduler_access(current_task, &another_task), Ok(()));
2367        })
2368        .await;
2369    }
2370
2371    #[fuchsia::test]
2372    async fn getsched_access_allowed_for_permissive_mode() {
2373        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2374            let another_task = create_task(&current_task.kernel(), "another-task");
2375            assert_eq!(check_task_getscheduler_access(current_task, &another_task), Ok(()));
2376        })
2377        .await;
2378    }
2379
2380    #[fuchsia::test]
2381    async fn setsched_access_allowed_for_selinux_disabled() {
2382        spawn_kernel_and_run(async |current_task| {
2383            let another_task = create_task(&current_task.kernel(), "another-task");
2384            assert_eq!(check_task_setscheduler_access(current_task, &another_task), Ok(()));
2385        })
2386        .await;
2387    }
2388
2389    #[fuchsia::test]
2390    async fn setsched_access_allowed_for_permissive_mode() {
2391        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2392            let another_task = create_task(&current_task.kernel(), "another-task");
2393            assert_eq!(check_task_setscheduler_access(current_task, &another_task), Ok(()));
2394        })
2395        .await;
2396    }
2397
2398    #[fuchsia::test]
2399    async fn getpgid_access_allowed_for_selinux_disabled() {
2400        spawn_kernel_and_run(async |current_task| {
2401            let another_task = create_task(&current_task.kernel(), "another-task");
2402            assert_eq!(check_getpgid_access(current_task, &another_task), Ok(()));
2403        })
2404        .await;
2405    }
2406
2407    #[fuchsia::test]
2408    async fn getpgid_access_allowed_for_permissive_mode() {
2409        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2410            let another_task = create_task(&current_task.kernel(), "another-task");
2411            assert_eq!(check_getpgid_access(current_task, &another_task), Ok(()));
2412        })
2413        .await;
2414    }
2415
2416    #[fuchsia::test]
2417    async fn setpgid_access_allowed_for_selinux_disabled() {
2418        spawn_kernel_and_run(async |current_task| {
2419            let another_task = create_task(&current_task.kernel(), "another-task");
2420            assert_eq!(check_setpgid_access(current_task, &another_task), Ok(()));
2421        })
2422        .await;
2423    }
2424
2425    #[fuchsia::test]
2426    async fn setpgid_access_allowed_for_permissive_mode() {
2427        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2428            let another_task = create_task(&current_task.kernel(), "another-task");
2429            assert_eq!(check_setpgid_access(current_task, &another_task), Ok(()));
2430        })
2431        .await;
2432    }
2433
2434    #[fuchsia::test]
2435    async fn task_getsid_allowed_for_selinux_disabled() {
2436        spawn_kernel_and_run(async |current_task| {
2437            let another_task = create_task(&current_task.kernel(), "another-task");
2438            assert_eq!(check_task_getsid(current_task, &another_task), Ok(()));
2439        })
2440        .await;
2441    }
2442
2443    #[fuchsia::test]
2444    async fn task_getsid_allowed_for_permissive_mode() {
2445        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2446            let another_task = create_task(&current_task.kernel(), "another-task");
2447            assert_eq!(check_task_getsid(current_task, &another_task), Ok(()));
2448        })
2449        .await;
2450    }
2451
2452    #[fuchsia::test]
2453    async fn signal_access_allowed_for_selinux_disabled() {
2454        spawn_kernel_and_run(async |current_task| {
2455            let another_task = create_task(&current_task.kernel(), "another-task");
2456            assert_eq!(check_signal_access(current_task, &another_task, SIGTERM), Ok(()));
2457        })
2458        .await;
2459    }
2460
2461    #[fuchsia::test]
2462    async fn signal_access_allowed_for_permissive_mode() {
2463        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2464            let another_task = create_task(&current_task.kernel(), "another-task");
2465            assert_eq!(check_signal_access(current_task, &another_task, SIGTERM), Ok(()));
2466        })
2467        .await;
2468    }
2469
2470    #[fuchsia::test]
2471    async fn ptrace_traceme_access_allowed_for_selinux_disabled() {
2472        spawn_kernel_and_run(async |current_task| {
2473            let another_task = create_task(&current_task.kernel(), "another-task");
2474            assert_eq!(ptrace_traceme(current_task, &another_task), Ok(()));
2475        })
2476        .await;
2477    }
2478
2479    #[fuchsia::test]
2480    async fn ptrace_traceme_access_allowed_for_permissive_mode() {
2481        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2482            let another_task = create_task(&current_task.kernel(), "another-task");
2483            assert_eq!(ptrace_traceme(current_task, &another_task), Ok(()));
2484        })
2485        .await;
2486    }
2487
2488    #[fuchsia::test]
2489    async fn ptrace_attach_access_allowed_for_selinux_disabled() {
2490        spawn_kernel_and_run(async |current_task| {
2491            let another_task = create_task(&current_task.kernel(), "another-task");
2492            assert_eq!(
2493                ptrace_access_check(current_task, &another_task, PTRACE_MODE_ATTACH),
2494                Ok(())
2495            );
2496        })
2497        .await;
2498    }
2499
2500    #[fuchsia::test]
2501    async fn ptrace_attach_access_allowed_for_permissive_mode() {
2502        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2503            let another_task = create_task(&current_task.kernel(), "another-task");
2504            assert_eq!(
2505                ptrace_access_check(current_task, &another_task, PTRACE_MODE_ATTACH),
2506                Ok(())
2507            );
2508        })
2509        .await;
2510    }
2511
2512    #[fuchsia::test]
2513    async fn task_prlimit_access_allowed_for_selinux_disabled() {
2514        spawn_kernel_and_run(async |current_task| {
2515            let another_task = create_task(&current_task.kernel(), "another-task");
2516            assert_eq!(task_prlimit(current_task, &another_task, true, true), Ok(()));
2517        })
2518        .await;
2519    }
2520
2521    #[fuchsia::test]
2522    async fn task_prlimit_access_allowed_for_permissive_mode() {
2523        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2524            let another_task = create_task(&current_task.kernel(), "another-task");
2525            assert_eq!(task_prlimit(current_task, &another_task, true, true), Ok(()));
2526        })
2527        .await;
2528    }
2529
2530    #[fuchsia::test]
2531    async fn fs_node_task_to_fs_node_noop_selinux_disabled() {
2532        spawn_kernel_and_run(async |current_task| {
2533            let node = &testing::create_test_file(current_task).entry.node;
2534            task_to_fs_node(current_task, &current_task.task, &node);
2535            assert_eq!(None, selinux_hooks::get_cached_sid(node));
2536        })
2537        .await;
2538    }
2539
2540    #[fuchsia::test]
2541    async fn fs_node_setsecurity_selinux_disabled_only_sets_xattr() {
2542        spawn_kernel_and_run(async |current_task| {
2543            let node = &testing::create_test_file(current_task).entry.node;
2544
2545            fs_node_setsecurity(
2546                &current_task,
2547                &node,
2548                XATTR_NAME_SELINUX.to_bytes().into(),
2549                VALID_SECURITY_CONTEXT.into(),
2550                XattrOp::Set,
2551            )
2552            .expect("set_xattr(security.selinux) failed");
2553
2554            assert_eq!(None, selinux_hooks::get_cached_sid(node));
2555        })
2556        .await;
2557    }
2558
2559    #[fuchsia::test]
2560    async fn fs_node_setsecurity_selinux_without_policy_only_sets_xattr() {
2561        spawn_kernel_with_selinux_and_run(async |current_task, _security_server| {
2562            let node = &testing::create_test_file(current_task).entry.node;
2563            fs_node_setsecurity(
2564                &current_task,
2565                &node,
2566                XATTR_NAME_SELINUX.to_bytes().into(),
2567                VALID_SECURITY_CONTEXT.into(),
2568                XattrOp::Set,
2569            )
2570            .expect("set_xattr(security.selinux) failed");
2571
2572            assert_eq!(None, selinux_hooks::get_cached_sid(node));
2573        })
2574        .await;
2575    }
2576
2577    #[fuchsia::test]
2578    async fn fs_node_setsecurity_selinux_permissive_sets_xattr_and_label() {
2579        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2580            security_server.set_enforcing(false);
2581            let expected_sid = security_server
2582                .security_context_to_sid(VALID_SECURITY_CONTEXT.into())
2583                .expect("no SID for VALID_SECURITY_CONTEXT");
2584            let node = &testing::create_test_file(&current_task).entry.node;
2585
2586            // Safeguard against a false positive by ensuring `expected_sid` is not already the file's label.
2587            assert_ne!(Some(expected_sid), selinux_hooks::get_cached_sid(node));
2588
2589            fs_node_setsecurity(
2590                &current_task,
2591                &node,
2592                XATTR_NAME_SELINUX.to_bytes().into(),
2593                VALID_SECURITY_CONTEXT.into(),
2594                XattrOp::Set,
2595            )
2596            .expect("set_xattr(security.selinux) failed");
2597
2598            // Verify that the SID now cached on the node is that SID
2599            // corresponding to VALID_SECURITY_CONTEXT.
2600            assert_eq!(Some(expected_sid), selinux_hooks::get_cached_sid(node));
2601        })
2602        .await;
2603    }
2604
2605    #[fuchsia::test]
2606    async fn fs_node_setsecurity_not_selinux_only_sets_xattr() {
2607        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2608            let valid_security_context_sid = security_server
2609                .security_context_to_sid(VALID_SECURITY_CONTEXT.into())
2610                .expect("no SID for VALID_SECURITY_CONTEXT");
2611            let node = &testing::create_test_file(current_task).entry.node;
2612            // The label assigned to the test file on creation must differ from
2613            // VALID_SECURITY_CONTEXT, otherwise this test may return a false
2614            // positive.
2615            let whatever_sid = selinux_hooks::get_cached_sid(node);
2616            assert_ne!(Some(valid_security_context_sid), whatever_sid);
2617
2618            fs_node_setsecurity(
2619                &current_task,
2620                &node,
2621                "security.selinu!".into(), // Note: name != "security.selinux".
2622                VALID_SECURITY_CONTEXT.into(),
2623                XattrOp::Set,
2624            )
2625            .expect("set_xattr(security.selinux) failed");
2626
2627            // Verify that the node's SID (whatever it was) has not changed.
2628            assert_eq!(whatever_sid, selinux_hooks::get_cached_sid(node));
2629        })
2630        .await;
2631    }
2632
2633    #[fuchsia::test]
2634    async fn fs_node_setsecurity_selinux_enforcing_invalid_context_fails() {
2635        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2636            let node = &testing::create_test_file(current_task).entry.node;
2637
2638            let before_sid = selinux_hooks::get_cached_sid(node);
2639            assert_ne!(Some(InitialSid::Unlabeled.into()), before_sid);
2640
2641            assert!(
2642                check_fs_node_setxattr_access(
2643                    &current_task,
2644                    &node,
2645                    XATTR_NAME_SELINUX.to_bytes().into(),
2646                    "!".into(), // Note: Not a valid security context.
2647                    XattrOp::Set,
2648                )
2649                .is_err()
2650            );
2651
2652            assert_eq!(before_sid, selinux_hooks::get_cached_sid(node));
2653        })
2654        .await;
2655    }
2656
2657    #[fuchsia::test]
2658    async fn fs_node_setsecurity_selinux_permissive_invalid_context_sets_xattr_and_label() {
2659        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2660            security_server.set_enforcing(false);
2661            let node = &testing::create_test_file(current_task).entry.node;
2662
2663            assert_ne!(Some(InitialSid::Unlabeled.into()), selinux_hooks::get_cached_sid(node));
2664
2665            fs_node_setsecurity(
2666                &current_task,
2667                &node,
2668                XATTR_NAME_SELINUX.to_bytes().into(),
2669                "!".into(), // Note: Not a valid security context.
2670                XattrOp::Set,
2671            )
2672            .expect("set_xattr(security.selinux) failed");
2673
2674            assert_eq!(Some(InitialSid::Unlabeled.into()), selinux_hooks::get_cached_sid(node));
2675        })
2676        .await;
2677    }
2678
2679    #[fuchsia::test]
2680    async fn fs_node_setsecurity_different_sid_for_different_context() {
2681        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2682            let node = &testing::create_test_file(current_task).entry.node;
2683
2684            fs_node_setsecurity(
2685                &current_task,
2686                &node,
2687                XATTR_NAME_SELINUX.to_bytes().into(),
2688                VALID_SECURITY_CONTEXT.into(),
2689                XattrOp::Set,
2690            )
2691            .expect("set_xattr(security.selinux) failed");
2692
2693            assert!(selinux_hooks::get_cached_sid(node).is_some());
2694
2695            let first_sid = selinux_hooks::get_cached_sid(node).unwrap();
2696            fs_node_setsecurity(
2697                &current_task,
2698                &node,
2699                XATTR_NAME_SELINUX.to_bytes().into(),
2700                DIFFERENT_VALID_SECURITY_CONTEXT.into(),
2701                XattrOp::Set,
2702            )
2703            .expect("set_xattr(security.selinux) failed");
2704
2705            assert!(selinux_hooks::get_cached_sid(node).is_some());
2706
2707            let second_sid = selinux_hooks::get_cached_sid(node).unwrap();
2708
2709            assert_ne!(first_sid, second_sid);
2710        })
2711        .await;
2712    }
2713
2714    #[fuchsia::test]
2715    async fn fs_node_getsecurity_returns_cached_context() {
2716        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2717            let node = &testing::create_test_file(current_task).entry.node;
2718
2719            // Set a mismatched value in `node`'s "security.seliux" attribute.
2720            const TEST_VALUE: &str = "Something Random";
2721            node.ops()
2722                .set_xattr(
2723                    node,
2724                    current_task,
2725                    XATTR_NAME_SELINUX.to_bytes().into(),
2726                    TEST_VALUE.into(),
2727                    XattrOp::Set,
2728                )
2729                .expect("set_xattr(security.selinux) failed");
2730
2731            // Attach a valid SID to the `node`.
2732            let sid = security_server
2733                .security_context_to_sid(VALID_SECURITY_CONTEXT.into())
2734                .expect("security context to SID");
2735            selinux_hooks::set_cached_sid(&node, sid);
2736
2737            // Reading the security attribute should return the Security Context for the SID, rather than delegating.
2738            let result =
2739                fs_node_getsecurity(current_task, node, XATTR_NAME_SELINUX.to_bytes().into(), 4096);
2740            assert_eq!(
2741                result,
2742                Ok(ValueOrSize::Value(FsString::new(VALID_SECURITY_CONTEXT_WITH_NUL.into())))
2743            );
2744        })
2745        .await;
2746    }
2747
2748    #[fuchsia::test]
2749    async fn fs_node_getsecurity_delegates_to_get_xattr() {
2750        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2751            let node = &testing::create_test_file(current_task).entry.node;
2752
2753            // Set an invalid value in `node`'s "security.selinux" attribute.
2754            // This requires SELinux to be in permissive mode, otherwise the "relabelto" permission check will fail.
2755            security_server.set_enforcing(false);
2756            const TEST_VALUE: &str = "Something Random";
2757            fs_node_setsecurity(
2758                &current_task,
2759                node,
2760                XATTR_NAME_SELINUX.to_bytes().into(),
2761                TEST_VALUE.into(),
2762                XattrOp::Set,
2763            )
2764            .expect("set_xattr(security.selinux) failed");
2765            security_server.set_enforcing(true);
2766
2767            // Reading the security attribute should pass-through to read the value from the file system.
2768            let result =
2769                fs_node_getsecurity(current_task, node, XATTR_NAME_SELINUX.to_bytes().into(), 4096);
2770            assert_eq!(result, Ok(ValueOrSize::Value(FsString::new(TEST_VALUE.into()))));
2771        })
2772        .await;
2773    }
2774
2775    #[fuchsia::test]
2776    async fn set_get_procattr() {
2777        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2778            assert_eq!(get_procattr(current_task, current_task, ProcAttr::Exec), Ok(Vec::new()));
2779
2780            assert_eq!(
2781                // Test policy allows "kernel_t" tasks to set the "exec" context.
2782                set_procattr(current_task, ProcAttr::Exec, VALID_SECURITY_CONTEXT.into()),
2783                Ok(())
2784            );
2785
2786            assert_eq!(
2787                // Test policy does not allow "kernel_t" tasks to set the "sockcreate" context.
2788                set_procattr(
2789                    current_task,
2790                    ProcAttr::SockCreate,
2791                    DIFFERENT_VALID_SECURITY_CONTEXT.into()
2792                ),
2793                error!(EACCES)
2794            );
2795
2796            assert_eq!(
2797                // It is never permitted to set the "previous" context.
2798                set_procattr(
2799                    current_task,
2800                    ProcAttr::Previous,
2801                    DIFFERENT_VALID_SECURITY_CONTEXT.into()
2802                ),
2803                error!(EINVAL)
2804            );
2805
2806            assert_eq!(
2807                // Cannot set an invalid context.
2808                set_procattr(current_task, ProcAttr::Exec, INVALID_SECURITY_CONTEXT.into()),
2809                error!(EINVAL)
2810            );
2811
2812            assert_eq!(
2813                get_procattr(current_task, current_task, ProcAttr::Exec),
2814                Ok(VALID_SECURITY_CONTEXT_WITH_NUL.into())
2815            );
2816
2817            assert!(get_procattr(current_task, current_task, ProcAttr::Current).is_ok());
2818        })
2819        .await;
2820    }
2821
2822    #[fuchsia::test]
2823    async fn set_get_procattr_with_nulls() {
2824        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2825            assert_eq!(get_procattr(current_task, current_task, ProcAttr::Exec), Ok(Vec::new()));
2826
2827            assert_eq!(
2828                // Setting a Context with a string with trailing null(s) should work, if the Context is valid.
2829                set_procattr(current_task, ProcAttr::Exec, VALID_SECURITY_CONTEXT_WITH_NUL.into()),
2830                Ok(())
2831            );
2832
2833            assert_eq!(
2834                // Nulls in the middle of an otherwise valid Context truncate it, rendering it invalid.
2835                set_procattr(
2836                    current_task,
2837                    ProcAttr::FsCreate,
2838                    INVALID_SECURITY_CONTEXT_INTERNAL_NUL.into()
2839                ),
2840                error!(EINVAL)
2841            );
2842
2843            assert_eq!(
2844                get_procattr(current_task, current_task, ProcAttr::Exec),
2845                Ok(VALID_SECURITY_CONTEXT_WITH_NUL.into())
2846            );
2847
2848            assert_eq!(
2849                get_procattr(current_task, current_task, ProcAttr::FsCreate),
2850                Ok(Vec::new())
2851            );
2852        })
2853        .await;
2854    }
2855
2856    #[fuchsia::test]
2857    async fn set_get_procattr_clear_context() {
2858        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2859            // Set up the "exec" and "fscreate" Contexts with valid values.
2860            assert_eq!(
2861                set_procattr(current_task, ProcAttr::Exec, VALID_SECURITY_CONTEXT.into()),
2862                Ok(())
2863            );
2864            assert_eq!(
2865                set_procattr(
2866                    current_task,
2867                    ProcAttr::FsCreate,
2868                    DIFFERENT_VALID_SECURITY_CONTEXT.into()
2869                ),
2870                Ok(())
2871            );
2872
2873            // Clear the "exec" context with a write containing a single null octet.
2874            assert_eq!(set_procattr(current_task, ProcAttr::Exec, b"\0"), Ok(()));
2875            assert_eq!(current_task.current_creds().security_state.exec_sid, None);
2876
2877            // Clear the "fscreate" context with a write containing a single newline.
2878            assert_eq!(set_procattr(current_task, ProcAttr::FsCreate, b"\x0a"), Ok(()));
2879            assert_eq!(current_task.current_creds().security_state.fscreate_sid, None);
2880        })
2881        .await;
2882    }
2883
2884    #[fuchsia::test]
2885    async fn set_get_procattr_setcurrent() {
2886        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, _security_server| {
2887            // Stash the initial "previous" context.
2888            let initial_previous =
2889                get_procattr(current_task, current_task, ProcAttr::Previous).unwrap();
2890
2891            assert_eq!(
2892                // Dynamically transition to a valid new context.
2893                set_procattr(current_task, ProcAttr::Current, VALID_SECURITY_CONTEXT.into()),
2894                Ok(())
2895            );
2896
2897            assert_eq!(
2898                // "current" should report the new context.
2899                get_procattr(current_task, current_task, ProcAttr::Current),
2900                Ok(VALID_SECURITY_CONTEXT_WITH_NUL.into())
2901            );
2902
2903            assert_eq!(
2904                // "prev" should continue to report the original context.
2905                get_procattr(current_task, current_task, ProcAttr::Previous),
2906                Ok(initial_previous.clone())
2907            );
2908
2909            assert_eq!(
2910                // Dynamically transition to a different valid context.
2911                set_procattr(
2912                    current_task,
2913                    ProcAttr::Current,
2914                    DIFFERENT_VALID_SECURITY_CONTEXT.into()
2915                ),
2916                Ok(())
2917            );
2918
2919            assert_eq!(
2920                // "current" should report the different new context.
2921                get_procattr(current_task, current_task, ProcAttr::Current),
2922                Ok(DIFFERENT_VALID_SECURITY_CONTEXT_WITH_NUL.into())
2923            );
2924
2925            assert_eq!(
2926                // "prev" should continue to report the original context.
2927                get_procattr(current_task, current_task, ProcAttr::Previous),
2928                Ok(initial_previous.clone())
2929            );
2930        })
2931        .await;
2932    }
2933
2934    #[fuchsia::test]
2935    async fn set_get_procattr_selinux_permissive() {
2936        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
2937            security_server.set_enforcing(false);
2938            assert_eq!(
2939                get_procattr(current_task, &current_task.task, ProcAttr::Exec),
2940                Ok(Vec::new())
2941            );
2942
2943            assert_eq!(
2944                // Test policy allows "kernel_t" tasks to set the "exec" context.
2945                set_procattr(current_task, ProcAttr::Exec, VALID_SECURITY_CONTEXT.into()),
2946                Ok(())
2947            );
2948
2949            assert_eq!(
2950                // Test policy does not allow "kernel_t" tasks to set the "fscreate" context, but
2951                // in permissive mode the setting will be allowed.
2952                set_procattr(
2953                    current_task,
2954                    ProcAttr::FsCreate,
2955                    DIFFERENT_VALID_SECURITY_CONTEXT.into()
2956                ),
2957                Ok(())
2958            );
2959
2960            assert_eq!(
2961                // Setting an invalid context should fail, even in permissive mode.
2962                set_procattr(current_task, ProcAttr::Exec, INVALID_SECURITY_CONTEXT.into()),
2963                error!(EINVAL)
2964            );
2965
2966            assert_eq!(
2967                get_procattr(current_task, &current_task.task, ProcAttr::Exec),
2968                Ok(VALID_SECURITY_CONTEXT_WITH_NUL.into())
2969            );
2970
2971            assert!(get_procattr(current_task, &current_task.task, ProcAttr::Current).is_ok());
2972        })
2973        .await;
2974    }
2975
2976    #[fuchsia::test]
2977    async fn set_get_procattr_selinux_disabled() {
2978        spawn_kernel_and_run(async |current_task| {
2979            assert_eq!(
2980                set_procattr(&current_task, ProcAttr::Exec, VALID_SECURITY_CONTEXT.into()),
2981                error!(EINVAL)
2982            );
2983
2984            assert_eq!(
2985                // Test policy allows "kernel_t" tasks to set the "exec" context.
2986                set_procattr(&current_task, ProcAttr::Exec, VALID_SECURITY_CONTEXT.into()),
2987                error!(EINVAL)
2988            );
2989
2990            assert_eq!(
2991                // Test policy does not allow "kernel_t" tasks to set the "fscreate" context.
2992                set_procattr(&current_task, ProcAttr::FsCreate, VALID_SECURITY_CONTEXT.into()),
2993                error!(EINVAL)
2994            );
2995
2996            assert_eq!(
2997                // Cannot set an invalid context.
2998                set_procattr(&current_task, ProcAttr::Exec, INVALID_SECURITY_CONTEXT.into()),
2999                error!(EINVAL)
3000            );
3001
3002            assert_eq!(
3003                get_procattr(&current_task, &current_task.task, ProcAttr::Current),
3004                error!(EINVAL)
3005            );
3006        })
3007        .await;
3008    }
3009
3010    #[fuchsia::test]
3011    async fn create_file_with_fscreate_sid() {
3012        spawn_kernel_with_selinux_hooks_test_policy_and_run(|current_task, security_server| {
3013            let sid =
3014                security_server.security_context_to_sid(VALID_SECURITY_CONTEXT.into()).unwrap();
3015            let source_node = &testing::create_test_file(current_task).entry.node;
3016
3017            fs_node_setsecurity(
3018                &current_task,
3019                &source_node,
3020                XATTR_NAME_SELINUX.to_bytes().into(),
3021                VALID_SECURITY_CONTEXT.into(),
3022                XattrOp::Set,
3023            )
3024            .expect("set_xattr(security.selinux) failed");
3025
3026            let mut creds = Credentials::clone(&current_task.current_creds());
3027            security::fs_node_copy_up(current_task, source_node, &source_node.fs(), &mut creds);
3028            let dir_entry = current_task
3029                .override_creds(creds.into(), || {
3030                    current_task
3031                        .fs()
3032                        .root()
3033                        .create_node(
3034                            &current_task,
3035                            "test_file2".into(),
3036                            FileMode::IFREG,
3037                            DeviceId::NONE,
3038                        )
3039                        .unwrap()
3040                })
3041                .entry;
3042
3043            assert_eq!(get_cached_sid(&dir_entry.node), Some(sid));
3044        })
3045        .await;
3046    }
3047}