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 pub fn serialize(&self, writer: &mut Vec<u8>) -> Result<(), SerializeError> {
168 let mut policy_writer = PolicyWriter::new(self.version, writer);
169 Serialize::serialize(self, &mut policy_writer)
170 }
171
172 #[cfg(test)]
174 fn version(&self) -> PolicyVersion {
175 self.version
176 }
177
178 pub fn handle_unknown(&self) -> HandleUnknown {
180 self.config.handle_unknown()
181 }
182
183 fn policy_capabilities(&self) -> &PolicyCapSet {
185 &self.policy_capabilities
186 }
187
188 fn permissive_map(&self) -> &PermissiveTypeSet {
190 &self.permissive_map
191 }
192
193 fn common_symbols(&self) -> &IdAndNameIndexed<SymbolArray<CommonSymbol>> {
195 &self.common_symbols
196 }
197
198 pub fn classes(&self) -> &IdAndNameIndexed<SymbolArray<Class>> {
200 &self.classes
201 }
202
203 fn roles(&self) -> &IdAndNameIndexed<SymbolArray<Role>> {
205 &self.roles
206 }
207
208 pub fn types(&self) -> &Types {
210 &self.types
211 }
212
213 fn users(&self) -> &IdAndNameIndexed<SymbolArray<User>> {
215 &self.users
216 }
217
218 pub fn conditional_booleans(&self) -> &IdAndNameIndexed<SymbolArray<ConditionalBoolean>> {
220 &self.conditional_booleans
221 }
222
223 fn sensitivities(&self) -> &IdAndNameIndexed<SymbolArray<Sensitivity>> {
225 &self.sensitivities
226 }
227
228 fn categories(&self) -> &IdAndNameIndexed<SymbolArray<Category>> {
230 &self.categories
231 }
232
233 fn access_vector_rules(&self) -> &IndexedAccessVectorRules {
235 &self.access_vector_rules
236 }
237
238 #[cfg(test)]
240 fn conditional_nodes(&self) -> &[ConditionalNode] {
241 self.conditional_nodes.as_ref()
242 }
243
244 fn role_transitions(&self) -> &[RoleTransition] {
246 self.role_transitions.as_ref()
247 }
248
249 fn role_allowlist(&self) -> &[RoleAllow] {
251 self.role_allowlist.as_ref()
252 }
253
254 fn filename_transitions(&self) -> &FilenameTransitions {
256 &self.filename_transitions
257 }
258
259 fn initial_sids(&self) -> &InitialSids {
261 &self.initial_sids
262 }
263
264 pub fn object_contexts(&self) -> &ObjectContexts {
266 &self.object_contexts
267 }
268
269 fn generic_fs_contexts(&self) -> &[GenfsCon] {
271 &self.generic_fs_contexts
272 }
273
274 fn range_transitions(&self) -> &[RangeTransition] {
276 &self.range_transitions
277 }
278
279 fn type_attribute_maps(&self) -> &TypeAttributeMaps {
281 &self.type_attribute_maps
282 }
283}
284
285#[cfg(test)]
286mod parse_tests {
287 use super::*;
288 use crate::policy::traits::{Parse, Serialize};
289
290 #[derive(Copy, Clone, Debug, Eq, PartialEq, Parse, Serialize, Validate)]
291 #[policy(wire_type = u32)]
292 enum TestEnum {
293 ValueOne = 1,
294 ValueTwo = 2,
295 }
296
297 #[test]
298 fn test_enum_derive() {
299 let mut cursor = PolicyCursor::new(&[1, 0, 0, 0]);
300 let parsed = TestEnum::parse(&mut cursor).unwrap();
301 assert_eq!(parsed, TestEnum::ValueOne);
302
303 let mut cursor = PolicyCursor::new(&[2, 0, 0, 0]);
304 let parsed = TestEnum::parse(&mut cursor).unwrap();
305 assert_eq!(parsed, TestEnum::ValueTwo);
306
307 let mut cursor = PolicyCursor::new(&[3, 0, 0, 0]);
308 let err = TestEnum::parse(&mut cursor).unwrap_err();
309 assert!(matches!(err, ParseError::InvalidEnumValue { enum_name: "TestEnum", value: 3 }));
310
311 let mut writer = Vec::new();
312 let mut policy_writer = PolicyWriter::new(PolicyVersion::V33, &mut writer);
313 TestEnum::ValueOne.serialize(&mut policy_writer).unwrap();
314 assert_eq!(writer, vec![1, 0, 0, 0]);
315
316 let mut writer = Vec::new();
317 let mut policy_writer = PolicyWriter::new(PolicyVersion::V33, &mut writer);
318 TestEnum::ValueTwo.serialize(&mut policy_writer).unwrap();
319 assert_eq!(writer, vec![2, 0, 0, 0]);
320
321 let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
322 let policy = Policy::parse(policy_bytes).unwrap();
323 TestEnum::ValueOne.validate(&policy).unwrap();
324 }
325
326 const TEST_POLICIES: &[(&str, &[u8])] = &[
327 ("selinux_testsuite", include_bytes!("../../testdata/policies/selinux_testsuite")),
328 ("emulator", include_bytes!("../../testdata/policies/emulator")),
329 (
330 "conditional_policy",
331 include_bytes!("../../testdata/composite_policies/compiled/conditional_policy"),
332 ),
333 (
334 "minimal_policy",
335 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy"),
336 ),
337 (
338 "allow_fork_policy",
339 include_bytes!("../../testdata/composite_policies/compiled/allow_fork_policy"),
340 ),
341 (
342 "class_defaults_policy",
343 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy"),
344 ),
345 (
346 "genfscon_policy",
347 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy"),
348 ),
349 (
350 "handle_unknown_policy-allow",
351 include_bytes!(
352 "../../testdata/composite_policies/compiled/handle_unknown_policy-allow"
353 ),
354 ),
355 (
356 "handle_unknown_policy-deny",
357 include_bytes!("../../testdata/composite_policies/compiled/handle_unknown_policy-deny"),
358 ),
359 (
360 "handle_unknown_policy-reject",
361 include_bytes!(
362 "../../testdata/composite_policies/compiled/handle_unknown_policy-reject"
363 ),
364 ),
365 (
366 "range_transition_policy",
367 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy"),
368 ),
369 (
370 "role_transition_policy",
371 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy"),
372 ),
373 (
374 "type_transition_policy",
375 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy"),
376 ),
377 ];
378
379 #[test]
380 fn test_all_compiled_policies_roundtrip() {
381 for (name, policy_bytes) in TEST_POLICIES {
382 let policy = Policy::parse(policy_bytes)
383 .unwrap_or_else(|e| panic!("Failed to parse {name}: {e:?}"));
384 policy.validate().unwrap_or_else(|e| panic!("Failed to validate {name}: {e:?}"));
385
386 if policy.version() >= PolicyVersion::V33 {
387 let mut serialized = Vec::new();
388 policy
389 .serialize(&mut serialized)
390 .unwrap_or_else(|e| panic!("Failed to serialize {name}: {e:?}"));
391 assert_bytes_eq(&serialized, policy_bytes);
392 }
393 }
394 }
395
396 #[test]
397 fn test_initial_sids_policy_elements() {
398 let policy_bytes =
399 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy");
400 let policy = Policy::parse(policy_bytes).expect("parse minimal policy");
401 policy.validate().expect("validate minimal policy");
402
403 assert!(!policy.initial_sids().is_empty());
404 assert!(policy.initial_sids().len() >= crate::InitialSid::all_variants().len() - 1);
405
406 let kernel_context =
407 policy.initial_sids().get_by_id(crate::InitialSid::Kernel as u32).unwrap();
408 assert!(policy.users().get_by_id(kernel_context.user()).is_some());
409 assert!(policy.roles().get_by_id(kernel_context.role()).is_some());
410
411 let unlabeled_context =
412 policy.initial_sids().get_by_id(crate::InitialSid::Unlabeled as u32).unwrap();
413 assert!(policy.users().get_by_id(unlabeled_context.user()).is_some());
414 assert!(policy.roles().get_by_id(unlabeled_context.role()).is_some());
415 }
416
417 #[test]
418 fn test_object_r_role_id_validation() {
419 let policy_bytes =
420 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy");
421 let mut policy = Policy::parse(policy_bytes).expect("parse minimal policy");
422 policy.validate().expect("validate minimal policy");
423
424 let object_r_index =
427 policy.roles.iter().position(|role| role.name() == OBJECT_R_ROLE_NAME).unwrap();
428 let other_index =
429 policy.roles.iter().position(|role| role.name() != OBJECT_R_ROLE_NAME).unwrap();
430 let object_r_id = policy.roles[object_r_index].id();
431 let other_id = policy.roles[other_index].id();
432 policy.roles[object_r_index].set_id(other_id);
433 policy.roles[other_index].set_id(object_r_id);
434
435 let mut serialized = Vec::new();
436 policy.serialize(&mut serialized).expect("serialize modified policy");
437
438 let reparsed = Policy::parse(&serialized).expect("re-parse modified policy");
439 assert_eq!(reparsed.validate(), Err(ValidateError::MissingObjectRRole));
440 }
441}
442
443#[cfg(test)]
444fn assert_bytes_eq(left: &[u8], right: &[u8]) {
445 if left != right {
446 let min_len = std::cmp::min(left.len(), right.len());
447 for i in 0..min_len {
448 if left[i] != right[i] {
449 let start = i.saturating_sub(8);
450 let end = std::cmp::min(i + 16, min_len);
451 panic!(
452 "Byte mismatch at offset {i} (0x{i:x}): actual=0x{:02x} vs expected=0x{:02x}.\nActual [{start}..{end}]: {:02x?}\nExpected [{start}..{end}]: {:02x?}",
453 left[i],
454 right[i],
455 &left[start..end],
456 &right[start..end]
457 );
458 }
459 }
460 panic!("Length mismatch: actual={}, expected={}", left.len(), right.len());
461 }
462}