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