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