1mod access_vector;
6mod bitmap;
7mod booleans;
8mod classes;
9mod common_symbols;
10mod compute;
11mod constraints;
12mod error;
13mod filename_transitions;
14mod id_type;
15mod indexed;
16mod initial_sids;
17mod metadata;
18mod mls;
19mod object_contexts;
20mod parser;
21mod permissions;
22mod policy_cap;
23mod roles;
24mod rules;
25mod security_context;
26#[cfg(test)]
27mod tests;
28mod traits;
29mod types;
30mod u24_index;
31mod users;
32
33use std::num::NonZeroU16;
34
35use selinux_policy_derive::{Parse, Serialize, Validate};
36
37use crate::InitialSid;
38pub use access_vector::AccessVector;
39use bitmap::IdSpan;
40use booleans::{ConditionalBoolean, ConditionalBooleanId};
41pub(crate) use classes::Class;
42pub use classes::ClassId;
43use classes::{ClassDefault, ClassDefaultRange};
44use common_symbols::CommonSymbol;
45pub use compute::XpermsKind;
46pub(crate) use compute::{FsUseLabelAndType, XpermsAccessDecision};
47use error::{ParseError, SerializeError, ValidateError};
48use filename_transitions::FilenameTransitions;
49use indexed::IdAndNameIndexed;
50use initial_sids::InitialSids;
51pub(crate) use metadata::HandleUnknown;
52pub use metadata::POLICYDB_VERSION_MAX;
53use metadata::{Config, Counts, Magic, PolicyVersion, Signature};
54use mls::{
55 Category, CategoryId, CategorySet, CategorySetBuilder, RangeTransition, Sensitivity,
56 SensitivityId,
57};
58pub use object_contexts::FsUseType;
59use object_contexts::{GenfsCon, GenfsConPath, ObjectContexts};
60pub use parser::PolicyData;
61use parser::{Array, PolicyCursor, PolicyWriter, SymbolArray};
62pub use permissions::PermissionId;
63pub use policy_cap::PolicyCap;
64use policy_cap::PolicyCapSet;
65pub(crate) use roles::RoleId;
66use roles::{Role, RoleAllow, RoleSet, RoleTransition};
67pub use rules::AccessDecision;
68use rules::{ConditionalNode, IndexedAccessVectorRules};
69pub(crate) use rules::{SELINUX_AVD_FLAGS_PERMISSIVE, XpermsBitmap};
70use security_context::{MlsLevel, MlsRange};
71pub(crate) use security_context::{SecurityContext, SecurityContextError};
72pub use traits::PolicyId;
73pub(crate) use traits::{HasName, HasPolicyId};
74use traits::{Serialize, Validate};
75pub(crate) use types::TypeId;
76use types::{PermissiveTypeSet, TypeAttributeMaps, TypeSet, Types};
77use u24_index::U24Index;
78use users::{User, UserId};
79
80const MAXIMUM_POLICY_SIZE: usize = (1 << 24) - 1;
85
86const OBJECT_R_ROLE_NAME: &[u8] = b"object_r";
88const OBJECT_R_ROLE_ID: RoleId = RoleId::new(NonZeroU16::MIN);
89
90#[derive(Debug, Parse, Serialize, Validate)]
92pub(crate) struct Policy {
93 magic: Magic,
94 signature: Signature,
95 version: PolicyVersion,
96 config: Config,
97 counts: Counts,
98 policy_capabilities: PolicyCapSet,
99 permissive_map: PermissiveTypeSet,
100 common_symbols: IdAndNameIndexed<SymbolArray<CommonSymbol>>,
101 classes: IdAndNameIndexed<SymbolArray<Class>>,
102 roles: IdAndNameIndexed<SymbolArray<Role>>,
103 types: Types,
104 users: IdAndNameIndexed<SymbolArray<User>>,
105 conditional_booleans: IdAndNameIndexed<SymbolArray<ConditionalBoolean>>,
106 sensitivities: IdAndNameIndexed<SymbolArray<Sensitivity>>,
107 categories: IdAndNameIndexed<SymbolArray<Category>>,
108 access_vector_rules: IndexedAccessVectorRules,
109 conditional_nodes: Array<ConditionalNode>,
110 role_transitions: Array<RoleTransition>,
111 role_allowlist: Array<RoleAllow>,
112 filename_transitions: FilenameTransitions,
113 initial_sids: InitialSids,
114 object_contexts: ObjectContexts,
115 generic_fs_contexts: Array<GenfsCon>,
116 range_transitions: Array<RangeTransition>,
117 type_attribute_maps: TypeAttributeMaps,
118}
119
120impl Policy {
121 pub fn parse(data: &[u8]) -> Result<Self, ParseError> {
123 let policy_size = data.len();
124 if policy_size > MAXIMUM_POLICY_SIZE {
125 return Err(ParseError::UnsupportedlyLarge {
126 observed: policy_size,
127 limit: MAXIMUM_POLICY_SIZE,
128 });
129 }
130 let mut cursor = PolicyCursor::new(data);
131 let policy = cursor.parse()?;
132 if cursor.offset() < data.len() {
133 return Err(ParseError::TrailingBytes { num_bytes: data.len() - cursor.offset() });
134 }
135 Ok(policy)
136 }
137
138 pub fn validate(&self) -> Result<(), ValidateError> {
140 Validate::validate(self, self)?;
141
142 let need_init_sid = self.has_policycap(PolicyCap::UserspaceInitialContext);
144 for initial_sid in InitialSid::all_variants() {
145 if *initial_sid == InitialSid::Init && !need_init_sid {
146 continue;
147 }
148 self.initial_sids()
149 .get_by_id(*initial_sid as u32)
150 .ok_or(ValidateError::MissingInitialSid { initial_sid: *initial_sid })?;
151 }
152
153 if self.roles().get_by_id(OBJECT_R_ROLE_ID).map(|role| role.name())
155 != Some(OBJECT_R_ROLE_NAME)
156 {
157 return Err(ValidateError::MissingObjectRRole);
158 }
159
160 Ok(())
164 }
165
166 #[cfg(test)]
168 pub(crate) fn parse_and_validate(data: &[u8]) -> Self {
169 let policy = Self::parse(data).expect("parse policy");
170 policy.validate().expect("validate policy");
171 policy
172 }
173
174 pub fn serialize(&self, writer: &mut Vec<u8>) -> Result<(), SerializeError> {
176 let mut policy_writer = PolicyWriter::new(self.version, writer);
177 Serialize::serialize(self, &mut policy_writer)
178 }
179
180 #[cfg(test)]
182 fn version(&self) -> PolicyVersion {
183 self.version
184 }
185
186 pub fn handle_unknown(&self) -> HandleUnknown {
188 self.config.handle_unknown()
189 }
190
191 fn policy_capabilities(&self) -> &PolicyCapSet {
193 &self.policy_capabilities
194 }
195
196 fn permissive_map(&self) -> &PermissiveTypeSet {
198 &self.permissive_map
199 }
200
201 fn common_symbols(&self) -> &IdAndNameIndexed<SymbolArray<CommonSymbol>> {
203 &self.common_symbols
204 }
205
206 pub fn classes(&self) -> &IdAndNameIndexed<SymbolArray<Class>> {
208 &self.classes
209 }
210
211 fn roles(&self) -> &IdAndNameIndexed<SymbolArray<Role>> {
213 &self.roles
214 }
215
216 pub fn types(&self) -> &Types {
218 &self.types
219 }
220
221 fn users(&self) -> &IdAndNameIndexed<SymbolArray<User>> {
223 &self.users
224 }
225
226 pub fn conditional_booleans(&self) -> &IdAndNameIndexed<SymbolArray<ConditionalBoolean>> {
228 &self.conditional_booleans
229 }
230
231 fn sensitivities(&self) -> &IdAndNameIndexed<SymbolArray<Sensitivity>> {
233 &self.sensitivities
234 }
235
236 fn categories(&self) -> &IdAndNameIndexed<SymbolArray<Category>> {
238 &self.categories
239 }
240
241 fn access_vector_rules(&self) -> &IndexedAccessVectorRules {
243 &self.access_vector_rules
244 }
245
246 fn role_transitions(&self) -> &[RoleTransition] {
248 self.role_transitions.as_ref()
249 }
250
251 fn role_allowlist(&self) -> &[RoleAllow] {
253 self.role_allowlist.as_ref()
254 }
255
256 fn filename_transitions(&self) -> &FilenameTransitions {
258 &self.filename_transitions
259 }
260
261 fn initial_sids(&self) -> &InitialSids {
263 &self.initial_sids
264 }
265
266 pub fn object_contexts(&self) -> &ObjectContexts {
268 &self.object_contexts
269 }
270
271 fn generic_fs_contexts(&self) -> &[GenfsCon] {
273 &self.generic_fs_contexts
274 }
275
276 fn range_transitions(&self) -> &[RangeTransition] {
278 &self.range_transitions
279 }
280
281 fn type_attribute_maps(&self) -> &TypeAttributeMaps {
283 &self.type_attribute_maps
284 }
285}
286
287#[cfg(test)]
288mod parse_tests {
289 use super::*;
290 use crate::policy::traits::{Parse, Serialize};
291
292 #[derive(Copy, Clone, Debug, Eq, PartialEq, Parse, Serialize, Validate)]
293 #[policy(wire_type = u32)]
294 enum TestEnum {
295 ValueOne = 1,
296 ValueTwo = 2,
297 }
298
299 #[test]
300 fn test_enum_derive() {
301 let mut cursor = PolicyCursor::new(&[1, 0, 0, 0]);
302 let parsed = TestEnum::parse(&mut cursor).unwrap();
303 assert_eq!(parsed, TestEnum::ValueOne);
304
305 let mut cursor = PolicyCursor::new(&[2, 0, 0, 0]);
306 let parsed = TestEnum::parse(&mut cursor).unwrap();
307 assert_eq!(parsed, TestEnum::ValueTwo);
308
309 let mut cursor = PolicyCursor::new(&[3, 0, 0, 0]);
310 let err = TestEnum::parse(&mut cursor).unwrap_err();
311 assert!(matches!(err, ParseError::InvalidEnumValue { enum_name: "TestEnum", value: 3 }));
312
313 let mut writer = Vec::new();
314 let mut policy_writer = PolicyWriter::new(PolicyVersion::V33, &mut writer);
315 TestEnum::ValueOne.serialize(&mut policy_writer).unwrap();
316 assert_eq!(writer, vec![1, 0, 0, 0]);
317
318 let mut writer = Vec::new();
319 let mut policy_writer = PolicyWriter::new(PolicyVersion::V33, &mut writer);
320 TestEnum::ValueTwo.serialize(&mut policy_writer).unwrap();
321 assert_eq!(writer, vec![2, 0, 0, 0]);
322
323 let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
324 let policy = Policy::parse(policy_bytes).unwrap();
325 TestEnum::ValueOne.validate(&policy).unwrap();
326 }
327
328 const TEST_POLICIES: &[(&str, &[u8])] = &[
329 ("selinux_testsuite", include_bytes!("../../testdata/policies/selinux_testsuite")),
330 ("emulator", include_bytes!("../../testdata/policies/emulator")),
331 (
332 "conditional_policy",
333 include_bytes!("../../testdata/composite_policies/compiled/conditional_policy"),
334 ),
335 (
336 "minimal_policy",
337 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy"),
338 ),
339 (
340 "allow_fork_policy",
341 include_bytes!("../../testdata/composite_policies/compiled/allow_fork_policy"),
342 ),
343 (
344 "class_defaults_policy",
345 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy"),
346 ),
347 (
348 "genfscon_policy",
349 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy"),
350 ),
351 (
352 "handle_unknown_policy-allow",
353 include_bytes!(
354 "../../testdata/composite_policies/compiled/handle_unknown_policy-allow"
355 ),
356 ),
357 (
358 "handle_unknown_policy-deny",
359 include_bytes!("../../testdata/composite_policies/compiled/handle_unknown_policy-deny"),
360 ),
361 (
362 "handle_unknown_policy-reject",
363 include_bytes!(
364 "../../testdata/composite_policies/compiled/handle_unknown_policy-reject"
365 ),
366 ),
367 (
368 "range_transition_policy",
369 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy"),
370 ),
371 (
372 "role_transition_policy",
373 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy"),
374 ),
375 (
376 "type_transition_policy",
377 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy"),
378 ),
379 ];
380
381 #[test]
382 fn test_all_compiled_policies_roundtrip() {
383 for (name, policy_bytes) in TEST_POLICIES {
384 let policy = Policy::parse(policy_bytes)
385 .unwrap_or_else(|e| panic!("Failed to parse {name}: {e:?}"));
386 policy.validate().unwrap_or_else(|e| panic!("Failed to validate {name}: {e:?}"));
387
388 if policy.version() >= PolicyVersion::V33 {
389 let mut serialized = Vec::new();
390 policy
391 .serialize(&mut serialized)
392 .unwrap_or_else(|e| panic!("Failed to serialize {name}: {e:?}"));
393 assert_bytes_eq(&serialized, policy_bytes);
394 }
395 }
396 }
397
398 #[test]
399 fn test_initial_sids_policy_elements() {
400 let policy_bytes =
401 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy");
402 let policy = Policy::parse(policy_bytes).expect("parse minimal policy");
403 policy.validate().expect("validate minimal policy");
404
405 assert!(!policy.initial_sids().is_empty());
406 assert!(policy.initial_sids().len() >= crate::InitialSid::all_variants().len() - 1);
407
408 let kernel_context =
409 policy.initial_sids().get_by_id(crate::InitialSid::Kernel as u32).unwrap();
410 assert!(policy.users().get_by_id(kernel_context.user()).is_some());
411 assert!(policy.roles().get_by_id(kernel_context.role()).is_some());
412
413 let unlabeled_context =
414 policy.initial_sids().get_by_id(crate::InitialSid::Unlabeled as u32).unwrap();
415 assert!(policy.users().get_by_id(unlabeled_context.user()).is_some());
416 assert!(policy.roles().get_by_id(unlabeled_context.role()).is_some());
417 }
418
419 #[test]
420 fn test_object_r_role_id_validation() {
421 let policy_bytes =
422 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy");
423 let mut policy = Policy::parse_and_validate(policy_bytes);
424
425 let roles = policy.roles.as_mut_slice();
428 let object_r_index =
429 roles.iter().position(|role| role.name() == OBJECT_R_ROLE_NAME).unwrap();
430 let other_index = roles.iter().position(|role| role.name() != OBJECT_R_ROLE_NAME).unwrap();
431 let object_r_id = roles[object_r_index].id();
432 let other_id = roles[other_index].id();
433 roles[object_r_index].set_id(other_id);
434 roles[other_index].set_id(object_r_id);
435
436 let mut serialized = Vec::new();
437 policy.serialize(&mut serialized).expect("serialize modified policy");
438
439 let reparsed = Policy::parse(&serialized).expect("re-parse modified policy");
440 assert_eq!(reparsed.validate(), Err(ValidateError::MissingObjectRRole));
441 }
442}
443
444#[cfg(test)]
445fn assert_bytes_eq(left: &[u8], right: &[u8]) {
446 if left != right {
447 let min_len = std::cmp::min(left.len(), right.len());
448 for i in 0..min_len {
449 if left[i] != right[i] {
450 let start = i.saturating_sub(8);
451 let end = std::cmp::min(i + 16, min_len);
452 panic!(
453 "Byte mismatch at offset {i} (0x{i:x}): actual=0x{:02x} vs expected=0x{:02x}.\nActual [{start}..{end}]: {:02x?}\nExpected [{start}..{end}]: {:02x?}",
454 left[i],
455 right[i],
456 &left[start..end],
457 &right[start..end]
458 );
459 }
460 }
461 panic!("Length mismatch: actual={}, expected={}", left.len(), right.len());
462 }
463}