Skip to main content

selinux/
lib.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#![warn(variant_size_differences)]
6
7pub mod local_cache;
8pub mod permission_check;
9pub mod policy;
10pub mod security_server;
11
12mod new_policy;
13
14pub use access_vector_cache::{AccessQueryArgs, DEFAULT_SHARED_SIZE, QueryCacheCapacity};
15pub use concurrent_access_cache::{AccessCacheStorage, ConcurrentAccessCache};
16pub use security_server::{PolicySeqNo, SecurityServer};
17
18mod access_vector_cache;
19mod cache_stats;
20mod concurrent_access_cache;
21mod concurrent_cache;
22mod exceptions_config;
23mod kernel_permissions;
24mod sid_table;
25mod sync;
26
27/// Allow callers to use the kernel class & permission definitions.
28pub use kernel_permissions::*;
29
30/// Numeric class Ids are provided to the userspace AVC surfaces (e.g. "create", "access", etc).
31pub use policy::ClassId;
32
33pub use starnix_uapi::selinux::{InitialSid, ReferenceInitialSid, SecurityId, TaskAttrs};
34
35use policy::arrays::FsUseType;
36
37/// Identifies a specific class by its policy-defined Id, or as a kernel object class enum Id.
38#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
39pub enum ObjectClass {
40    /// Refers to a well-known SELinux kernel object class (e.g. "process", "file", "capability").
41    Kernel(KernelClass),
42    /// Refers to a policy-defined class by its policy-defined numeric Id. This is most commonly
43    /// used when handling queries from userspace, which refer to classes by-Id.
44    ClassId(ClassId),
45}
46
47impl From<ClassId> for ObjectClass {
48    fn from(id: ClassId) -> Self {
49        Self::ClassId(id)
50    }
51}
52
53impl<T: Into<KernelClass>> From<T> for ObjectClass {
54    fn from(class: T) -> Self {
55        Self::Kernel(class.into())
56    }
57}
58
59/// A borrowed byte slice that contains no `NUL` characters by truncating the input slice at the
60/// first `NUL` (if any) upon construction.
61#[derive(Clone, Copy, Debug, PartialEq)]
62pub struct NullessByteStr<'a>(&'a [u8]);
63
64impl<'a> NullessByteStr<'a> {
65    /// Returns a non-null-terminated representation of the security context string.
66    pub fn as_bytes(&self) -> &[u8] {
67        &self.0
68    }
69}
70
71impl<'a, S: AsRef<[u8]> + ?Sized> From<&'a S> for NullessByteStr<'a> {
72    /// Any `AsRef<[u8]>` can be processed into a [`NullessByteStr`]. The [`NullessByteStr`] will
73    /// retain everything up to (but not including) a null character, or else the complete byte
74    /// string.
75    fn from(s: &'a S) -> Self {
76        let value = s.as_ref();
77        match value.iter().position(|c| *c == 0) {
78            Some(end) => Self(&value[..end]),
79            None => Self(value),
80        }
81    }
82}
83
84#[derive(Clone, Debug, PartialEq)]
85pub struct FileSystemMountSids {
86    pub context: Option<SecurityId>,
87    pub fs_context: Option<SecurityId>,
88    pub def_context: Option<SecurityId>,
89    pub root_context: Option<SecurityId>,
90}
91
92#[derive(Clone, Debug, PartialEq)]
93pub struct FileSystemLabel {
94    pub sid: SecurityId,
95    pub scheme: FileSystemLabelingScheme,
96    // Sids obtained by parsing the mount options of the FileSystem.
97    pub mount_sids: FileSystemMountSids,
98}
99
100#[derive(Clone, Debug, PartialEq)]
101pub enum FileSystemLabelingScheme {
102    /// This filesystem was mounted with "context=".
103    Mountpoint { sid: SecurityId },
104    /// This filesystem has an "fs_use_xattr", "fs_use_task", or "fs_use_trans" entry in the
105    /// policy. If the `fs_use_type` is "fs_use_xattr" then the `default_sid` specifies the SID
106    /// with which to label `FsNode`s of files that do not have the "security.selinux" xattr.
107    FsUse { fs_use_type: FsUseType, default_sid: SecurityId },
108    /// This filesystem has one or more "genfscon" statements associated with it in the policy.
109    /// If `supports_seclabel` is true then nodes in the filesystem may be dynamically relabeled.
110    GenFsCon { supports_seclabel: bool },
111}
112
113/// SELinux security context-related filesystem mount options. These options are documented in the
114/// `context=context, fscontext=context, defcontext=context, and rootcontext=context` section of
115/// the `mount(8)` manpage.
116#[derive(Clone, Debug, Default, PartialEq)]
117pub struct FileSystemMountOptions {
118    /// Specifies the effective security context to use for all nodes in the filesystem, and the
119    /// filesystem itself. If the filesystem already contains security attributes then these are
120    /// ignored. May not be combined with any of the other options.
121    pub context: Option<Vec<u8>>,
122    /// Specifies an effective security context to use for un-labeled nodes in the filesystem,
123    /// rather than falling-back to the policy-defined "file" context.
124    pub def_context: Option<Vec<u8>>,
125    /// The value of the `fscontext=[security-context]` mount option. This option is used to
126    /// label the filesystem (superblock) itself.
127    pub fs_context: Option<Vec<u8>>,
128    /// The value of the `rootcontext=[security-context]` mount option. This option is used to
129    /// (re)label the inode located at the filesystem mountpoint.
130    pub root_context: Option<Vec<u8>>,
131}
132
133/// Status information parameter for the [`SeLinuxStatusPublisher`] interface.
134pub struct SeLinuxStatus {
135    /// SELinux-wide enforcing vs. permissive mode  bit.
136    pub is_enforcing: bool,
137    /// Number of times the policy has been changed since SELinux started.
138    pub change_count: u32,
139    /// Bit indicating whether operations unknown SELinux abstractions will be denied.
140    pub deny_unknown: bool,
141}
142
143/// Interface for security server to interact with selinuxfs status file.
144pub trait SeLinuxStatusPublisher: Send + Sync {
145    /// Sets the value part of the associated selinuxfs status file.
146    fn set_status(&mut self, policy_status: SeLinuxStatus);
147}
148
149pub use new_policy::PolicyCap;
150
151#[cfg(test)]
152mod tests {
153    use super::*;
154
155    #[test]
156    fn object_class_permissions() {
157        let test_class_id = ClassId::for_test(20);
158        assert_eq!(ObjectClass::ClassId(test_class_id), test_class_id.into());
159        for variant in ProcessPermission::PERMISSIONS {
160            assert_eq!(KernelClass::Process, variant.class());
161            assert_eq!("process", variant.class().name());
162            assert_eq!(ObjectClass::Kernel(KernelClass::Process), variant.class().into());
163        }
164    }
165
166    #[test]
167    fn nulless_byte_str_equivalence() {
168        let unterminated: NullessByteStr<'_> = b"u:object_r:test_valid_t:s0".into();
169        let nul_terminated: NullessByteStr<'_> = b"u:object_r:test_valid_t:s0\0".into();
170        let nul_containing: NullessByteStr<'_> =
171            b"u:object_r:test_valid_t:s0\0IGNORE THIS\0!\0".into();
172
173        for context in [nul_terminated, nul_containing] {
174            assert_eq!(unterminated, context);
175            assert_eq!(unterminated.as_bytes(), context.as_bytes());
176        }
177    }
178}