1pub mod arrays;
6pub mod error;
7pub mod index;
8pub mod metadata;
9pub mod parsed_policy;
10pub mod parser;
11pub mod view;
12
13mod constraints;
14mod extensible_bitmap;
15mod security_context;
16
17pub use arrays::{FsUseType, XpermsBitmap};
18pub use index::FsUseLabelAndType;
19pub use parser::PolicyCursor;
20pub use security_context::{SecurityContext, SecurityContextError};
21
22use crate::new_policy::traits::Serialize as _;
23pub use crate::new_policy::traits::{HasName, HasPolicyId, PolicyId};
24pub use crate::new_policy::{
25 AccessVector, CategoryId, ClassId, HandleUnknown, MlsLevel, MlsRange, POLICYDB_VERSION_MAX,
26 PermissionId, RoleId, SensitivityId, TypeId, User, UserId,
27};
28use crate::{ClassPermission, KernelClass, NullessByteStr, ObjectClass, new_policy as new};
29use index::PolicyIndex;
30use parsed_policy::ParsedPolicy;
31use parser::PolicyData;
32
33use anyhow::Context as _;
34use std::fmt::Debug;
35use std::num::NonZeroU32;
36use std::ops::Deref;
37
38use std::sync::Arc;
39use zerocopy::{
40 FromBytes, Immutable, KnownLayout, Ref, SplitByteSlice, Unaligned, little_endian as le,
41};
42
43impl<T, Tag> Parse for crate::new_policy::IdType<T, Tag>
44where
45 crate::new_policy::IdType<T, Tag>: crate::new_policy::traits::PolicyId,
46{
47 type Error = error::ParseError;
48
49 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
50 let (id_val, tail) = PolicyCursor::parse::<le::U32>(bytes)?;
51 let id = Self::try_from(id_val.get())
52 .map_err(|_| error::ParseError::InvalidId { value: id_val.get() })?;
53 Ok((id, tail))
54 }
55}
56
57impl<T, Tag> Validate for crate::new_policy::IdType<T, Tag>
58where
59 crate::new_policy::IdType<T, Tag>: crate::new_policy::traits::PolicyId,
60{
61 type Error = anyhow::Error;
62
63 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
64 Ok(())
65 }
66}
67
68#[derive(Debug, Clone, PartialEq)]
73pub struct AccessDecision {
74 pub allow: AccessVector,
75 pub auditallow: AccessVector,
76 pub auditdeny: AccessVector,
77 pub flags: u32,
78
79 pub todo_bug: Option<NonZeroU32>,
82}
83
84impl Default for AccessDecision {
85 fn default() -> Self {
86 Self::allow(AccessVector::NONE)
87 }
88}
89
90impl AccessDecision {
91 pub(super) const fn allow(allow: AccessVector) -> Self {
94 Self {
95 allow,
96 auditallow: AccessVector::NONE,
97 auditdeny: AccessVector::ALL,
98 flags: 0,
99 todo_bug: None,
100 }
101 }
102}
103
104pub(super) const SELINUX_AVD_FLAGS_PERMISSIVE: u32 = 1;
106
107#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
110pub enum XpermsKind {
111 Ioctl,
112 Nlmsg,
113}
114
115#[derive(Debug, Clone, PartialEq)]
120pub struct XpermsAccessDecision {
121 pub allow: XpermsBitmap,
122 pub auditallow: XpermsBitmap,
123 pub auditdeny: XpermsBitmap,
124}
125
126impl XpermsAccessDecision {
127 pub const DENY_ALL: Self = Self {
128 allow: XpermsBitmap::NONE,
129 auditallow: XpermsBitmap::NONE,
130 auditdeny: XpermsBitmap::ALL,
131 };
132 pub const ALLOW_ALL: Self = Self {
133 allow: XpermsBitmap::ALL,
134 auditallow: XpermsBitmap::NONE,
135 auditdeny: XpermsBitmap::ALL,
136 };
137}
138
139pub fn parse_policy_by_value(binary_policy: Vec<u8>) -> Result<Unvalidated, anyhow::Error> {
148 let policy_data: PolicyData = Arc::from(binary_policy);
149 let policy = ParsedPolicy::parse(policy_data).context("parsing policy")?;
150 Ok(Unvalidated(policy))
151}
152
153#[derive(Debug)]
154pub struct Policy(PolicyIndex);
155
156impl Deref for Policy {
157 type Target = PolicyIndex;
158
159 fn deref(&self) -> &Self::Target {
160 &self.0
161 }
162}
163
164impl Policy {
165 pub fn serialize(&self) -> PolicyData {
167 let mut bytes = Vec::new();
168 self.0.serialize(&mut bytes).expect("serialization of new_policy should succeed");
169 std::sync::Arc::from(bytes)
170 }
171
172 pub fn conditional_booleans<'a>(&'a self) -> Vec<(&'a [u8], bool)> {
173 self.0
174 .conditional_booleans()
175 .iter()
176 .map(|boolean| (boolean.name(), boolean.active()))
177 .collect()
178 }
179
180 pub fn find_class_permissions_by_name(
185 &self,
186 class_name: &str,
187 ) -> Result<Vec<(PermissionId, Vec<u8>)>, ()> {
188 let classes = self.classes();
189 let class = classes.get_by_name(class_name.as_bytes()).ok_or(())?;
190 let owned_permissions = class.permissions();
191
192 let mut result: Vec<_> = owned_permissions
193 .iter()
194 .map(|permission| (permission.id(), permission.name().to_vec()))
195 .collect();
196
197 if class.common_name().is_empty() {
199 return Ok(result);
200 }
201
202 let common_symbol_permissions =
203 self.common_symbols().get_by_name(class.common_name()).ok_or(())?.permissions();
204
205 result.append(
206 &mut common_symbol_permissions
207 .iter()
208 .map(|permission| (permission.id(), permission.name().to_vec()))
209 .collect(),
210 );
211
212 Ok(result)
213 }
214
215 pub fn fs_use_label_and_type(&self, fs_type: NullessByteStr<'_>) -> Option<FsUseLabelAndType> {
218 self.0.fs_use_label_and_type(fs_type)
219 }
220
221 pub fn genfscon_label_for_fs_and_path(
224 &self,
225 fs_type: NullessByteStr<'_>,
226 node_path: NullessByteStr<'_>,
227 class_id: Option<KernelClass>,
228 ) -> Option<SecurityContext> {
229 self.0.genfscon_label_for_fs_and_path(fs_type, node_path, class_id)
230 }
231
232 pub fn initial_context(&self, id: crate::InitialSid) -> security_context::SecurityContext {
235 self.0.initial_context(id)
236 }
237
238 pub fn parse_security_context(
240 &self,
241 security_context: NullessByteStr<'_>,
242 ) -> Result<security_context::SecurityContext, security_context::SecurityContextError> {
243 security_context::SecurityContext::from_string(&self.0, security_context)
244 }
245
246 pub fn validate_security_context(
248 &self,
249 security_context: &SecurityContext,
250 ) -> Result<(), SecurityContextError> {
251 security_context.validate(&self.0)
252 }
253
254 pub fn serialize_security_context(&self, security_context: &SecurityContext) -> Vec<u8> {
256 security_context.to_string(&self.0)
257 }
258
259 pub fn compute_create_context_with_name(
267 &self,
268 source: &SecurityContext,
269 target: &SecurityContext,
270 class: impl Into<ObjectClass>,
271 name: NullessByteStr<'_>,
272 ) -> Option<SecurityContext> {
273 self.0.compute_create_context_with_name(source, target, class.into(), name)
274 }
275
276 pub fn compute_create_context(
294 &self,
295 source: &SecurityContext,
296 target: &SecurityContext,
297 class: impl Into<ObjectClass>,
298 ) -> SecurityContext {
299 self.0.compute_create_context(source, target, class.into())
300 }
301
302 pub fn compute_access_decision(
312 &self,
313 source_context: &SecurityContext,
314 target_context: &SecurityContext,
315 object_class: impl Into<ObjectClass>,
316 ) -> AccessDecision {
317 if let Some(target_class) = self.0.class(object_class.into()) {
318 self.0.compute_access_decision(source_context, target_context, &target_class)
319 } else {
320 let mut decision = AccessDecision::allow(AccessVector::NONE);
321 if self.is_permissive(source_context.type_()) {
322 decision.flags |= SELINUX_AVD_FLAGS_PERMISSIVE;
323 }
324 decision
325 }
326 }
327
328 pub fn compute_xperms_access_decision(
332 &self,
333 xperms_kind: XpermsKind,
334 source_context: &SecurityContext,
335 target_context: &SecurityContext,
336 object_class: impl Into<ObjectClass>,
337 xperms_prefix: u8,
338 ) -> XpermsAccessDecision {
339 if let Some(target_class) = self.0.class(object_class.into()) {
340 self.0.compute_xperms_access_decision(
341 xperms_kind,
342 source_context,
343 target_context,
344 &target_class,
345 xperms_prefix,
346 )
347 } else {
348 XpermsAccessDecision::DENY_ALL
349 }
350 }
351
352 pub fn is_bounded_by(&self, bounded_type: TypeId, parent_type: TypeId) -> bool {
353 self.0.types().get_by_id(bounded_type).unwrap().bounded_by() == Some(parent_type)
354 }
355
356 pub fn is_permissive(&self, type_: TypeId) -> bool {
358 self.0.permissive_map().contains(type_)
359 }
360}
361
362impl AccessVectorComputer for Policy {
363 fn access_decision_to_kernel_access_decision(
364 &self,
365 class: KernelClass,
366 av: AccessDecision,
367 ) -> KernelAccessDecision {
368 let mut kernel_allow;
369 let mut kernel_audit;
370 if self.0.handle_unknown() == HandleUnknown::Allow {
373 kernel_allow = 0xffffffffu32;
375 kernel_audit = 0u32;
376 } else {
377 kernel_allow = 0u32;
379 kernel_audit = 0xffffffffu32;
380 }
381
382 let decision_allow = av.allow;
383 let decision_audit = (av.allow & av.auditallow) | (!av.allow & av.auditdeny);
384 for permission in class.permissions() {
385 if let Some(permission_access_vector) =
386 self.0.kernel_permission_to_access_vector(permission.clone())
387 {
388 let bit = 1 << permission.id();
391 let allow = decision_allow & permission_access_vector == permission_access_vector;
392 let audit = decision_audit & permission_access_vector == permission_access_vector;
393 kernel_allow = (kernel_allow & !bit) | ((allow as u32) << permission.id());
394 kernel_audit = (kernel_audit & !bit) | ((audit as u32) << permission.id());
395 }
396 }
397 KernelAccessDecision {
398 allow: AccessVector::from(kernel_allow),
399 audit: AccessVector::from(kernel_audit),
400 flags: av.flags,
401 todo_bug: av.todo_bug,
402 }
403 }
404}
405
406pub struct Unvalidated(ParsedPolicy);
408
409impl Unvalidated {
410 pub fn validate(self) -> Result<Policy, anyhow::Error> {
411 self.0.validate().context("validating parsed policy")?;
412 let index = PolicyIndex::new(self.0).context("building index")?;
413 Ok(Policy(index))
414 }
415}
416
417#[derive(Clone, Copy, Debug, PartialEq, Eq)]
418pub struct KernelAccessDecision {
419 pub allow: AccessVector,
420 pub audit: AccessVector,
421 pub flags: u32,
422 pub todo_bug: Option<NonZeroU32>,
423}
424
425pub trait AccessVectorComputer {
428 fn access_decision_to_kernel_access_decision(
435 &self,
436 class: KernelClass,
437 av: AccessDecision,
438 ) -> KernelAccessDecision;
439}
440
441pub trait Parse: Sized {
443 type Error: Into<anyhow::Error>;
446
447 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error>;
450}
451
452pub(super) struct PolicyValidationContext {
454 pub(super) data: PolicyData,
456
457 pub(super) need_init_sid: bool,
459
460 pub(super) new_policy: Arc<new::NewPolicy>,
462}
463
464pub(super) trait Validate {
466 type Error: Into<anyhow::Error>;
469
470 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error>;
472}
473
474pub(super) trait ValidateArray<M, D> {
475 type Error: Into<anyhow::Error>;
478
479 fn validate_array(
481 context: &PolicyValidationContext,
482 metadata: &M,
483 items: &[D],
484 ) -> Result<(), Self::Error>;
485}
486
487pub(super) trait Counted {
489 fn count(&self) -> u32;
491}
492
493impl<T: Validate> Validate for Option<T> {
494 type Error = <T as Validate>::Error;
495
496 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
497 match self {
498 Some(value) => value.validate(context),
499 None => Ok(()),
500 }
501 }
502}
503
504impl<T: Validate> Validate for Vec<T> {
505 type Error = <T as Validate>::Error;
506
507 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
508 for item in self {
509 item.validate(context)?;
510 }
511 Ok(())
512 }
513}
514
515impl Validate for le::U32 {
516 type Error = anyhow::Error;
517
518 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
521 Ok(())
522 }
523}
524
525impl Validate for u8 {
526 type Error = anyhow::Error;
527
528 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
531 Ok(())
532 }
533}
534
535impl<B: SplitByteSlice, T: Validate + FromBytes + KnownLayout + Immutable> Validate for Ref<B, T> {
536 type Error = <T as Validate>::Error;
537
538 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
539 self.deref().validate(context)
540 }
541}
542
543impl<B: SplitByteSlice, T: Counted + FromBytes + KnownLayout + Immutable> Counted for Ref<B, T> {
544 fn count(&self) -> u32 {
545 self.deref().count()
546 }
547}
548
549#[derive(Clone, Debug, PartialEq)]
551struct Array<M, T> {
552 metadata: M,
553 data: Vec<T>,
554}
555
556impl<M: Counted + Parse, T: Parse> Parse for Array<M, T> {
557 type Error = anyhow::Error;
560
561 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
563 let tail = bytes;
564
565 let (metadata, tail) = M::parse(tail).map_err(Into::<anyhow::Error>::into)?;
566
567 let count = metadata.count() as usize;
568 let mut data = Vec::with_capacity(count);
569 let mut cur_tail = tail;
570 for _ in 0..count {
571 let (item, next_tail) = T::parse(cur_tail).map_err(Into::<anyhow::Error>::into)?;
572 data.push(item);
573 cur_tail = next_tail;
574 }
575 let tail = cur_tail;
576
577 let array = Self { metadata, data };
578
579 Ok((array, tail))
580 }
581}
582
583impl<T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned> Parse for T {
584 type Error = anyhow::Error;
585
586 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
587 bytes.parse::<T>().map_err(anyhow::Error::from)
588 }
589}
590
591macro_rules! array_type {
595 ($type_name:ident, $metadata_type:ty, $data_type:ty, $metadata_type_name:expr, $data_type_name:expr) => {
596 #[doc = "An [`Array`] with [`"]
597 #[doc = $metadata_type_name]
598 #[doc = "`] metadata and [`"]
599 #[doc = $data_type_name]
600 #[doc = "`] data items."]
601 #[derive(Debug, PartialEq)]
602 pub(super) struct $type_name(super::Array<$metadata_type, $data_type>);
603
604 impl std::ops::Deref for $type_name {
605 type Target = super::Array<$metadata_type, $data_type>;
606
607 fn deref(&self) -> &Self::Target {
608 &self.0
609 }
610 }
611
612 impl super::Parse for $type_name
613 where
614 super::Array<$metadata_type, $data_type>: super::Parse,
615 {
616 type Error = <Array<$metadata_type, $data_type> as super::Parse>::Error;
617
618 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
619 let (array, tail) = Array::<$metadata_type, $data_type>::parse(bytes)?;
620 Ok((Self(array), tail))
621 }
622 }
623 };
624
625 ($type_name:ident, $metadata_type:ty, $data_type:ty) => {
626 array_type!(
627 $type_name,
628 $metadata_type,
629 $data_type,
630 stringify!($metadata_type),
631 stringify!($data_type)
632 );
633 };
634}
635
636pub(super) use array_type;
637
638macro_rules! array_type_validate_deref_both {
639 ($type_name:ident) => {
640 impl Validate for $type_name {
641 type Error = anyhow::Error;
642
643 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
644 let metadata = &self.metadata;
645 metadata.validate(context)?;
646
647 self.data.validate(context).map_err(Into::<anyhow::Error>::into)?;
648
649 Self::validate_array(context, metadata, &self.data)
650 .map_err(Into::<anyhow::Error>::into)
651 }
652 }
653 };
654}
655
656pub(super) use array_type_validate_deref_both;
657
658#[cfg(test)]
659pub(super) mod testing {
660 use super::error::ParseError;
661
662 pub(super) fn as_parse_error(error: anyhow::Error) -> ParseError {
664 error.downcast::<ParseError>().expect("parse error")
665 }
666}
667
668#[cfg(test)]
669pub(super) mod tests {
670 use super::arrays::XpermsBitmap;
671 use super::security_context::SecurityContext;
672 use super::{
673 AccessVector, ClassId, HandleUnknown, Policy, TypeId, XpermsAccessDecision, XpermsKind,
674 parse_policy_by_value,
675 };
676 use crate::new_policy::traits::HasPolicyId;
677 use crate::{FileClass, InitialSid, KernelClass};
678
679 use anyhow::Context as _;
680 use serde::Deserialize;
681 use std::ops::{Deref, Shl};
682 use zerocopy::little_endian as le;
683
684 fn is_explicitly_allowed(
692 policy: &Policy,
693 source_type: TypeId,
694 target_type: TypeId,
695 target_class: &str,
696 permission: &str,
697 ) -> bool {
698 let classes = policy.classes();
699 let class = classes.get_by_name(target_class.as_bytes()).expect("class not found");
700 let class_permissions = policy
701 .find_class_permissions_by_name(target_class)
702 .expect("class permissions not found");
703 let (permission_id, _) = class_permissions
704 .iter()
705 .find(|(_, name)| permission.as_bytes() == name)
706 .expect("permission not found");
707 let permission_bit = AccessVector::from(*permission_id);
708 let access_decision = policy.0.compute_explicitly_allowed(source_type, target_type, class);
709 permission_bit == access_decision.allow & permission_bit
710 }
711
712 #[derive(Debug, Deserialize)]
713 struct Expectations {
714 expected_policy_version: u32,
715 expected_handle_unknown: LocalHandleUnknown,
716 }
717
718 #[derive(Debug, Deserialize, PartialEq)]
719 #[serde(rename_all = "snake_case")]
720 enum LocalHandleUnknown {
721 Deny,
722 Reject,
723 Allow,
724 }
725
726 impl PartialEq<HandleUnknown> for LocalHandleUnknown {
727 fn eq(&self, other: &HandleUnknown) -> bool {
728 match self {
729 LocalHandleUnknown::Deny => *other == HandleUnknown::Deny,
730 LocalHandleUnknown::Reject => *other == HandleUnknown::Reject,
731 LocalHandleUnknown::Allow => *other == HandleUnknown::Allow,
732 }
733 }
734 }
735
736 fn xperms_bitmap_from_elements(elements: &[u8]) -> XpermsBitmap {
739 let mut bitmap = [le::U32::ZERO; 8];
740 for element in elements {
741 let block_index = (*element as usize) / 32;
742 let bit_index = ((*element as usize) % 32) as u32;
743 let bitmask = le::U32::new(1).shl(bit_index);
744 bitmap[block_index] = bitmap[block_index] | bitmask;
745 }
746 XpermsBitmap::new(bitmap)
747 }
748
749 #[test]
750 fn known_policies() {
751 let policies_and_expectations = [
752 [
753 b"testdata/policies/emulator".to_vec(),
754 include_bytes!("../../testdata/policies/emulator").to_vec(),
755 include_bytes!("../../testdata/expectations/emulator").to_vec(),
756 ],
757 [
758 b"testdata/policies/selinux_testsuite".to_vec(),
759 include_bytes!("../../testdata/policies/selinux_testsuite").to_vec(),
760 include_bytes!("../../testdata/expectations/selinux_testsuite").to_vec(),
761 ],
762 ];
763
764 for [policy_path, policy_bytes, expectations_bytes] in policies_and_expectations {
765 let expectations = serde_json5::from_reader::<_, Expectations>(
766 &mut std::io::Cursor::new(expectations_bytes),
767 )
768 .expect("deserialize expectations");
769
770 let unvalidated_policy =
773 parse_policy_by_value(policy_bytes.clone()).expect("parse policy");
774
775 let policy = unvalidated_policy
776 .validate()
777 .with_context(|| {
778 format!(
779 "policy path: {:?}",
780 std::str::from_utf8(policy_path.as_slice()).unwrap()
781 )
782 })
783 .expect("validate policy");
784
785 assert_eq!(expectations.expected_policy_version, policy.policy_version());
786 assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
787
788 let binary_policy = policy.serialize();
790 assert_eq!(&policy_bytes, binary_policy.deref());
791 }
792 }
793
794 #[test]
795 fn policy_lookup() {
796 let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
797 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
798 let policy = policy.validate().expect("validate selinux testsuite policy");
799
800 let unconfined_t = policy.types().get_by_name(b"unconfined_t").expect("look up type").id();
801
802 assert!(is_explicitly_allowed(&policy, unconfined_t, unconfined_t, "process", "fork",));
803 }
804
805 #[test]
806 fn initial_contexts() {
807 let policy_bytes =
808 include_bytes!("../../testdata/micro_policies/multiple_levels_and_categories_policy");
809 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
810 let policy = policy.validate().expect("validate policy");
811
812 let kernel_context = policy.initial_context(InitialSid::Kernel);
813 assert_eq!(
814 policy.serialize_security_context(&kernel_context),
815 b"user0:object_r:type0:s0:c0-s1:c0.c2,c4"
816 )
817 }
818
819 #[test]
820 fn explicit_allow_type_type() {
821 let policy_bytes =
822 include_bytes!("../../testdata/micro_policies/allow_a_t_b_t_class0_perm0_policy");
823 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
824 let policy = policy.validate().expect("validate policy");
825
826 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
827 let b_t = policy.types().get_by_name(b"b_t").expect("look up type").id();
828
829 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
830 }
831
832 #[test]
833 fn no_explicit_allow_type_type() {
834 let policy_bytes =
835 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_t_class0_perm0_policy");
836 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
837 let policy = policy.validate().expect("validate policy");
838
839 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
840 let b_t = policy.types().get_by_name(b"b_t").expect("look up type").id();
841
842 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
843 }
844
845 #[test]
846 fn explicit_allow_type_attr() {
847 let policy_bytes =
848 include_bytes!("../../testdata/micro_policies/allow_a_t_b_attr_class0_perm0_policy");
849 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
850 let policy = policy.validate().expect("validate policy");
851
852 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
853 let b_t = policy.types().get_by_name(b"b_t").expect("look up type").id();
854
855 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
856 }
857
858 #[test]
859 fn no_explicit_allow_type_attr() {
860 let policy_bytes =
861 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_attr_class0_perm0_policy");
862 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
863 let policy = policy.validate().expect("validate policy");
864
865 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
866 let b_t = policy.types().get_by_name(b"b_t").expect("look up type").id();
867
868 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
869 }
870
871 #[test]
872 fn explicit_allow_attr_attr() {
873 let policy_bytes =
874 include_bytes!("../../testdata/micro_policies/allow_a_attr_b_attr_class0_perm0_policy");
875 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
876 let policy = policy.validate().expect("validate policy");
877
878 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
879 let b_t = policy.types().get_by_name(b"b_t").expect("look up type").id();
880
881 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
882 }
883
884 #[test]
885 fn no_explicit_allow_attr_attr() {
886 let policy_bytes = include_bytes!(
887 "../../testdata/micro_policies/no_allow_a_attr_b_attr_class0_perm0_policy"
888 );
889 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
890 let policy = policy.validate().expect("validate policy");
891
892 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
893 let b_t = policy.types().get_by_name(b"b_t").expect("look up type").id();
894
895 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
896 }
897
898 #[test]
899 fn compute_explicitly_allowed_multiple_attributes() {
900 let policy_bytes = include_bytes!(
901 "../../testdata/micro_policies/allow_a_t_a1_attr_class0_perm0_a2_attr_class0_perm1_policy"
902 );
903 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
904 let policy = policy.validate().expect("validate policy");
905
906 let a_t = policy.types().get_by_name(b"a_t").expect("look up type").id();
907
908 let classes = policy.classes();
909 let class = classes.get_by_name(b"class0").expect("class not found");
910 let raw_access_vector = policy.0.compute_explicitly_allowed(a_t, a_t, class).allow.value();
911
912 assert_eq!(2, raw_access_vector.count_ones());
917 }
918
919 #[test]
920 fn compute_access_decision_with_constraints() {
921 let policy_bytes =
922 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy");
923 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
924 let policy = policy.validate().expect("validate policy");
925
926 let source_context: SecurityContext = policy
927 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
928 .expect("create source security context");
929
930 let target_context_satisfied: SecurityContext = source_context.clone();
931 let decision_satisfied = policy.compute_access_decision(
932 &source_context,
933 &target_context_satisfied,
934 KernelClass::File,
935 );
936 assert_eq!(decision_satisfied.allow, AccessVector::from(7));
940
941 let target_context_unsatisfied: SecurityContext = policy
942 .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
943 .expect("create target security context failing some constraints");
944 let decision_unsatisfied = policy.compute_access_decision(
945 &source_context,
946 &target_context_unsatisfied,
947 KernelClass::File,
948 );
949 assert_eq!(decision_unsatisfied.allow, AccessVector::from(4));
952 }
953
954 #[test]
955 fn compute_ioctl_access_decision_explicitly_allowed() {
956 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
957 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
958 let policy = policy.validate().expect("validate policy");
959
960 let source_context: SecurityContext = policy
961 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
962 .expect("create source security context");
963 let target_context_matched: SecurityContext = source_context.clone();
964
965 let decision_single = policy.compute_xperms_access_decision(
983 XpermsKind::Ioctl,
984 &source_context,
985 &target_context_matched,
986 KernelClass::File,
987 0xab,
988 );
989
990 let mut expected_auditdeny =
991 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
992 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
993
994 let expected_decision_single = XpermsAccessDecision {
995 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
996 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
997 auditdeny: expected_auditdeny,
998 };
999 assert_eq!(decision_single, expected_decision_single);
1000
1001 let decision_range = policy.compute_xperms_access_decision(
1002 XpermsKind::Ioctl,
1003 &source_context,
1004 &target_context_matched,
1005 KernelClass::File,
1006 0x10,
1007 );
1008 let expected_decision_range = XpermsAccessDecision {
1009 allow: XpermsBitmap::ALL,
1010 auditallow: XpermsBitmap::ALL,
1011 auditdeny: XpermsBitmap::NONE,
1012 };
1013 assert_eq!(decision_range, expected_decision_range);
1014 }
1015
1016 #[test]
1017 fn compute_ioctl_access_decision_denied() {
1018 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1019 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1020 let class_id = unvalidated
1021 .0
1022 .classes()
1023 .get_by_name(b"class_one_ioctl")
1024 .expect("look up class_one_ioctl")
1025 .id();
1026 let policy = unvalidated.validate().expect("validate policy");
1027 let source_context: SecurityContext = policy
1028 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1029 .expect("create source security context");
1030 let target_context_matched: SecurityContext = source_context.clone();
1031
1032 let decision_single = policy.compute_xperms_access_decision(
1036 XpermsKind::Ioctl,
1037 &source_context,
1038 &target_context_matched,
1039 class_id,
1040 0xdb,
1041 );
1042
1043 let expected_decision = XpermsAccessDecision {
1044 allow: XpermsBitmap::NONE,
1045 auditallow: XpermsBitmap::NONE,
1046 auditdeny: XpermsBitmap::ALL,
1047 };
1048 assert_eq!(decision_single, expected_decision);
1049 }
1050
1051 #[test]
1052 fn compute_ioctl_access_decision_unmatched() {
1053 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1054 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1055 let policy = policy.validate().expect("validate policy");
1056
1057 let source_context: SecurityContext = policy
1058 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1059 .expect("create source security context");
1060
1061 let target_context_unmatched: SecurityContext = policy
1063 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1064 .expect("create source security context");
1065
1066 for prefix in 0x0..=0xff {
1067 let decision = policy.compute_xperms_access_decision(
1068 XpermsKind::Ioctl,
1069 &source_context,
1070 &target_context_unmatched,
1071 KernelClass::File,
1072 prefix,
1073 );
1074 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1075 }
1076 }
1077
1078 #[test]
1079 fn compute_ioctl_earlier_redundant_prefixful_not_coalesced_into_prefixless() {
1080 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1081 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1082 let class_id = unvalidated
1083 .0
1084 .classes()
1085 .get_by_name(b"class_earlier_redundant_prefixful_not_coalesced_into_prefixless")
1086 .expect("look up class_earlier_redundant_prefixful_not_coalesced_into_prefixless")
1087 .id();
1088 let policy = unvalidated.validate().expect("validate policy");
1089 let source_context: SecurityContext = policy
1090 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1091 .expect("create source security context");
1092 let target_context_matched: SecurityContext = source_context.clone();
1093
1094 let decision = policy.compute_xperms_access_decision(
1099 XpermsKind::Ioctl,
1100 &source_context,
1101 &target_context_matched,
1102 class_id,
1103 0x7f,
1104 );
1105 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1106 let decision = policy.compute_xperms_access_decision(
1107 XpermsKind::Ioctl,
1108 &source_context,
1109 &target_context_matched,
1110 class_id,
1111 0x80,
1112 );
1113 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1114 let decision = policy.compute_xperms_access_decision(
1115 XpermsKind::Ioctl,
1116 &source_context,
1117 &target_context_matched,
1118 class_id,
1119 0x81,
1120 );
1121 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1122 }
1123
1124 #[test]
1125 fn compute_ioctl_later_redundant_prefixful_not_coalesced_into_prefixless() {
1126 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1127 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1128 let class_id = unvalidated
1129 .0
1130 .classes()
1131 .get_by_name(b"class_later_redundant_prefixful_not_coalesced_into_prefixless")
1132 .expect("look up class_later_redundant_prefixful_not_coalesced_into_prefixless")
1133 .id();
1134 let policy = unvalidated.validate().expect("validate policy");
1135 let source_context: SecurityContext = policy
1136 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1137 .expect("create source security context");
1138 let target_context_matched: SecurityContext = source_context.clone();
1139
1140 let decision = policy.compute_xperms_access_decision(
1145 XpermsKind::Ioctl,
1146 &source_context,
1147 &target_context_matched,
1148 class_id,
1149 0x8f,
1150 );
1151 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1152 let decision = policy.compute_xperms_access_decision(
1153 XpermsKind::Ioctl,
1154 &source_context,
1155 &target_context_matched,
1156 class_id,
1157 0x90,
1158 );
1159 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1160 let decision = policy.compute_xperms_access_decision(
1161 XpermsKind::Ioctl,
1162 &source_context,
1163 &target_context_matched,
1164 class_id,
1165 0x91,
1166 );
1167 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1168 }
1169
1170 #[test]
1171 fn compute_ioctl_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless() {
1172 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1173 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1174 let class_id = unvalidated
1175 .0
1176 .classes()
1177 .get_by_name(
1178 b"class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless",
1179 )
1180 .expect(
1181 "look up class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless",
1182 )
1183 .id();
1184 let policy = unvalidated.validate().expect("validate policy");
1185 let source_context: SecurityContext = policy
1186 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1187 .expect("create source security context");
1188 let target_context_matched: SecurityContext = source_context.clone();
1189
1190 let decision = policy.compute_xperms_access_decision(
1196 XpermsKind::Ioctl,
1197 &source_context,
1198 &target_context_matched,
1199 class_id,
1200 0x9f,
1201 );
1202 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1203 let decision = policy.compute_xperms_access_decision(
1204 XpermsKind::Ioctl,
1205 &source_context,
1206 &target_context_matched,
1207 class_id,
1208 0xa0,
1209 );
1210 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1211 let decision = policy.compute_xperms_access_decision(
1212 XpermsKind::Ioctl,
1213 &source_context,
1214 &target_context_matched,
1215 class_id,
1216 0xa1,
1217 );
1218 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1219 }
1220
1221 #[test]
1222 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless() {
1223 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1224 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1225 let class_id: ClassId = unvalidated
1226 .0
1227 .classes()
1228 .get_by_name(b"class_prefixfuls_that_coalesce_to_prefixless")
1229 .expect("look up class_prefixfuls_that_coalesce_to_prefixless")
1230 .id();
1231 let policy = unvalidated.validate().expect("validate policy");
1232 let source_context: SecurityContext = policy
1233 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1234 .expect("create source security context");
1235 let target_context_matched: SecurityContext = source_context.clone();
1236
1237 let decision = policy.compute_xperms_access_decision(
1243 XpermsKind::Ioctl,
1244 &source_context,
1245 &target_context_matched,
1246 class_id,
1247 0xaf,
1248 );
1249 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1250 let decision = policy.compute_xperms_access_decision(
1251 XpermsKind::Ioctl,
1252 &source_context,
1253 &target_context_matched,
1254 class_id,
1255 0xb0,
1256 );
1257 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1258 let decision = policy.compute_xperms_access_decision(
1259 XpermsKind::Ioctl,
1260 &source_context,
1261 &target_context_matched,
1262 class_id,
1263 0xb1,
1264 );
1265 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1266 }
1267
1268 #[test]
1269 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless() {
1270 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1271 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1272 let class_id = unvalidated
1273 .0
1274 .classes()
1275 .get_by_name(b"class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless")
1276 .expect("look up class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless")
1277 .id();
1278 let policy = unvalidated.validate().expect("validate policy");
1279 let source_context: SecurityContext = policy
1280 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1281 .expect("create source security context");
1282 let target_context_matched: SecurityContext = source_context.clone();
1283
1284 let decision = policy.compute_xperms_access_decision(
1291 XpermsKind::Ioctl,
1292 &source_context,
1293 &target_context_matched,
1294 class_id,
1295 0xbf,
1296 );
1297 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1298 let decision = policy.compute_xperms_access_decision(
1299 XpermsKind::Ioctl,
1300 &source_context,
1301 &target_context_matched,
1302 class_id,
1303 0xc0,
1304 );
1305 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1306 let decision = policy.compute_xperms_access_decision(
1307 XpermsKind::Ioctl,
1308 &source_context,
1309 &target_context_matched,
1310 class_id,
1311 0xc1,
1312 );
1313 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1314 let decision = policy.compute_xperms_access_decision(
1315 XpermsKind::Ioctl,
1316 &source_context,
1317 &target_context_matched,
1318 class_id,
1319 0xc2,
1320 );
1321 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1322 }
1323
1324 #[test]
1325 fn compute_ioctl_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless() {
1326 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1327 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1328 let class_id = unvalidated
1329 .0
1330 .classes()
1331 .get_by_name(b"class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless")
1332 .expect("look up class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless")
1333 .id();
1334 let policy = unvalidated.validate().expect("validate policy");
1335 let source_context: SecurityContext = policy
1336 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1337 .expect("create source security context");
1338 let target_context_matched: SecurityContext = source_context.clone();
1339
1340 let decision = policy.compute_xperms_access_decision(
1347 XpermsKind::Ioctl,
1348 &source_context,
1349 &target_context_matched,
1350 class_id,
1351 0xd5,
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 0xd6,
1360 );
1361 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1362 let decision = policy.compute_xperms_access_decision(
1363 XpermsKind::Ioctl,
1364 &source_context,
1365 &target_context_matched,
1366 class_id,
1367 0xd7,
1368 );
1369 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1370 let decision = policy.compute_xperms_access_decision(
1371 XpermsKind::Ioctl,
1372 &source_context,
1373 &target_context_matched,
1374 class_id,
1375 0xd8,
1376 );
1377 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1378 }
1379
1380 #[test]
1391 fn compute_ioctl_ridiculous_permission_ordering() {
1392 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1393 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1394 let class_id = unvalidated
1395 .0
1396 .classes()
1397 .get_by_name(b"class_ridiculous_permission_ordering")
1398 .expect("look up class_ridiculous_permission_ordering")
1399 .id();
1400 let policy = unvalidated.validate().expect("validate policy");
1401 let source_context: SecurityContext = policy
1402 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1403 .expect("create source security context");
1404 let target_context_matched: SecurityContext = source_context.clone();
1405
1406 let decision = policy.compute_xperms_access_decision(
1411 XpermsKind::Ioctl,
1412 &source_context,
1413 &target_context_matched,
1414 class_id,
1415 0x00,
1416 );
1417 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1418 let decision = policy.compute_xperms_access_decision(
1419 XpermsKind::Ioctl,
1420 &source_context,
1421 &target_context_matched,
1422 class_id,
1423 0x01,
1424 );
1425 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1426 let decision = policy.compute_xperms_access_decision(
1427 XpermsKind::Ioctl,
1428 &source_context,
1429 &target_context_matched,
1430 class_id,
1431 0xbf,
1432 );
1433 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1434 let decision = policy.compute_xperms_access_decision(
1435 XpermsKind::Ioctl,
1436 &source_context,
1437 &target_context_matched,
1438 class_id,
1439 0xc0,
1440 );
1441 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1442 let decision = policy.compute_xperms_access_decision(
1443 XpermsKind::Ioctl,
1444 &source_context,
1445 &target_context_matched,
1446 class_id,
1447 0xce,
1448 );
1449 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1450 let decision = policy.compute_xperms_access_decision(
1451 XpermsKind::Ioctl,
1452 &source_context,
1453 &target_context_matched,
1454 class_id,
1455 0xcf,
1456 );
1457 assert_eq!(
1458 decision,
1459 XpermsAccessDecision {
1460 allow: xperms_bitmap_from_elements((0x0..=0xf2).collect::<Vec<_>>().as_slice()),
1461 auditallow: XpermsBitmap::NONE,
1462 auditdeny: XpermsBitmap::ALL,
1463 }
1464 );
1465 let decision = policy.compute_xperms_access_decision(
1466 XpermsKind::Ioctl,
1467 &source_context,
1468 &target_context_matched,
1469 class_id,
1470 0xd0,
1471 );
1472 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1473 let decision = policy.compute_xperms_access_decision(
1474 XpermsKind::Ioctl,
1475 &source_context,
1476 &target_context_matched,
1477 class_id,
1478 0xe9,
1479 );
1480 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1481 let decision = policy.compute_xperms_access_decision(
1482 XpermsKind::Ioctl,
1483 &source_context,
1484 &target_context_matched,
1485 class_id,
1486 0xf0,
1487 );
1488 assert_eq!(
1489 decision,
1490 XpermsAccessDecision {
1491 allow: xperms_bitmap_from_elements(&[0x01]),
1492 auditallow: XpermsBitmap::NONE,
1493 auditdeny: XpermsBitmap::ALL,
1494 }
1495 );
1496 let decision = policy.compute_xperms_access_decision(
1497 XpermsKind::Ioctl,
1498 &source_context,
1499 &target_context_matched,
1500 class_id,
1501 0xf1,
1502 );
1503 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1504 let decision = policy.compute_xperms_access_decision(
1505 XpermsKind::Ioctl,
1506 &source_context,
1507 &target_context_matched,
1508 class_id,
1509 0xfc,
1510 );
1511 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1512 let decision = policy.compute_xperms_access_decision(
1513 XpermsKind::Ioctl,
1514 &source_context,
1515 &target_context_matched,
1516 class_id,
1517 0xfd,
1518 );
1519 assert_eq!(
1520 decision,
1521 XpermsAccessDecision {
1522 allow: xperms_bitmap_from_elements((0xfa..=0xfd).collect::<Vec<_>>().as_slice()),
1523 auditallow: XpermsBitmap::NONE,
1524 auditdeny: XpermsBitmap::ALL,
1525 }
1526 );
1527 let decision = policy.compute_xperms_access_decision(
1528 XpermsKind::Ioctl,
1529 &source_context,
1530 &target_context_matched,
1531 class_id,
1532 0xfe,
1533 );
1534 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1535 }
1536
1537 #[test]
1538 fn compute_nlmsg_access_decision_explicitly_allowed() {
1539 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1540 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1541 let policy = policy.validate().expect("validate policy");
1542
1543 let source_context: SecurityContext = policy
1544 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1545 .expect("create source security context");
1546 let target_context_matched: SecurityContext = source_context.clone();
1547
1548 let decision_single = policy.compute_xperms_access_decision(
1566 XpermsKind::Nlmsg,
1567 &source_context,
1568 &target_context_matched,
1569 KernelClass::NetlinkRouteSocket,
1570 0xab,
1571 );
1572
1573 let mut expected_auditdeny =
1574 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1575 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1576
1577 let expected_decision_single = XpermsAccessDecision {
1578 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1579 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1580 auditdeny: expected_auditdeny,
1581 };
1582 assert_eq!(decision_single, expected_decision_single);
1583
1584 let decision_range = policy.compute_xperms_access_decision(
1585 XpermsKind::Nlmsg,
1586 &source_context,
1587 &target_context_matched,
1588 KernelClass::NetlinkRouteSocket,
1589 0x10,
1590 );
1591 let expected_decision_range = XpermsAccessDecision {
1592 allow: XpermsBitmap::ALL,
1593 auditallow: XpermsBitmap::ALL,
1594 auditdeny: XpermsBitmap::NONE,
1595 };
1596 assert_eq!(decision_range, expected_decision_range);
1597 }
1598
1599 #[test]
1600 fn compute_nlmsg_access_decision_unmatched() {
1601 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1602 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1603 let policy = policy.validate().expect("validate policy");
1604
1605 let source_context: SecurityContext = policy
1606 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1607 .expect("create source security context");
1608
1609 let target_context_unmatched: SecurityContext = policy
1611 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1612 .expect("create source security context");
1613
1614 for prefix in 0x0..=0xff {
1615 let decision = policy.compute_xperms_access_decision(
1616 XpermsKind::Nlmsg,
1617 &source_context,
1618 &target_context_unmatched,
1619 KernelClass::NetlinkRouteSocket,
1620 prefix,
1621 );
1622 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1623 }
1624 }
1625
1626 #[test]
1627 fn compute_ioctl_grant_does_not_cause_nlmsg_deny() {
1628 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1629 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1630 let class_id = unvalidated
1631 .0
1632 .classes()
1633 .get_by_name(b"class_ioctl_grant_does_not_cause_nlmsg_deny")
1634 .expect("look up class_ioctl_grant_does_not_cause_nlmsg_deny")
1635 .id();
1636 let policy = unvalidated.validate().expect("validate policy");
1637 let source_context: SecurityContext = policy
1638 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1639 .expect("create source security context");
1640 let target_context_matched: SecurityContext = source_context.clone();
1641
1642 let ioctl_decision = policy.compute_xperms_access_decision(
1646 XpermsKind::Ioctl,
1647 &source_context,
1648 &target_context_matched,
1649 class_id,
1650 0x00,
1651 );
1652 assert_eq!(
1653 ioctl_decision,
1654 XpermsAccessDecision {
1655 allow: xperms_bitmap_from_elements(&[0x0002]),
1656 auditallow: XpermsBitmap::NONE,
1657 auditdeny: XpermsBitmap::ALL,
1658 }
1659 );
1660 let nlmsg_decision = policy.compute_xperms_access_decision(
1661 XpermsKind::Nlmsg,
1662 &source_context,
1663 &target_context_matched,
1664 class_id,
1665 0x00,
1666 );
1667 assert_eq!(nlmsg_decision, XpermsAccessDecision::ALLOW_ALL);
1668 }
1669
1670 #[test]
1671 fn compute_nlmsg_grant_does_not_cause_ioctl_deny() {
1672 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1673 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1674 let class_id = unvalidated
1675 .0
1676 .classes()
1677 .get_by_name(b"class_nlmsg_grant_does_not_cause_ioctl_deny")
1678 .expect("look up class_nlmsg_grant_does_not_cause_ioctl_deny")
1679 .id();
1680 let policy = unvalidated.validate().expect("validate policy");
1681 let source_context: SecurityContext = policy
1682 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1683 .expect("create source security context");
1684 let target_context_matched: SecurityContext = source_context.clone();
1685
1686 let nlmsg_decision = policy.compute_xperms_access_decision(
1690 XpermsKind::Nlmsg,
1691 &source_context,
1692 &target_context_matched,
1693 class_id,
1694 0x00,
1695 );
1696 assert_eq!(
1697 nlmsg_decision,
1698 XpermsAccessDecision {
1699 allow: xperms_bitmap_from_elements(&[0x0003]),
1700 auditallow: XpermsBitmap::NONE,
1701 auditdeny: XpermsBitmap::ALL,
1702 }
1703 );
1704 let ioctl_decision = policy.compute_xperms_access_decision(
1705 XpermsKind::Ioctl,
1706 &source_context,
1707 &target_context_matched,
1708 class_id,
1709 0x00,
1710 );
1711 assert_eq!(ioctl_decision, XpermsAccessDecision::ALLOW_ALL);
1712 }
1713
1714 #[test]
1715 fn compute_create_context_minimal() {
1716 let policy_bytes =
1717 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy");
1718 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1719 let policy = policy.validate().expect("validate policy");
1720 let source = policy
1721 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1722 .expect("valid source security context");
1723 let target = policy
1724 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1725 .expect("valid target security context");
1726
1727 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1728 let expected: SecurityContext = policy
1729 .parse_security_context(b"source_u:object_r:target_t:s0:c0".into())
1730 .expect("valid expected security context");
1731
1732 assert_eq!(expected, actual);
1733 }
1734
1735 #[test]
1736 fn new_security_context_minimal() {
1737 let policy_bytes =
1738 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy");
1739 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1740 let policy = policy.validate().expect("validate policy");
1741 let source = policy
1742 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1743 .expect("valid source security context");
1744 let target = policy
1745 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1746 .expect("valid target security context");
1747
1748 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1749
1750 assert_eq!(source, actual);
1751 }
1752
1753 #[test]
1754 fn compute_create_context_class_defaults() {
1755 let policy_bytes =
1756 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy");
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"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1764 .expect("valid target security context");
1765
1766 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1767 let expected: SecurityContext = policy
1768 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1769 .expect("valid expected security context");
1770
1771 assert_eq!(expected, actual);
1772 }
1773
1774 #[test]
1775 fn new_security_context_class_defaults() {
1776 let policy_bytes =
1777 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy");
1778 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1779 let policy = policy.validate().expect("validate policy");
1780 let source = policy
1781 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1782 .expect("valid source security context");
1783 let target = policy
1784 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1785 .expect("valid target security context");
1786
1787 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1788 let expected: SecurityContext = policy
1789 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1790 .expect("valid expected security context");
1791
1792 assert_eq!(expected, actual);
1793 }
1794
1795 #[test]
1796 fn compute_create_context_role_transition() {
1797 let policy_bytes =
1798 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy");
1799 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1800 let policy = policy.validate().expect("validate policy");
1801 let source = policy
1802 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1803 .expect("valid source security context");
1804 let target = policy
1805 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1806 .expect("valid target security context");
1807
1808 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1809 let expected: SecurityContext = policy
1810 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
1811 .expect("valid expected security context");
1812
1813 assert_eq!(expected, actual);
1814 }
1815
1816 #[test]
1817 fn new_security_context_role_transition() {
1818 let policy_bytes =
1819 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy");
1820 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1821 let policy = policy.validate().expect("validate policy");
1822 let source = policy
1823 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1824 .expect("valid source security context");
1825 let target = policy
1826 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1827 .expect("valid target security context");
1828
1829 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1830 let expected: SecurityContext = policy
1831 .parse_security_context(b"source_u:transition_r:source_t:s0:c0-s2:c0.c1".into())
1832 .expect("valid expected security context");
1833
1834 assert_eq!(expected, actual);
1835 }
1836
1837 #[test]
1838 #[ignore]
1840 fn compute_create_context_role_transition_not_allowed() {
1841 let policy_bytes = include_bytes!(
1842 "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy"
1843 );
1844 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1845 let policy = policy.validate().expect("validate policy");
1846 let source = policy
1847 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1848 .expect("valid source security context");
1849 let target = policy
1850 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1851 .expect("valid target security context");
1852
1853 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1854
1855 assert!(policy.validate_security_context(&actual).is_err());
1857 }
1858
1859 #[test]
1860 fn compute_create_context_type_transition() {
1861 let policy_bytes =
1862 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy");
1863 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1864 let policy = policy.validate().expect("validate policy");
1865 let source = policy
1866 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1867 .expect("valid source security context");
1868 let target = policy
1869 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1870 .expect("valid target security context");
1871
1872 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1873 let expected: SecurityContext = policy
1874 .parse_security_context(b"source_u:object_r:transition_t:s0:c0".into())
1875 .expect("valid expected security context");
1876
1877 assert_eq!(expected, actual);
1878 }
1879
1880 #[test]
1881 fn new_security_context_type_transition() {
1882 let policy_bytes =
1883 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy");
1884 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1885 let policy = policy.validate().expect("validate policy");
1886 let source = policy
1887 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1888 .expect("valid source security context");
1889 let target = policy
1890 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1891 .expect("valid target security context");
1892
1893 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1894 let expected: SecurityContext = policy
1895 .parse_security_context(b"source_u:source_r:transition_t:s0:c0-s2:c0.c1".into())
1896 .expect("valid expected security context");
1897
1898 assert_eq!(expected, actual);
1899 }
1900
1901 #[test]
1902 fn compute_create_context_range_transition() {
1903 let policy_bytes =
1904 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy");
1905 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1906 let policy = policy.validate().expect("validate policy");
1907 let source = policy
1908 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1909 .expect("valid source security context");
1910 let target = policy
1911 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1912 .expect("valid target security context");
1913
1914 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1915 let expected: SecurityContext = policy
1916 .parse_security_context(b"source_u:object_r:target_t:s1:c1-s2:c1.c2".into())
1917 .expect("valid expected security context");
1918
1919 assert_eq!(expected, actual);
1920 }
1921
1922 #[test]
1923 fn new_security_context_range_transition() {
1924 let policy_bytes =
1925 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy");
1926 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1927 let policy = policy.validate().expect("validate policy");
1928 let source = policy
1929 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1930 .expect("valid source security context");
1931 let target = policy
1932 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1933 .expect("valid target security context");
1934
1935 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1936 let expected: SecurityContext = policy
1937 .parse_security_context(b"source_u:source_r:source_t:s1:c1-s2:c1.c2".into())
1938 .expect("valid expected security context");
1939
1940 assert_eq!(expected, actual);
1941 }
1942
1943 #[test]
1944 fn access_vector_formats() {
1945 assert_eq!(format!("{:x}", AccessVector::NONE), "0");
1946 assert_eq!(format!("{:x}", AccessVector::ALL), "ffffffff");
1947 assert_eq!(format!("{:?}", AccessVector::NONE), "AccessVector(00000000)");
1948 assert_eq!(format!("{:?}", AccessVector::ALL), "AccessVector(ffffffff)");
1949 }
1950
1951 #[test]
1952 fn policy_genfscon_root_path() {
1953 let policy_bytes =
1954 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy");
1955 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1956 let policy = policy.validate().expect("validate selinux policy");
1957
1958 {
1959 let context = policy.genfscon_label_for_fs_and_path(
1960 "fs_with_path_rules".into(),
1961 "/".into(),
1962 None,
1963 );
1964 assert_eq!(
1965 policy.serialize_security_context(&context.unwrap()),
1966 b"system_u:object_r:fs_with_path_rules_t:s0"
1967 )
1968 }
1969 {
1970 let context = policy.genfscon_label_for_fs_and_path(
1971 "fs_2_with_path_rules".into(),
1972 "/".into(),
1973 None,
1974 );
1975 assert_eq!(
1976 policy.serialize_security_context(&context.unwrap()),
1977 b"system_u:object_r:fs_2_with_path_rules_t:s0"
1978 )
1979 }
1980 }
1981
1982 #[test]
1983 fn policy_genfscon_subpaths() {
1984 let policy_bytes =
1985 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy");
1986 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1987 let policy = policy.validate().expect("validate selinux policy");
1988
1989 let path_label_expectations = [
1990 ("/a1/", "system_u:object_r:fs_with_path_rules_a1_t:s0"),
1994 ("/a1/b", "system_u:object_r:fs_with_path_rules_a1_t:s0"),
1995 ("/a1/b/c", "system_u:object_r:fs_with_path_rules_a1_b_c_t:s0"),
1996 ("/a2/", "system_u:object_r:fs_with_path_rules_t:s0"),
1999 ("/a2/b/c/d", "system_u:object_r:fs_with_path_rules_a2_b_t:s0"),
2000 ("/a3/b/c/d", "system_u:object_r:fs_with_path_rules_a3_t:s0"),
2003 ];
2004 for (path, expected_label) in path_label_expectations {
2005 let context = policy.genfscon_label_for_fs_and_path(
2006 "fs_with_path_rules".into(),
2007 path.into(),
2008 None,
2009 );
2010 assert_eq!(
2011 policy.serialize_security_context(&context.unwrap()),
2012 expected_label.as_bytes()
2013 )
2014 }
2015 }
2016
2017 #[test]
2018 fn policy_genfscon_mixed_order() {
2019 let policy_bytes =
2020 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy");
2021 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2022 let policy = policy.validate().expect("validate selinux policy");
2023
2024 let path_label_expectations = [
2025 ("/", "system_u:object_r:fs_mixed_order_t:s0"),
2026 ("/a", "system_u:object_r:fs_mixed_order_a_t:s0"),
2027 ("/a/a", "system_u:object_r:fs_mixed_order_a_a_t:s0"),
2028 ("/a/b", "system_u:object_r:fs_mixed_order_a_b_t:s0"),
2029 ("/a/b/c", "system_u:object_r:fs_mixed_order_a_b_t:s0"),
2030 ];
2031 for (path, expected_label) in path_label_expectations {
2032 let context =
2033 policy.genfscon_label_for_fs_and_path("fs_mixed_order".into(), path.into(), None);
2034 assert_eq!(
2035 policy.serialize_security_context(&context.unwrap()),
2036 expected_label.as_bytes()
2037 );
2038 }
2039 }
2040}