1pub mod local_cache;
6pub mod permission_check;
7pub mod policy;
8pub mod security_server;
9
10pub use access_vector_cache::{AccessQueryArgs, DEFAULT_SHARED_SIZE, QueryCacheCapacity};
11pub use concurrent_access_cache::{AccessCacheStorage, ConcurrentAccessCache};
12pub use security_server::SecurityServer;
13
14mod access_vector_cache;
15mod cache_stats;
16mod concurrent_access_cache;
17mod concurrent_cache;
18mod exceptions_config;
19mod kernel_permissions;
20mod sid_table;
21mod sync;
22
23pub use kernel_permissions::*;
25
26pub use policy::ClassId;
28
29pub use starnix_uapi::selinux::{InitialSid, ReferenceInitialSid, SecurityId, TaskAttrs};
30
31use policy::arrays::FsUseType;
32use strum::VariantArray as _;
33use strum_macros::VariantArray;
34
35#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
37pub enum ObjectClass {
38 Kernel(KernelClass),
40 ClassId(ClassId),
43}
44
45impl From<ClassId> for ObjectClass {
46 fn from(id: ClassId) -> Self {
47 Self::ClassId(id)
48 }
49}
50
51impl<T: Into<KernelClass>> From<T> for ObjectClass {
52 fn from(class: T) -> Self {
53 Self::Kernel(class.into())
54 }
55}
56
57#[derive(Clone, Copy, Debug, PartialEq)]
60pub struct NullessByteStr<'a>(&'a [u8]);
61
62impl<'a> NullessByteStr<'a> {
63 pub fn as_bytes(&self) -> &[u8] {
65 &self.0
66 }
67}
68
69impl<'a, S: AsRef<[u8]> + ?Sized> From<&'a S> for NullessByteStr<'a> {
70 fn from(s: &'a S) -> Self {
74 let value = s.as_ref();
75 match value.iter().position(|c| *c == 0) {
76 Some(end) => Self(&value[..end]),
77 None => Self(value),
78 }
79 }
80}
81
82#[derive(Clone, Debug, PartialEq)]
83pub struct FileSystemMountSids {
84 pub context: Option<SecurityId>,
85 pub fs_context: Option<SecurityId>,
86 pub def_context: Option<SecurityId>,
87 pub root_context: Option<SecurityId>,
88}
89
90#[derive(Clone, Debug, PartialEq)]
91pub struct FileSystemLabel {
92 pub sid: SecurityId,
93 pub scheme: FileSystemLabelingScheme,
94 pub mount_sids: FileSystemMountSids,
96}
97
98#[derive(Clone, Debug, PartialEq)]
99pub enum FileSystemLabelingScheme {
100 Mountpoint { sid: SecurityId },
102 FsUse { fs_use_type: FsUseType, default_sid: SecurityId },
106 GenFsCon { supports_seclabel: bool },
109}
110
111#[derive(Clone, Debug, Default, PartialEq)]
115pub struct FileSystemMountOptions {
116 pub context: Option<Vec<u8>>,
120 pub def_context: Option<Vec<u8>>,
123 pub fs_context: Option<Vec<u8>>,
126 pub root_context: Option<Vec<u8>>,
129}
130
131pub struct SeLinuxStatus {
133 pub is_enforcing: bool,
135 pub change_count: u32,
137 pub deny_unknown: bool,
139}
140
141pub trait SeLinuxStatusPublisher: Send + Sync {
143 fn set_status(&mut self, policy_status: SeLinuxStatus);
145}
146
147#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, VariantArray)]
149pub enum PolicyCap {
150 NetworkPeerControls = 0,
151 OpenPerms = 1,
152 ExtendedSocketClass = 2,
153 AlwaysCheckNetwork = 3,
154 CgroupSeclabel = 4,
155 NnpNosuidTransition = 5,
156 GenfsSeclabelSymlinks = 6,
157 IoctlSkipCloexec = 7,
158 UserspaceInitialContext = 8,
159 NetlinkXperm = 9,
160 NetifWildcard = 10,
161 GenfsSeclabelWildcard = 11,
162 FunctionfsSeclabel = 12,
163 MemfdClass = 13,
164}
165
166impl PolicyCap {
167 pub fn name(&self) -> &str {
168 match self {
169 Self::NetworkPeerControls => "network_peer_controls",
170 Self::OpenPerms => "open_perms",
171 Self::ExtendedSocketClass => "extended_socket_class",
172 Self::AlwaysCheckNetwork => "always_check_network",
173 Self::CgroupSeclabel => "cgroup_seclabel",
174 Self::NnpNosuidTransition => "nnp_nosuid_transition",
175 Self::GenfsSeclabelSymlinks => "genfs_seclabel_symlinks",
176 Self::IoctlSkipCloexec => "ioctl_skip_cloexec",
177 Self::UserspaceInitialContext => "userspace_initial_context",
178 Self::NetlinkXperm => "netlink_xperm",
179 Self::NetifWildcard => "netif_wildcard",
180 Self::GenfsSeclabelWildcard => "genfs_seclabel_wildcard",
181 Self::FunctionfsSeclabel => "functionfs_seclabel",
182 Self::MemfdClass => "memfd_class",
183 }
184 }
185
186 pub fn by_name(name: &str) -> Option<Self> {
187 Self::VARIANTS.iter().find(|x| x.name() == name).copied()
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194 use std::num::NonZeroU32;
195
196 #[test]
197 fn object_class_permissions() {
198 let test_class_id = ClassId::new(NonZeroU32::new(20).unwrap());
199 assert_eq!(ObjectClass::ClassId(test_class_id), test_class_id.into());
200 for variant in ProcessPermission::PERMISSIONS {
201 assert_eq!(KernelClass::Process, variant.class());
202 assert_eq!("process", variant.class().name());
203 assert_eq!(ObjectClass::Kernel(KernelClass::Process), variant.class().into());
204 }
205 }
206
207 #[test]
208 fn policy_capabilities() {
209 for capability in PolicyCap::VARIANTS {
210 assert_eq!(Some(*capability), PolicyCap::by_name(capability.name()));
211 }
212 }
213
214 #[test]
215 fn nulless_byte_str_equivalence() {
216 let unterminated: NullessByteStr<'_> = b"u:object_r:test_valid_t:s0".into();
217 let nul_terminated: NullessByteStr<'_> = b"u:object_r:test_valid_t:s0\0".into();
218 let nul_containing: NullessByteStr<'_> =
219 b"u:object_r:test_valid_t:s0\0IGNORE THIS\0!\0".into();
220
221 for context in [nul_terminated, nul_containing] {
222 assert_eq!(unterminated, context);
223 assert_eq!(unterminated.as_bytes(), context.as_bytes());
224 }
225 }
226}