1pub mod arrays;
6pub mod error;
7pub mod index;
8pub mod parsed_policy;
9pub mod parser;
10pub mod view;
11
12mod constraints;
13mod security_context;
14
15pub use crate::new_policy::{
16 AccessDecision, AccessVectorRules, IndexedAccessVectorRules, SELINUX_AVD_FLAGS_PERMISSIVE,
17 XpermsBitmap,
18};
19pub use arrays::FsUseType;
20pub use index::FsUseLabelAndType;
21pub use parser::PolicyCursor;
22pub use security_context::{SecurityContext, SecurityContextError};
23
24use crate::new_policy::traits::Serialize as _;
25pub use crate::new_policy::traits::{HasName, HasPolicyId, PolicyId};
26pub use crate::new_policy::{
27 AccessVector, CategoryId, ClassId, HandleUnknown, MlsLevel, MlsRange, POLICYDB_VERSION_MAX,
28 PermissionId, RoleId, SensitivityId, TypeId, User, UserId,
29};
30use crate::{ClassPermission, KernelClass, NullessByteStr, ObjectClass, new_policy as new};
31use index::PolicyIndex;
32use parsed_policy::ParsedPolicy;
33use parser::PolicyData;
34
35use anyhow::Context as _;
36use std::fmt::Debug;
37use std::num::NonZeroU32;
38use std::ops::Deref;
39
40use std::sync::Arc;
41use zerocopy::{
42 FromBytes, Immutable, KnownLayout, Ref, SplitByteSlice, Unaligned, little_endian as le,
43};
44
45impl<T, Tag> Parse for crate::new_policy::IdType<T, Tag>
46where
47 crate::new_policy::IdType<T, Tag>: crate::new_policy::traits::PolicyId,
48{
49 type Error = error::ParseError;
50
51 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
52 let (id_val, tail) = PolicyCursor::parse::<le::U32>(bytes)?;
53 let id = Self::try_from(id_val.get())
54 .map_err(|_| error::ParseError::InvalidId { value: id_val.get() })?;
55 Ok((id, tail))
56 }
57}
58
59impl<T, Tag> Validate for crate::new_policy::IdType<T, Tag>
60where
61 crate::new_policy::IdType<T, Tag>: crate::new_policy::traits::PolicyId,
62{
63 type Error = anyhow::Error;
64
65 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
66 Ok(())
67 }
68}
69
70#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
76pub enum XpermsKind {
77 Ioctl,
78 Nlmsg,
79}
80
81#[derive(Debug, Clone, PartialEq)]
86pub struct XpermsAccessDecision {
87 pub allow: XpermsBitmap,
88 pub auditallow: XpermsBitmap,
89 pub auditdeny: XpermsBitmap,
90}
91
92impl XpermsAccessDecision {
93 pub const DENY_ALL: Self = Self {
94 allow: XpermsBitmap::NONE,
95 auditallow: XpermsBitmap::NONE,
96 auditdeny: XpermsBitmap::ALL,
97 };
98 pub const ALLOW_ALL: Self = Self {
99 allow: XpermsBitmap::ALL,
100 auditallow: XpermsBitmap::NONE,
101 auditdeny: XpermsBitmap::ALL,
102 };
103}
104
105pub fn parse_policy_by_value(binary_policy: Vec<u8>) -> Result<Unvalidated, anyhow::Error> {
114 let policy_data: PolicyData = Arc::from(binary_policy);
115 let policy = ParsedPolicy::parse(policy_data).context("parsing policy")?;
116 Ok(Unvalidated(policy))
117}
118
119#[derive(Debug)]
120pub struct Policy(PolicyIndex);
121
122impl Deref for Policy {
123 type Target = PolicyIndex;
124
125 fn deref(&self) -> &Self::Target {
126 &self.0
127 }
128}
129
130impl Policy {
131 pub fn serialize(&self) -> PolicyData {
133 let mut bytes = Vec::new();
134 self.0.serialize(&mut bytes).expect("serialization of new_policy should succeed");
135 std::sync::Arc::from(bytes)
136 }
137
138 pub fn conditional_booleans<'a>(&'a self) -> Vec<(&'a [u8], bool)> {
139 self.0
140 .conditional_booleans()
141 .iter()
142 .map(|boolean| (boolean.name(), boolean.active()))
143 .collect()
144 }
145
146 pub fn find_class_permissions_by_name(
151 &self,
152 class_name: &str,
153 ) -> Result<Vec<(PermissionId, Vec<u8>)>, ()> {
154 let classes = self.classes();
155 let class = classes.get_by_name(class_name.as_bytes()).ok_or(())?;
156 let owned_permissions = class.permissions();
157
158 let mut result: Vec<_> = owned_permissions
159 .iter()
160 .map(|permission| (permission.id(), permission.name().to_vec()))
161 .collect();
162
163 if class.common_name().is_empty() {
165 return Ok(result);
166 }
167
168 let common_symbol_permissions =
169 self.common_symbols().get_by_name(class.common_name()).ok_or(())?.permissions();
170
171 result.append(
172 &mut common_symbol_permissions
173 .iter()
174 .map(|permission| (permission.id(), permission.name().to_vec()))
175 .collect(),
176 );
177
178 Ok(result)
179 }
180
181 pub fn fs_use_label_and_type(&self, fs_type: NullessByteStr<'_>) -> Option<FsUseLabelAndType> {
184 self.0.fs_use_label_and_type(fs_type)
185 }
186
187 pub fn genfscon_label_for_fs_and_path(
190 &self,
191 fs_type: NullessByteStr<'_>,
192 node_path: NullessByteStr<'_>,
193 class_id: Option<KernelClass>,
194 ) -> Option<SecurityContext> {
195 self.0.genfscon_label_for_fs_and_path(fs_type, node_path, class_id)
196 }
197
198 pub fn initial_context(&self, id: crate::InitialSid) -> security_context::SecurityContext {
201 self.0.initial_context(id)
202 }
203
204 pub fn parse_security_context(
206 &self,
207 security_context: NullessByteStr<'_>,
208 ) -> Result<security_context::SecurityContext, security_context::SecurityContextError> {
209 security_context::SecurityContext::from_string(&self.0, security_context)
210 }
211
212 pub fn validate_security_context(
214 &self,
215 security_context: &SecurityContext,
216 ) -> Result<(), SecurityContextError> {
217 security_context.validate(&self.0)
218 }
219
220 pub fn serialize_security_context(&self, security_context: &SecurityContext) -> Vec<u8> {
222 security_context.to_string(&self.0)
223 }
224
225 pub fn compute_create_context_with_name(
233 &self,
234 source: &SecurityContext,
235 target: &SecurityContext,
236 class: impl Into<ObjectClass>,
237 name: NullessByteStr<'_>,
238 ) -> Option<SecurityContext> {
239 self.0.compute_create_context_with_name(source, target, class.into(), name)
240 }
241
242 pub fn compute_create_context(
260 &self,
261 source: &SecurityContext,
262 target: &SecurityContext,
263 class: impl Into<ObjectClass>,
264 ) -> SecurityContext {
265 self.0.compute_create_context(source, target, class.into())
266 }
267
268 pub fn compute_access_decision(
278 &self,
279 source_context: &SecurityContext,
280 target_context: &SecurityContext,
281 object_class: impl Into<ObjectClass>,
282 ) -> AccessDecision {
283 if let Some(target_class) = self.0.class(object_class.into()) {
284 self.0.compute_access_decision(source_context, target_context, &target_class)
285 } else {
286 let mut decision = AccessDecision::allow(AccessVector::NONE);
287 if self.is_permissive(source_context.type_()) {
288 decision.flags |= SELINUX_AVD_FLAGS_PERMISSIVE;
289 }
290 decision
291 }
292 }
293
294 pub fn compute_xperms_access_decision(
298 &self,
299 xperms_kind: XpermsKind,
300 source_context: &SecurityContext,
301 target_context: &SecurityContext,
302 object_class: impl Into<ObjectClass>,
303 xperms_prefix: u8,
304 ) -> XpermsAccessDecision {
305 if let Some(target_class) = self.0.class(object_class.into()) {
306 self.0.compute_xperms_access_decision(
307 xperms_kind,
308 source_context,
309 target_context,
310 &target_class,
311 xperms_prefix,
312 )
313 } else {
314 XpermsAccessDecision::DENY_ALL
315 }
316 }
317
318 pub fn is_bounded_by(&self, bounded_type: TypeId, parent_type: TypeId) -> bool {
319 self.0.types().get_by_id(bounded_type).unwrap().bounded_by() == Some(parent_type)
320 }
321
322 pub fn is_permissive(&self, type_: TypeId) -> bool {
324 self.0.permissive_map().contains(type_)
325 }
326}
327
328impl AccessVectorComputer for Policy {
329 fn access_decision_to_kernel_access_decision(
330 &self,
331 class: KernelClass,
332 av: AccessDecision,
333 ) -> KernelAccessDecision {
334 let mut kernel_allow;
335 let mut kernel_audit;
336 if self.0.handle_unknown() == HandleUnknown::Allow {
339 kernel_allow = 0xffffffffu32;
341 kernel_audit = 0u32;
342 } else {
343 kernel_allow = 0u32;
345 kernel_audit = 0xffffffffu32;
346 }
347
348 let decision_allow = av.allow;
349 let decision_audit = (av.allow & av.auditallow) | (!av.allow & av.auditdeny);
350 for permission in class.permissions() {
351 if let Some(permission_access_vector) =
352 self.0.kernel_permission_to_access_vector(permission.clone())
353 {
354 let bit = 1 << permission.id();
357 let allow = decision_allow & permission_access_vector == permission_access_vector;
358 let audit = decision_audit & permission_access_vector == permission_access_vector;
359 kernel_allow = (kernel_allow & !bit) | ((allow as u32) << permission.id());
360 kernel_audit = (kernel_audit & !bit) | ((audit as u32) << permission.id());
361 }
362 }
363 KernelAccessDecision {
364 allow: AccessVector::from(kernel_allow),
365 audit: AccessVector::from(kernel_audit),
366 flags: av.flags,
367 todo_bug: av.todo_bug,
368 }
369 }
370}
371
372pub struct Unvalidated(ParsedPolicy);
374
375impl Unvalidated {
376 pub fn validate(self) -> Result<Policy, anyhow::Error> {
377 self.0.validate().context("validating parsed policy")?;
378 let index = PolicyIndex::new(self.0).context("building index")?;
379 Ok(Policy(index))
380 }
381}
382
383#[derive(Clone, Copy, Debug, PartialEq, Eq)]
384pub struct KernelAccessDecision {
385 pub allow: AccessVector,
386 pub audit: AccessVector,
387 pub flags: u32,
388 pub todo_bug: Option<NonZeroU32>,
389}
390
391pub trait AccessVectorComputer {
394 fn access_decision_to_kernel_access_decision(
401 &self,
402 class: KernelClass,
403 av: AccessDecision,
404 ) -> KernelAccessDecision;
405}
406
407pub trait Parse: Sized {
409 type Error: Into<anyhow::Error>;
412
413 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error>;
416}
417
418pub(super) struct PolicyValidationContext {
420 pub(super) data: PolicyData,
422
423 pub(super) need_init_sid: bool,
425
426 pub(super) new_policy: Arc<new::NewPolicy>,
428}
429
430pub(super) trait Validate {
432 type Error: Into<anyhow::Error>;
435
436 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error>;
438}
439
440pub(super) trait Counted {
442 fn count(&self) -> u32;
444}
445
446impl<T: Validate> Validate for Option<T> {
447 type Error = <T as Validate>::Error;
448
449 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
450 match self {
451 Some(value) => value.validate(context),
452 None => Ok(()),
453 }
454 }
455}
456
457impl<T: Validate> Validate for Vec<T> {
458 type Error = <T as Validate>::Error;
459
460 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
461 for item in self {
462 item.validate(context)?;
463 }
464 Ok(())
465 }
466}
467
468impl Validate for le::U32 {
469 type Error = anyhow::Error;
470
471 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
474 Ok(())
475 }
476}
477
478impl Validate for u8 {
479 type Error = anyhow::Error;
480
481 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
484 Ok(())
485 }
486}
487
488impl<B: SplitByteSlice, T: Validate + FromBytes + KnownLayout + Immutable> Validate for Ref<B, T> {
489 type Error = <T as Validate>::Error;
490
491 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
492 self.deref().validate(context)
493 }
494}
495
496impl<B: SplitByteSlice, T: Counted + FromBytes + KnownLayout + Immutable> Counted for Ref<B, T> {
497 fn count(&self) -> u32 {
498 self.deref().count()
499 }
500}
501
502#[derive(Clone, Debug, PartialEq)]
504struct Array<M, T> {
505 metadata: M,
506 data: Vec<T>,
507}
508
509impl<M: Counted + Parse, T: Parse> Parse for Array<M, T> {
510 type Error = anyhow::Error;
513
514 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
516 let tail = bytes;
517
518 let (metadata, tail) = M::parse(tail).map_err(Into::<anyhow::Error>::into)?;
519
520 let count = metadata.count() as usize;
521 let mut data = Vec::with_capacity(count);
522 let mut cur_tail = tail;
523 for _ in 0..count {
524 let (item, next_tail) = T::parse(cur_tail).map_err(Into::<anyhow::Error>::into)?;
525 data.push(item);
526 cur_tail = next_tail;
527 }
528 let tail = cur_tail;
529
530 let array = Self { metadata, data };
531
532 Ok((array, tail))
533 }
534}
535
536impl<T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned> Parse for T {
537 type Error = anyhow::Error;
538
539 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
540 bytes.parse::<T>().map_err(anyhow::Error::from)
541 }
542}
543
544#[cfg(test)]
545pub(super) mod tests {
546 use super::security_context::SecurityContext;
547 use super::{
548 AccessVector, ClassId, HandleUnknown, Policy, TypeId, XpermsAccessDecision, XpermsBitmap,
549 XpermsKind, parse_policy_by_value,
550 };
551 use crate::new_policy::traits::HasPolicyId;
552 use crate::{FileClass, InitialSid, KernelClass};
553
554 use anyhow::Context as _;
555 use serde::Deserialize;
556 use std::ops::Deref;
557
558 fn is_explicitly_allowed(
566 policy: &Policy,
567 source_type: TypeId,
568 target_type: TypeId,
569 target_class: &str,
570 permission: &str,
571 ) -> bool {
572 let classes = policy.classes();
573 let class = classes.get_by_name(target_class.as_bytes()).expect("class not found");
574 let class_permissions = policy
575 .find_class_permissions_by_name(target_class)
576 .expect("class permissions not found");
577 let (permission_id, _) = class_permissions
578 .iter()
579 .find(|(_, name)| permission.as_bytes() == name)
580 .expect("permission not found");
581 let permission_bit = AccessVector::from(*permission_id);
582 let access_decision = policy.0.compute_explicitly_allowed(source_type, target_type, class);
583 permission_bit == access_decision.allow & permission_bit
584 }
585
586 #[derive(Debug, Deserialize)]
587 struct Expectations {
588 expected_policy_version: u32,
589 expected_handle_unknown: LocalHandleUnknown,
590 }
591
592 #[derive(Debug, Deserialize, PartialEq)]
593 #[serde(rename_all = "snake_case")]
594 enum LocalHandleUnknown {
595 Deny,
596 Reject,
597 Allow,
598 }
599
600 impl PartialEq<HandleUnknown> for LocalHandleUnknown {
601 fn eq(&self, other: &HandleUnknown) -> bool {
602 match self {
603 LocalHandleUnknown::Deny => *other == HandleUnknown::Deny,
604 LocalHandleUnknown::Reject => *other == HandleUnknown::Reject,
605 LocalHandleUnknown::Allow => *other == HandleUnknown::Allow,
606 }
607 }
608 }
609
610 fn xperms_bitmap_from_elements(elements: &[u8]) -> XpermsBitmap {
613 let mut bitmap = [0u64; 4];
614 for element in elements {
615 let block_index = (*element as usize) / 64;
616 let bit_index = (*element as usize) % 64;
617 bitmap[block_index] |= 1u64 << bit_index;
618 }
619 XpermsBitmap::new(bitmap)
620 }
621
622 #[test]
623 fn known_policies() {
624 let policies_and_expectations = [
625 [
626 b"testdata/policies/emulator".to_vec(),
627 include_bytes!("../../testdata/policies/emulator").to_vec(),
628 include_bytes!("../../testdata/expectations/emulator").to_vec(),
629 ],
630 [
631 b"testdata/policies/selinux_testsuite".to_vec(),
632 include_bytes!("../../testdata/policies/selinux_testsuite").to_vec(),
633 include_bytes!("../../testdata/expectations/selinux_testsuite").to_vec(),
634 ],
635 ];
636
637 for [policy_path, policy_bytes, expectations_bytes] in policies_and_expectations {
638 let expectations = serde_json5::from_reader::<_, Expectations>(
639 &mut std::io::Cursor::new(expectations_bytes),
640 )
641 .expect("deserialize expectations");
642
643 let unvalidated_policy =
646 parse_policy_by_value(policy_bytes.clone()).expect("parse policy");
647
648 let policy = unvalidated_policy
649 .validate()
650 .with_context(|| {
651 format!(
652 "policy path: {:?}",
653 std::str::from_utf8(policy_path.as_slice()).unwrap()
654 )
655 })
656 .expect("validate policy");
657
658 assert_eq!(expectations.expected_policy_version, policy.policy_version());
659 assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
660
661 let binary_policy = policy.serialize();
663 assert_eq!(&policy_bytes, binary_policy.deref());
664 }
665 }
666
667 #[test]
668 fn policy_lookup() {
669 let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
670 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
671 let policy = policy.validate().expect("validate selinux testsuite policy");
672
673 let unconfined_t = policy.types().get_by_name(b"unconfined_t").expect("look up type").id();
674
675 assert!(is_explicitly_allowed(&policy, unconfined_t, unconfined_t, "process", "fork",));
676 }
677
678 #[test]
679 fn initial_contexts() {
680 let policy_bytes =
681 include_bytes!("../../testdata/micro_policies/multiple_levels_and_categories_policy");
682 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
683 let policy = policy.validate().expect("validate policy");
684
685 let kernel_context = policy.initial_context(InitialSid::Kernel);
686 assert_eq!(
687 policy.serialize_security_context(&kernel_context),
688 b"user0:object_r:type0:s0:c0-s1:c0.c2,c4"
689 )
690 }
691
692 #[test]
693 fn explicit_allow_type_type() {
694 let policy_bytes =
695 include_bytes!("../../testdata/micro_policies/allow_a_t_b_t_class0_perm0_policy");
696 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
697 let policy = policy.validate().expect("validate policy");
698
699 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
700 let b_t = policy.types().get_by_name(b"b_t").expect("look up type").id();
701
702 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
703 }
704
705 #[test]
706 fn no_explicit_allow_type_type() {
707 let policy_bytes =
708 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_t_class0_perm0_policy");
709 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
710 let policy = policy.validate().expect("validate policy");
711
712 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
713 let b_t = policy.types().get_by_name(b"b_t").expect("look up type").id();
714
715 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
716 }
717
718 #[test]
719 fn explicit_allow_type_attr() {
720 let policy_bytes =
721 include_bytes!("../../testdata/micro_policies/allow_a_t_b_attr_class0_perm0_policy");
722 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
723 let policy = policy.validate().expect("validate policy");
724
725 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
726 let b_t = policy.types().get_by_name(b"b_t").expect("look up type").id();
727
728 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
729 }
730
731 #[test]
732 fn no_explicit_allow_type_attr() {
733 let policy_bytes =
734 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_attr_class0_perm0_policy");
735 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
736 let policy = policy.validate().expect("validate policy");
737
738 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
739 let b_t = policy.types().get_by_name(b"b_t").expect("look up type").id();
740
741 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
742 }
743
744 #[test]
745 fn explicit_allow_attr_attr() {
746 let policy_bytes =
747 include_bytes!("../../testdata/micro_policies/allow_a_attr_b_attr_class0_perm0_policy");
748 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
749 let policy = policy.validate().expect("validate policy");
750
751 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
752 let b_t = policy.types().get_by_name(b"b_t").expect("look up type").id();
753
754 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
755 }
756
757 #[test]
758 fn no_explicit_allow_attr_attr() {
759 let policy_bytes = include_bytes!(
760 "../../testdata/micro_policies/no_allow_a_attr_b_attr_class0_perm0_policy"
761 );
762 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
763 let policy = policy.validate().expect("validate policy");
764
765 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
766 let b_t = policy.types().get_by_name(b"b_t").expect("look up type").id();
767
768 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
769 }
770
771 #[test]
772 fn compute_explicitly_allowed_multiple_attributes() {
773 let policy_bytes = include_bytes!(
774 "../../testdata/micro_policies/allow_a_t_a1_attr_class0_perm0_a2_attr_class0_perm1_policy"
775 );
776 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
777 let policy = policy.validate().expect("validate policy");
778
779 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
780
781 let classes = policy.classes();
782 let class = classes.get_by_name(b"class0").expect("class not found");
783 let raw_access_vector = policy.0.compute_explicitly_allowed(a_t, a_t, class).allow.value();
784
785 assert_eq!(2, raw_access_vector.count_ones());
790 }
791
792 #[test]
793 fn compute_access_decision_with_constraints() {
794 let policy_bytes =
795 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy");
796 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
797 let policy = policy.validate().expect("validate policy");
798
799 let source_context: SecurityContext = policy
800 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
801 .expect("create source security context");
802
803 let target_context_satisfied: SecurityContext = source_context.clone();
804 let decision_satisfied = policy.compute_access_decision(
805 &source_context,
806 &target_context_satisfied,
807 KernelClass::File,
808 );
809 assert_eq!(decision_satisfied.allow, AccessVector::from(7));
813
814 let target_context_unsatisfied: SecurityContext = policy
815 .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
816 .expect("create target security context failing some constraints");
817 let decision_unsatisfied = policy.compute_access_decision(
818 &source_context,
819 &target_context_unsatisfied,
820 KernelClass::File,
821 );
822 assert_eq!(decision_unsatisfied.allow, AccessVector::from(4));
825 }
826
827 #[test]
828 fn compute_ioctl_access_decision_explicitly_allowed() {
829 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
830 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
831 let policy = policy.validate().expect("validate policy");
832
833 let source_context: SecurityContext = policy
834 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
835 .expect("create source security context");
836 let target_context_matched: SecurityContext = source_context.clone();
837
838 let decision_single = policy.compute_xperms_access_decision(
856 XpermsKind::Ioctl,
857 &source_context,
858 &target_context_matched,
859 KernelClass::File,
860 0xab,
861 );
862
863 let mut expected_auditdeny =
864 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
865 expected_auditdeny -= xperms_bitmap_from_elements(&[0xcd, 0xef]);
866
867 let expected_decision_single = XpermsAccessDecision {
868 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
869 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
870 auditdeny: expected_auditdeny,
871 };
872 assert_eq!(decision_single, expected_decision_single);
873
874 let decision_range = policy.compute_xperms_access_decision(
875 XpermsKind::Ioctl,
876 &source_context,
877 &target_context_matched,
878 KernelClass::File,
879 0x10,
880 );
881 let expected_decision_range = XpermsAccessDecision {
882 allow: XpermsBitmap::ALL,
883 auditallow: XpermsBitmap::ALL,
884 auditdeny: XpermsBitmap::NONE,
885 };
886 assert_eq!(decision_range, expected_decision_range);
887 }
888
889 #[test]
890 fn compute_ioctl_access_decision_denied() {
891 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
892 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
893 let class_id = unvalidated
894 .0
895 .classes()
896 .get_by_name(b"class_one_ioctl")
897 .expect("look up class_one_ioctl")
898 .id();
899 let policy = unvalidated.validate().expect("validate policy");
900 let source_context: SecurityContext = policy
901 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
902 .expect("create source security context");
903 let target_context_matched: SecurityContext = source_context.clone();
904
905 let decision_single = policy.compute_xperms_access_decision(
909 XpermsKind::Ioctl,
910 &source_context,
911 &target_context_matched,
912 class_id,
913 0xdb,
914 );
915
916 let expected_decision = XpermsAccessDecision {
917 allow: XpermsBitmap::NONE,
918 auditallow: XpermsBitmap::NONE,
919 auditdeny: XpermsBitmap::ALL,
920 };
921 assert_eq!(decision_single, expected_decision);
922 }
923
924 #[test]
925 fn compute_ioctl_access_decision_unmatched() {
926 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
927 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
928 let policy = policy.validate().expect("validate policy");
929
930 let source_context: SecurityContext = policy
931 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
932 .expect("create source security context");
933
934 let target_context_unmatched: SecurityContext = policy
936 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
937 .expect("create source security context");
938
939 for prefix in 0x0..=0xff {
940 let decision = policy.compute_xperms_access_decision(
941 XpermsKind::Ioctl,
942 &source_context,
943 &target_context_unmatched,
944 KernelClass::File,
945 prefix,
946 );
947 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
948 }
949 }
950
951 #[test]
952 fn compute_ioctl_earlier_redundant_prefixful_not_coalesced_into_prefixless() {
953 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
954 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
955 let class_id = unvalidated
956 .0
957 .classes()
958 .get_by_name(b"class_earlier_redundant_prefixful_not_coalesced_into_prefixless")
959 .expect("look up class_earlier_redundant_prefixful_not_coalesced_into_prefixless")
960 .id();
961 let policy = unvalidated.validate().expect("validate policy");
962 let source_context: SecurityContext = policy
963 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
964 .expect("create source security context");
965 let target_context_matched: SecurityContext = source_context.clone();
966
967 let decision = policy.compute_xperms_access_decision(
972 XpermsKind::Ioctl,
973 &source_context,
974 &target_context_matched,
975 class_id,
976 0x7f,
977 );
978 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
979 let decision = policy.compute_xperms_access_decision(
980 XpermsKind::Ioctl,
981 &source_context,
982 &target_context_matched,
983 class_id,
984 0x80,
985 );
986 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
987 let decision = policy.compute_xperms_access_decision(
988 XpermsKind::Ioctl,
989 &source_context,
990 &target_context_matched,
991 class_id,
992 0x81,
993 );
994 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
995 }
996
997 #[test]
998 fn compute_ioctl_later_redundant_prefixful_not_coalesced_into_prefixless() {
999 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1000 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1001 let class_id = unvalidated
1002 .0
1003 .classes()
1004 .get_by_name(b"class_later_redundant_prefixful_not_coalesced_into_prefixless")
1005 .expect("look up class_later_redundant_prefixful_not_coalesced_into_prefixless")
1006 .id();
1007 let policy = unvalidated.validate().expect("validate policy");
1008 let source_context: SecurityContext = policy
1009 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1010 .expect("create source security context");
1011 let target_context_matched: SecurityContext = source_context.clone();
1012
1013 let decision = policy.compute_xperms_access_decision(
1018 XpermsKind::Ioctl,
1019 &source_context,
1020 &target_context_matched,
1021 class_id,
1022 0x8f,
1023 );
1024 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1025 let decision = policy.compute_xperms_access_decision(
1026 XpermsKind::Ioctl,
1027 &source_context,
1028 &target_context_matched,
1029 class_id,
1030 0x90,
1031 );
1032 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1033 let decision = policy.compute_xperms_access_decision(
1034 XpermsKind::Ioctl,
1035 &source_context,
1036 &target_context_matched,
1037 class_id,
1038 0x91,
1039 );
1040 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1041 }
1042
1043 #[test]
1044 fn compute_ioctl_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless() {
1045 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1046 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1047 let class_id = unvalidated
1048 .0
1049 .classes()
1050 .get_by_name(
1051 b"class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless",
1052 )
1053 .expect(
1054 "look up class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless",
1055 )
1056 .id();
1057 let policy = unvalidated.validate().expect("validate policy");
1058 let source_context: SecurityContext = policy
1059 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1060 .expect("create source security context");
1061 let target_context_matched: SecurityContext = source_context.clone();
1062
1063 let decision = policy.compute_xperms_access_decision(
1069 XpermsKind::Ioctl,
1070 &source_context,
1071 &target_context_matched,
1072 class_id,
1073 0x9f,
1074 );
1075 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1076 let decision = policy.compute_xperms_access_decision(
1077 XpermsKind::Ioctl,
1078 &source_context,
1079 &target_context_matched,
1080 class_id,
1081 0xa0,
1082 );
1083 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1084 let decision = policy.compute_xperms_access_decision(
1085 XpermsKind::Ioctl,
1086 &source_context,
1087 &target_context_matched,
1088 class_id,
1089 0xa1,
1090 );
1091 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1092 }
1093
1094 #[test]
1095 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless() {
1096 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1097 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1098 let class_id: ClassId = unvalidated
1099 .0
1100 .classes()
1101 .get_by_name(b"class_prefixfuls_that_coalesce_to_prefixless")
1102 .expect("look up class_prefixfuls_that_coalesce_to_prefixless")
1103 .id();
1104 let policy = unvalidated.validate().expect("validate policy");
1105 let source_context: SecurityContext = policy
1106 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1107 .expect("create source security context");
1108 let target_context_matched: SecurityContext = source_context.clone();
1109
1110 let decision = policy.compute_xperms_access_decision(
1116 XpermsKind::Ioctl,
1117 &source_context,
1118 &target_context_matched,
1119 class_id,
1120 0xaf,
1121 );
1122 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1123 let decision = policy.compute_xperms_access_decision(
1124 XpermsKind::Ioctl,
1125 &source_context,
1126 &target_context_matched,
1127 class_id,
1128 0xb0,
1129 );
1130 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1131 let decision = policy.compute_xperms_access_decision(
1132 XpermsKind::Ioctl,
1133 &source_context,
1134 &target_context_matched,
1135 class_id,
1136 0xb1,
1137 );
1138 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1139 }
1140
1141 #[test]
1142 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless() {
1143 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1144 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1145 let class_id = unvalidated
1146 .0
1147 .classes()
1148 .get_by_name(b"class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless")
1149 .expect("look up class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless")
1150 .id();
1151 let policy = unvalidated.validate().expect("validate policy");
1152 let source_context: SecurityContext = policy
1153 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1154 .expect("create source security context");
1155 let target_context_matched: SecurityContext = source_context.clone();
1156
1157 let decision = policy.compute_xperms_access_decision(
1164 XpermsKind::Ioctl,
1165 &source_context,
1166 &target_context_matched,
1167 class_id,
1168 0xbf,
1169 );
1170 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1171 let decision = policy.compute_xperms_access_decision(
1172 XpermsKind::Ioctl,
1173 &source_context,
1174 &target_context_matched,
1175 class_id,
1176 0xc0,
1177 );
1178 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1179 let decision = policy.compute_xperms_access_decision(
1180 XpermsKind::Ioctl,
1181 &source_context,
1182 &target_context_matched,
1183 class_id,
1184 0xc1,
1185 );
1186 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1187 let decision = policy.compute_xperms_access_decision(
1188 XpermsKind::Ioctl,
1189 &source_context,
1190 &target_context_matched,
1191 class_id,
1192 0xc2,
1193 );
1194 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1195 }
1196
1197 #[test]
1198 fn compute_ioctl_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless() {
1199 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1200 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1201 let class_id = unvalidated
1202 .0
1203 .classes()
1204 .get_by_name(b"class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless")
1205 .expect("look up class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless")
1206 .id();
1207 let policy = unvalidated.validate().expect("validate policy");
1208 let source_context: SecurityContext = policy
1209 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1210 .expect("create source security context");
1211 let target_context_matched: SecurityContext = source_context.clone();
1212
1213 let decision = policy.compute_xperms_access_decision(
1220 XpermsKind::Ioctl,
1221 &source_context,
1222 &target_context_matched,
1223 class_id,
1224 0xd5,
1225 );
1226 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1227 let decision = policy.compute_xperms_access_decision(
1228 XpermsKind::Ioctl,
1229 &source_context,
1230 &target_context_matched,
1231 class_id,
1232 0xd6,
1233 );
1234 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1235 let decision = policy.compute_xperms_access_decision(
1236 XpermsKind::Ioctl,
1237 &source_context,
1238 &target_context_matched,
1239 class_id,
1240 0xd7,
1241 );
1242 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1243 let decision = policy.compute_xperms_access_decision(
1244 XpermsKind::Ioctl,
1245 &source_context,
1246 &target_context_matched,
1247 class_id,
1248 0xd8,
1249 );
1250 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1251 }
1252
1253 #[test]
1264 fn compute_ioctl_ridiculous_permission_ordering() {
1265 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1266 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1267 let class_id = unvalidated
1268 .0
1269 .classes()
1270 .get_by_name(b"class_ridiculous_permission_ordering")
1271 .expect("look up class_ridiculous_permission_ordering")
1272 .id();
1273 let policy = unvalidated.validate().expect("validate policy");
1274 let source_context: SecurityContext = policy
1275 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1276 .expect("create source security context");
1277 let target_context_matched: SecurityContext = source_context.clone();
1278
1279 let decision = policy.compute_xperms_access_decision(
1284 XpermsKind::Ioctl,
1285 &source_context,
1286 &target_context_matched,
1287 class_id,
1288 0x00,
1289 );
1290 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1291 let decision = policy.compute_xperms_access_decision(
1292 XpermsKind::Ioctl,
1293 &source_context,
1294 &target_context_matched,
1295 class_id,
1296 0x01,
1297 );
1298 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1299 let decision = policy.compute_xperms_access_decision(
1300 XpermsKind::Ioctl,
1301 &source_context,
1302 &target_context_matched,
1303 class_id,
1304 0xbf,
1305 );
1306 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1307 let decision = policy.compute_xperms_access_decision(
1308 XpermsKind::Ioctl,
1309 &source_context,
1310 &target_context_matched,
1311 class_id,
1312 0xc0,
1313 );
1314 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1315 let decision = policy.compute_xperms_access_decision(
1316 XpermsKind::Ioctl,
1317 &source_context,
1318 &target_context_matched,
1319 class_id,
1320 0xce,
1321 );
1322 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1323 let decision = policy.compute_xperms_access_decision(
1324 XpermsKind::Ioctl,
1325 &source_context,
1326 &target_context_matched,
1327 class_id,
1328 0xcf,
1329 );
1330 assert_eq!(
1331 decision,
1332 XpermsAccessDecision {
1333 allow: xperms_bitmap_from_elements((0x0..=0xf2).collect::<Vec<_>>().as_slice()),
1334 auditallow: XpermsBitmap::NONE,
1335 auditdeny: XpermsBitmap::ALL,
1336 }
1337 );
1338 let decision = policy.compute_xperms_access_decision(
1339 XpermsKind::Ioctl,
1340 &source_context,
1341 &target_context_matched,
1342 class_id,
1343 0xd0,
1344 );
1345 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1346 let decision = policy.compute_xperms_access_decision(
1347 XpermsKind::Ioctl,
1348 &source_context,
1349 &target_context_matched,
1350 class_id,
1351 0xe9,
1352 );
1353 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1354 let decision = policy.compute_xperms_access_decision(
1355 XpermsKind::Ioctl,
1356 &source_context,
1357 &target_context_matched,
1358 class_id,
1359 0xf0,
1360 );
1361 assert_eq!(
1362 decision,
1363 XpermsAccessDecision {
1364 allow: xperms_bitmap_from_elements(&[0x01]),
1365 auditallow: XpermsBitmap::NONE,
1366 auditdeny: XpermsBitmap::ALL,
1367 }
1368 );
1369 let decision = policy.compute_xperms_access_decision(
1370 XpermsKind::Ioctl,
1371 &source_context,
1372 &target_context_matched,
1373 class_id,
1374 0xf1,
1375 );
1376 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1377 let decision = policy.compute_xperms_access_decision(
1378 XpermsKind::Ioctl,
1379 &source_context,
1380 &target_context_matched,
1381 class_id,
1382 0xfc,
1383 );
1384 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1385 let decision = policy.compute_xperms_access_decision(
1386 XpermsKind::Ioctl,
1387 &source_context,
1388 &target_context_matched,
1389 class_id,
1390 0xfd,
1391 );
1392 assert_eq!(
1393 decision,
1394 XpermsAccessDecision {
1395 allow: xperms_bitmap_from_elements((0xfa..=0xfd).collect::<Vec<_>>().as_slice()),
1396 auditallow: XpermsBitmap::NONE,
1397 auditdeny: XpermsBitmap::ALL,
1398 }
1399 );
1400 let decision = policy.compute_xperms_access_decision(
1401 XpermsKind::Ioctl,
1402 &source_context,
1403 &target_context_matched,
1404 class_id,
1405 0xfe,
1406 );
1407 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1408 }
1409
1410 #[test]
1411 fn compute_nlmsg_access_decision_explicitly_allowed() {
1412 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1413 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1414 let policy = policy.validate().expect("validate policy");
1415
1416 let source_context: SecurityContext = policy
1417 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1418 .expect("create source security context");
1419 let target_context_matched: SecurityContext = source_context.clone();
1420
1421 let decision_single = policy.compute_xperms_access_decision(
1439 XpermsKind::Nlmsg,
1440 &source_context,
1441 &target_context_matched,
1442 KernelClass::NetlinkRouteSocket,
1443 0xab,
1444 );
1445
1446 let mut expected_auditdeny =
1447 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1448 expected_auditdeny -= xperms_bitmap_from_elements(&[0xcd, 0xef]);
1449
1450 let expected_decision_single = XpermsAccessDecision {
1451 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1452 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1453 auditdeny: expected_auditdeny,
1454 };
1455 assert_eq!(decision_single, expected_decision_single);
1456
1457 let decision_range = policy.compute_xperms_access_decision(
1458 XpermsKind::Nlmsg,
1459 &source_context,
1460 &target_context_matched,
1461 KernelClass::NetlinkRouteSocket,
1462 0x10,
1463 );
1464 let expected_decision_range = XpermsAccessDecision {
1465 allow: XpermsBitmap::ALL,
1466 auditallow: XpermsBitmap::ALL,
1467 auditdeny: XpermsBitmap::NONE,
1468 };
1469 assert_eq!(decision_range, expected_decision_range);
1470 }
1471
1472 #[test]
1473 fn compute_nlmsg_access_decision_unmatched() {
1474 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1475 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1476 let policy = policy.validate().expect("validate policy");
1477
1478 let source_context: SecurityContext = policy
1479 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1480 .expect("create source security context");
1481
1482 let target_context_unmatched: SecurityContext = policy
1484 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1485 .expect("create source security context");
1486
1487 for prefix in 0x0..=0xff {
1488 let decision = policy.compute_xperms_access_decision(
1489 XpermsKind::Nlmsg,
1490 &source_context,
1491 &target_context_unmatched,
1492 KernelClass::NetlinkRouteSocket,
1493 prefix,
1494 );
1495 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1496 }
1497 }
1498
1499 #[test]
1500 fn compute_ioctl_grant_does_not_cause_nlmsg_deny() {
1501 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1502 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1503 let class_id = unvalidated
1504 .0
1505 .classes()
1506 .get_by_name(b"class_ioctl_grant_does_not_cause_nlmsg_deny")
1507 .expect("look up class_ioctl_grant_does_not_cause_nlmsg_deny")
1508 .id();
1509 let policy = unvalidated.validate().expect("validate policy");
1510 let source_context: SecurityContext = policy
1511 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1512 .expect("create source security context");
1513 let target_context_matched: SecurityContext = source_context.clone();
1514
1515 let ioctl_decision = policy.compute_xperms_access_decision(
1519 XpermsKind::Ioctl,
1520 &source_context,
1521 &target_context_matched,
1522 class_id,
1523 0x00,
1524 );
1525 assert_eq!(
1526 ioctl_decision,
1527 XpermsAccessDecision {
1528 allow: xperms_bitmap_from_elements(&[0x0002]),
1529 auditallow: XpermsBitmap::NONE,
1530 auditdeny: XpermsBitmap::ALL,
1531 }
1532 );
1533 let nlmsg_decision = policy.compute_xperms_access_decision(
1534 XpermsKind::Nlmsg,
1535 &source_context,
1536 &target_context_matched,
1537 class_id,
1538 0x00,
1539 );
1540 assert_eq!(nlmsg_decision, XpermsAccessDecision::ALLOW_ALL);
1541 }
1542
1543 #[test]
1544 fn compute_nlmsg_grant_does_not_cause_ioctl_deny() {
1545 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1546 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1547 let class_id = unvalidated
1548 .0
1549 .classes()
1550 .get_by_name(b"class_nlmsg_grant_does_not_cause_ioctl_deny")
1551 .expect("look up class_nlmsg_grant_does_not_cause_ioctl_deny")
1552 .id();
1553 let policy = unvalidated.validate().expect("validate policy");
1554 let source_context: SecurityContext = policy
1555 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1556 .expect("create source security context");
1557 let target_context_matched: SecurityContext = source_context.clone();
1558
1559 let nlmsg_decision = policy.compute_xperms_access_decision(
1563 XpermsKind::Nlmsg,
1564 &source_context,
1565 &target_context_matched,
1566 class_id,
1567 0x00,
1568 );
1569 assert_eq!(
1570 nlmsg_decision,
1571 XpermsAccessDecision {
1572 allow: xperms_bitmap_from_elements(&[0x0003]),
1573 auditallow: XpermsBitmap::NONE,
1574 auditdeny: XpermsBitmap::ALL,
1575 }
1576 );
1577 let ioctl_decision = policy.compute_xperms_access_decision(
1578 XpermsKind::Ioctl,
1579 &source_context,
1580 &target_context_matched,
1581 class_id,
1582 0x00,
1583 );
1584 assert_eq!(ioctl_decision, XpermsAccessDecision::ALLOW_ALL);
1585 }
1586
1587 #[test]
1588 fn compute_create_context_minimal() {
1589 let policy_bytes =
1590 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy");
1591 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1592 let policy = policy.validate().expect("validate policy");
1593 let source = policy
1594 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1595 .expect("valid source security context");
1596 let target = policy
1597 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1598 .expect("valid target security context");
1599
1600 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1601 let expected: SecurityContext = policy
1602 .parse_security_context(b"source_u:object_r:target_t:s0:c0".into())
1603 .expect("valid expected security context");
1604
1605 assert_eq!(expected, actual);
1606 }
1607
1608 #[test]
1609 fn new_security_context_minimal() {
1610 let policy_bytes =
1611 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy");
1612 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1613 let policy = policy.validate().expect("validate policy");
1614 let source = policy
1615 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1616 .expect("valid source security context");
1617 let target = policy
1618 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1619 .expect("valid target security context");
1620
1621 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1622
1623 assert_eq!(source, actual);
1624 }
1625
1626 #[test]
1627 fn compute_create_context_class_defaults() {
1628 let policy_bytes =
1629 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy");
1630 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1631 let policy = policy.validate().expect("validate policy");
1632 let source = policy
1633 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1634 .expect("valid source security context");
1635 let target = policy
1636 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1637 .expect("valid target security context");
1638
1639 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1640 let expected: SecurityContext = policy
1641 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1642 .expect("valid expected security context");
1643
1644 assert_eq!(expected, actual);
1645 }
1646
1647 #[test]
1648 fn new_security_context_class_defaults() {
1649 let policy_bytes =
1650 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy");
1651 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1652 let policy = policy.validate().expect("validate policy");
1653 let source = policy
1654 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1655 .expect("valid source security context");
1656 let target = policy
1657 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1658 .expect("valid target security context");
1659
1660 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1661 let expected: SecurityContext = policy
1662 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1663 .expect("valid expected security context");
1664
1665 assert_eq!(expected, actual);
1666 }
1667
1668 #[test]
1669 fn compute_create_context_role_transition() {
1670 let policy_bytes =
1671 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy");
1672 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1673 let policy = policy.validate().expect("validate policy");
1674 let source = policy
1675 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1676 .expect("valid source security context");
1677 let target = policy
1678 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1679 .expect("valid target security context");
1680
1681 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1682 let expected: SecurityContext = policy
1683 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
1684 .expect("valid expected security context");
1685
1686 assert_eq!(expected, actual);
1687 }
1688
1689 #[test]
1690 fn new_security_context_role_transition() {
1691 let policy_bytes =
1692 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy");
1693 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1694 let policy = policy.validate().expect("validate policy");
1695 let source = policy
1696 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1697 .expect("valid source security context");
1698 let target = policy
1699 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1700 .expect("valid target security context");
1701
1702 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1703 let expected: SecurityContext = policy
1704 .parse_security_context(b"source_u:transition_r:source_t:s0:c0-s2:c0.c1".into())
1705 .expect("valid expected security context");
1706
1707 assert_eq!(expected, actual);
1708 }
1709
1710 #[test]
1711 fn compute_create_context_role_transition_not_allowed() {
1712 let policy_bytes = include_bytes!(
1713 "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy"
1714 );
1715 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1716 let policy = policy.validate().expect("validate policy");
1717 let source = policy
1718 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1719 .expect("valid source security context");
1720 let target = policy
1721 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1722 .expect("valid target security context");
1723
1724 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1725 let expected: SecurityContext = policy
1726 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
1727 .expect("valid expected security context");
1728
1729 assert_eq!(expected, actual);
1732 assert!(policy.validate_security_context(&actual).is_ok());
1733 }
1734
1735 #[test]
1736 fn compute_access_decision_role_allow() {
1737 let policy_bytes =
1739 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy");
1740 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1741 let policy = policy.validate().expect("validate policy");
1742 let source = policy
1743 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1744 .expect("valid source security context");
1745 let target = policy
1746 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
1747 .expect("valid target security context");
1748
1749 let decision_allowed =
1750 policy.compute_access_decision(&source, &target, KernelClass::Process);
1751 assert_ne!(decision_allowed.allow, AccessVector::NONE);
1752
1753 let policy_bytes = include_bytes!(
1755 "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy"
1756 );
1757 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1758 let policy = policy.validate().expect("validate policy");
1759 let source = policy
1760 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1761 .expect("valid source security context");
1762 let target = policy
1763 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
1764 .expect("valid target security context");
1765
1766 let decision_denied =
1767 policy.compute_access_decision(&source, &target, KernelClass::Process);
1768 assert_eq!(decision_denied.allow, AccessVector::NONE);
1769 }
1770
1771 #[test]
1772 fn compute_create_context_type_transition() {
1773 let policy_bytes =
1774 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy");
1775 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1776 let policy = policy.validate().expect("validate policy");
1777 let source = policy
1778 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1779 .expect("valid source security context");
1780 let target = policy
1781 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1782 .expect("valid target security context");
1783
1784 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1785 let expected: SecurityContext = policy
1786 .parse_security_context(b"source_u:object_r:transition_t:s0:c0".into())
1787 .expect("valid expected security context");
1788
1789 assert_eq!(expected, actual);
1790 }
1791
1792 #[test]
1793 fn new_security_context_type_transition() {
1794 let policy_bytes =
1795 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy");
1796 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1797 let policy = policy.validate().expect("validate policy");
1798 let source = policy
1799 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1800 .expect("valid source security context");
1801 let target = policy
1802 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1803 .expect("valid target security context");
1804
1805 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1806 let expected: SecurityContext = policy
1807 .parse_security_context(b"source_u:source_r:transition_t:s0:c0-s2:c0.c1".into())
1808 .expect("valid expected security context");
1809
1810 assert_eq!(expected, actual);
1811 }
1812
1813 #[test]
1814 fn compute_create_context_range_transition() {
1815 let policy_bytes =
1816 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy");
1817 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1818 let policy = policy.validate().expect("validate policy");
1819 let source = policy
1820 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1821 .expect("valid source security context");
1822 let target = policy
1823 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1824 .expect("valid target security context");
1825
1826 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1827 let expected: SecurityContext = policy
1828 .parse_security_context(b"source_u:object_r:target_t:s1:c1-s2:c1.c2".into())
1829 .expect("valid expected security context");
1830
1831 assert_eq!(expected, actual);
1832 }
1833
1834 #[test]
1835 fn new_security_context_range_transition() {
1836 let policy_bytes =
1837 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy");
1838 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1839 let policy = policy.validate().expect("validate policy");
1840 let source = policy
1841 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1842 .expect("valid source security context");
1843 let target = policy
1844 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1845 .expect("valid target security context");
1846
1847 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1848 let expected: SecurityContext = policy
1849 .parse_security_context(b"source_u:source_r:source_t:s1:c1-s2:c1.c2".into())
1850 .expect("valid expected security context");
1851
1852 assert_eq!(expected, actual);
1853 }
1854
1855 #[test]
1856 fn access_vector_formats() {
1857 assert_eq!(format!("{:x}", AccessVector::NONE), "0");
1858 assert_eq!(format!("{:x}", AccessVector::ALL), "ffffffff");
1859 assert_eq!(format!("{:?}", AccessVector::NONE), "AccessVector(00000000)");
1860 assert_eq!(format!("{:?}", AccessVector::ALL), "AccessVector(ffffffff)");
1861 }
1862
1863 #[test]
1864 fn policy_genfscon_root_path() {
1865 let policy_bytes =
1866 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy");
1867 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1868 let policy = policy.validate().expect("validate selinux policy");
1869
1870 {
1871 let context = policy.genfscon_label_for_fs_and_path(
1872 "fs_with_path_rules".into(),
1873 "/".into(),
1874 None,
1875 );
1876 assert_eq!(
1877 policy.serialize_security_context(&context.unwrap()),
1878 b"system_u:object_r:fs_with_path_rules_t:s0"
1879 )
1880 }
1881 {
1882 let context = policy.genfscon_label_for_fs_and_path(
1883 "fs_2_with_path_rules".into(),
1884 "/".into(),
1885 None,
1886 );
1887 assert_eq!(
1888 policy.serialize_security_context(&context.unwrap()),
1889 b"system_u:object_r:fs_2_with_path_rules_t:s0"
1890 )
1891 }
1892 }
1893
1894 #[test]
1895 fn policy_genfscon_subpaths() {
1896 let policy_bytes =
1897 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy");
1898 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1899 let policy = policy.validate().expect("validate selinux policy");
1900
1901 let path_label_expectations = [
1902 ("/a1/", "system_u:object_r:fs_with_path_rules_a1_t:s0"),
1906 ("/a1/b", "system_u:object_r:fs_with_path_rules_a1_t:s0"),
1907 ("/a1/b/c", "system_u:object_r:fs_with_path_rules_a1_b_c_t:s0"),
1908 ("/a2/", "system_u:object_r:fs_with_path_rules_t:s0"),
1911 ("/a2/b/c/d", "system_u:object_r:fs_with_path_rules_a2_b_t:s0"),
1912 ("/a3/b/c/d", "system_u:object_r:fs_with_path_rules_a3_t:s0"),
1915 ];
1916 for (path, expected_label) in path_label_expectations {
1917 let context = policy.genfscon_label_for_fs_and_path(
1918 "fs_with_path_rules".into(),
1919 path.into(),
1920 None,
1921 );
1922 assert_eq!(
1923 policy.serialize_security_context(&context.unwrap()),
1924 expected_label.as_bytes()
1925 )
1926 }
1927 }
1928
1929 #[test]
1930 fn policy_genfscon_mixed_order() {
1931 let policy_bytes =
1932 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy");
1933 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1934 let policy = policy.validate().expect("validate selinux policy");
1935
1936 let path_label_expectations = [
1937 ("/", "system_u:object_r:fs_mixed_order_t:s0"),
1938 ("/a", "system_u:object_r:fs_mixed_order_a_t:s0"),
1939 ("/a/a", "system_u:object_r:fs_mixed_order_a_a_t:s0"),
1940 ("/a/b", "system_u:object_r:fs_mixed_order_a_b_t:s0"),
1941 ("/a/b/c", "system_u:object_r:fs_mixed_order_a_b_t:s0"),
1942 ];
1943 for (path, expected_label) in path_label_expectations {
1944 let context =
1945 policy.genfscon_label_for_fs_and_path("fs_mixed_order".into(), path.into(), None);
1946 assert_eq!(
1947 policy.serialize_security_context(&context.unwrap()),
1948 expected_label.as_bytes()
1949 );
1950 }
1951 }
1952}