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