1pub mod local_cache;
6pub mod permission_check;
7pub mod policy;
8pub mod security_server;
9
10mod new_policy;
11
12pub use access_vector_cache::{AccessQueryArgs, DEFAULT_SHARED_SIZE, QueryCacheCapacity};
13pub use concurrent_access_cache::{AccessCacheStorage, ConcurrentAccessCache};
14pub use security_server::{PolicySeqNo, SecurityServer};
15
16mod access_vector_cache;
17mod cache_stats;
18mod concurrent_access_cache;
19mod concurrent_cache;
20mod exceptions_config;
21mod kernel_permissions;
22mod sid_table;
23mod sync;
24
25pub use kernel_permissions::*;
27
28pub use policy::ClassId;
30
31pub use starnix_uapi::selinux::{InitialSid, ReferenceInitialSid, SecurityId, TaskAttrs};
32
33use policy::arrays::FsUseType;
34use strum::VariantArray as _;
35use strum_macros::VariantArray;
36
37#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
39pub enum ObjectClass {
40 Kernel(KernelClass),
42 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#[derive(Clone, Copy, Debug, PartialEq)]
62pub struct NullessByteStr<'a>(&'a [u8]);
63
64impl<'a> NullessByteStr<'a> {
65 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 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 pub mount_sids: FileSystemMountSids,
98}
99
100#[derive(Clone, Debug, PartialEq)]
101pub enum FileSystemLabelingScheme {
102 Mountpoint { sid: SecurityId },
104 FsUse { fs_use_type: FsUseType, default_sid: SecurityId },
108 GenFsCon { supports_seclabel: bool },
111}
112
113#[derive(Clone, Debug, Default, PartialEq)]
117pub struct FileSystemMountOptions {
118 pub context: Option<Vec<u8>>,
122 pub def_context: Option<Vec<u8>>,
125 pub fs_context: Option<Vec<u8>>,
128 pub root_context: Option<Vec<u8>>,
131}
132
133pub struct SeLinuxStatus {
135 pub is_enforcing: bool,
137 pub change_count: u32,
139 pub deny_unknown: bool,
141}
142
143pub trait SeLinuxStatusPublisher: Send + Sync {
145 fn set_status(&mut self, policy_status: SeLinuxStatus);
147}
148
149#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, VariantArray)]
151pub enum PolicyCap {
152 NetworkPeerControls = 0,
153 OpenPerms = 1,
154 ExtendedSocketClass = 2,
155 AlwaysCheckNetwork = 3,
156 CgroupSeclabel = 4,
157 NnpNosuidTransition = 5,
158 GenfsSeclabelSymlinks = 6,
159 IoctlSkipCloexec = 7,
160 UserspaceInitialContext = 8,
161 NetlinkXperm = 9,
162 NetifWildcard = 10,
163 GenfsSeclabelWildcard = 11,
164 FunctionfsSeclabel = 12,
165 MemfdClass = 13,
166}
167
168impl PolicyCap {
169 pub fn name(&self) -> &str {
170 match self {
171 Self::NetworkPeerControls => "network_peer_controls",
172 Self::OpenPerms => "open_perms",
173 Self::ExtendedSocketClass => "extended_socket_class",
174 Self::AlwaysCheckNetwork => "always_check_network",
175 Self::CgroupSeclabel => "cgroup_seclabel",
176 Self::NnpNosuidTransition => "nnp_nosuid_transition",
177 Self::GenfsSeclabelSymlinks => "genfs_seclabel_symlinks",
178 Self::IoctlSkipCloexec => "ioctl_skip_cloexec",
179 Self::UserspaceInitialContext => "userspace_initial_context",
180 Self::NetlinkXperm => "netlink_xperm",
181 Self::NetifWildcard => "netif_wildcard",
182 Self::GenfsSeclabelWildcard => "genfs_seclabel_wildcard",
183 Self::FunctionfsSeclabel => "functionfs_seclabel",
184 Self::MemfdClass => "memfd_class",
185 }
186 }
187
188 pub fn by_name(name: &str) -> Option<Self> {
189 Self::VARIANTS.iter().find(|x| x.name() == name).copied()
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 #[test]
198 fn object_class_permissions() {
199 let test_class_id = ClassId::for_test(20);
200 assert_eq!(ObjectClass::ClassId(test_class_id), test_class_id.into());
201 for variant in ProcessPermission::PERMISSIONS {
202 assert_eq!(KernelClass::Process, variant.class());
203 assert_eq!("process", variant.class().name());
204 assert_eq!(ObjectClass::Kernel(KernelClass::Process), variant.class().into());
205 }
206 }
207
208 #[test]
209 fn policy_capabilities() {
210 for capability in PolicyCap::VARIANTS {
211 assert_eq!(Some(*capability), PolicyCap::by_name(capability.name()));
212 }
213 }
214
215 #[test]
216 fn nulless_byte_str_equivalence() {
217 let unterminated: NullessByteStr<'_> = b"u:object_r:test_valid_t:s0".into();
218 let nul_terminated: NullessByteStr<'_> = b"u:object_r:test_valid_t:s0\0".into();
219 let nul_containing: NullessByteStr<'_> =
220 b"u:object_r:test_valid_t:s0\0IGNORE THIS\0!\0".into();
221
222 for context in [nul_terminated, nul_containing] {
223 assert_eq!(unterminated, context);
224 assert_eq!(unterminated.as_bytes(), context.as_bytes());
225 }
226 }
227}