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;
16mod symbols;
17
18pub use arrays::{FsUseType, XpermsBitmap};
19pub use index::FsUseLabelAndType;
20pub use parser::PolicyCursor;
21pub use security_context::{SecurityContext, SecurityContextError};
22
23use crate::{ClassPermission, KernelClass, NullessByteStr, ObjectClass, PolicyCap};
24use index::PolicyIndex;
25use metadata::HandleUnknown;
26use parsed_policy::ParsedPolicy;
27use parser::PolicyData;
28use symbols::{find_class_by_name, find_common_symbol_by_name_bytes};
29
30use anyhow::Context as _;
31use std::fmt::{Debug, Display, LowerHex};
32use std::num::{NonZeroU8, NonZeroU32};
33use std::ops::Deref;
34use std::str::FromStr;
35use std::sync::Arc;
36use zerocopy::{
37 FromBytes, Immutable, KnownLayout, Ref, SplitByteSlice, Unaligned, little_endian as le,
38};
39
40#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
42pub struct UserId(NonZeroU32);
43
44#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
46pub struct RoleId(NonZeroU32);
47
48#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
50pub struct TypeId(NonZeroU32);
51
52#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
54pub struct SensitivityId(NonZeroU32);
55
56#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
58pub struct CategoryId(NonZeroU32);
59
60#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
63pub struct ClassId(NonZeroU32);
64
65impl ClassId {
66 pub fn new(id: NonZeroU32) -> Self {
68 Self(id)
69 }
70}
71
72impl Into<u32> for ClassId {
73 fn into(self) -> u32 {
74 self.0.into()
75 }
76}
77
78#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
80pub struct ClassPermissionId(NonZeroU8);
81
82impl Display for ClassPermissionId {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 write!(f, "{}", self.0)
85 }
86}
87
88#[derive(Debug, Clone, PartialEq)]
93pub struct AccessDecision {
94 pub allow: AccessVector,
95 pub auditallow: AccessVector,
96 pub auditdeny: AccessVector,
97 pub flags: u32,
98
99 pub todo_bug: Option<NonZeroU32>,
102}
103
104impl Default for AccessDecision {
105 fn default() -> Self {
106 Self::allow(AccessVector::NONE)
107 }
108}
109
110impl AccessDecision {
111 pub(super) const fn allow(allow: AccessVector) -> Self {
114 Self {
115 allow,
116 auditallow: AccessVector::NONE,
117 auditdeny: AccessVector::ALL,
118 flags: 0,
119 todo_bug: None,
120 }
121 }
122}
123
124pub(super) const SELINUX_AVD_FLAGS_PERMISSIVE: u32 = 1;
126
127#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
130pub struct AccessVector(u32);
131
132impl AccessVector {
133 pub const NONE: AccessVector = AccessVector(0);
134 pub const ALL: AccessVector = AccessVector(std::u32::MAX);
135
136 pub(super) fn from_class_permission_id(id: ClassPermissionId) -> Self {
137 Self((1 as u32) << (id.0.get() - 1))
138 }
139}
140
141impl From<u32> for AccessVector {
142 fn from(x: u32) -> Self {
143 Self(x)
144 }
145}
146
147impl Into<u32> for AccessVector {
148 fn into(self) -> u32 {
149 self.0
150 }
151}
152
153impl Debug for AccessVector {
154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155 write!(f, "AccessVector({:0>8x})", self)
156 }
157}
158
159impl FromStr for AccessVector {
160 type Err = <u32 as FromStr>::Err;
161
162 fn from_str(value: &str) -> Result<Self, Self::Err> {
163 Ok(AccessVector(u32::from_str_radix(value, 16)?))
165 }
166}
167
168impl LowerHex for AccessVector {
169 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170 LowerHex::fmt(&self.0, f)
171 }
172}
173
174impl std::ops::BitAnd for AccessVector {
175 type Output = Self;
176
177 fn bitand(self, rhs: Self) -> Self::Output {
178 AccessVector(self.0 & rhs.0)
179 }
180}
181
182impl std::ops::BitOr for AccessVector {
183 type Output = Self;
184
185 fn bitor(self, rhs: Self) -> Self::Output {
186 AccessVector(self.0 | rhs.0)
187 }
188}
189
190impl std::ops::BitAndAssign for AccessVector {
191 fn bitand_assign(&mut self, rhs: Self) {
192 self.0 &= rhs.0
193 }
194}
195
196impl std::ops::BitOrAssign for AccessVector {
197 fn bitor_assign(&mut self, rhs: Self) {
198 self.0 |= rhs.0
199 }
200}
201
202impl std::ops::SubAssign for AccessVector {
203 fn sub_assign(&mut self, rhs: Self) {
204 self.0 = self.0 ^ (self.0 & rhs.0);
205 }
206}
207
208impl std::ops::Sub for AccessVector {
209 type Output = Self;
210
211 fn sub(self, rhs: Self) -> Self::Output {
212 AccessVector(self.0 ^ (self.0 & rhs.0))
213 }
214}
215
216impl std::ops::Not for AccessVector {
217 type Output = Self;
218
219 fn not(self) -> Self {
220 AccessVector(!self.0)
221 }
222}
223
224#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
227pub enum XpermsKind {
228 Ioctl,
229 Nlmsg,
230}
231
232#[derive(Debug, Clone, PartialEq)]
237pub struct XpermsAccessDecision {
238 pub allow: XpermsBitmap,
239 pub auditallow: XpermsBitmap,
240 pub auditdeny: XpermsBitmap,
241}
242
243impl XpermsAccessDecision {
244 pub const DENY_ALL: Self = Self {
245 allow: XpermsBitmap::NONE,
246 auditallow: XpermsBitmap::NONE,
247 auditdeny: XpermsBitmap::ALL,
248 };
249 pub const ALLOW_ALL: Self = Self {
250 allow: XpermsBitmap::ALL,
251 auditallow: XpermsBitmap::NONE,
252 auditdeny: XpermsBitmap::ALL,
253 };
254}
255
256pub fn parse_policy_by_value(binary_policy: Vec<u8>) -> Result<Unvalidated, anyhow::Error> {
265 let policy_data = Arc::new(binary_policy);
266 let policy = ParsedPolicy::parse(policy_data).context("parsing policy")?;
267 Ok(Unvalidated(policy))
268}
269
270pub struct ClassInfo {
272 pub class_name: Box<[u8]>,
274 pub class_id: ClassId,
276}
277
278#[derive(Debug)]
279pub struct Policy(PolicyIndex);
280
281impl Policy {
282 pub fn policy_version(&self) -> u32 {
284 self.0.parsed_policy().policy_version()
285 }
286
287 pub fn binary(&self) -> &PolicyData {
288 &self.0.parsed_policy().data
289 }
290
291 pub fn handle_unknown(&self) -> HandleUnknown {
294 self.0.parsed_policy().handle_unknown()
295 }
296
297 pub fn conditional_booleans<'a>(&'a self) -> Vec<(&'a [u8], bool)> {
298 self.0
299 .parsed_policy()
300 .conditional_booleans()
301 .iter()
302 .map(|boolean| (boolean.data.as_slice(), boolean.metadata.active()))
303 .collect()
304 }
305
306 pub fn classes(&self) -> Vec<ClassInfo> {
308 self.0
309 .parsed_policy()
310 .classes()
311 .into_iter()
312 .map(|class| ClassInfo {
313 class_name: Box::<[u8]>::from(class.name_bytes()),
314 class_id: class.id(),
315 })
316 .collect()
317 }
318
319 pub(super) fn type_id_by_name(&self, name: &str) -> Option<TypeId> {
321 self.0.parsed_policy().type_id_by_name(name)
322 }
323
324 pub fn find_class_permissions_by_name(
329 &self,
330 class_name: &str,
331 ) -> Result<Vec<(ClassPermissionId, Vec<u8>)>, ()> {
332 let classes = self.0.parsed_policy().classes();
333 let class = find_class_by_name(&classes, class_name).ok_or(())?;
334 let owned_permissions = class.permissions();
335
336 let mut result: Vec<_> = owned_permissions
337 .iter()
338 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
339 .collect();
340
341 if class.common_name_bytes().is_empty() {
343 return Ok(result);
344 }
345
346 let common_symbol_permissions = find_common_symbol_by_name_bytes(
347 self.0.parsed_policy().common_symbols(),
348 class.common_name_bytes(),
349 )
350 .ok_or(())?
351 .permissions();
352
353 result.append(
354 &mut common_symbol_permissions
355 .iter()
356 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
357 .collect(),
358 );
359
360 Ok(result)
361 }
362
363 pub fn fs_use_label_and_type(&self, fs_type: NullessByteStr<'_>) -> Option<FsUseLabelAndType> {
366 self.0.fs_use_label_and_type(fs_type)
367 }
368
369 pub fn genfscon_label_for_fs_and_path(
372 &self,
373 fs_type: NullessByteStr<'_>,
374 node_path: NullessByteStr<'_>,
375 class_id: Option<KernelClass>,
376 ) -> Option<SecurityContext> {
377 self.0.genfscon_label_for_fs_and_path(fs_type, node_path, class_id)
378 }
379
380 pub fn initial_context(&self, id: crate::InitialSid) -> security_context::SecurityContext {
383 self.0.initial_context(id)
384 }
385
386 pub fn parse_security_context(
388 &self,
389 security_context: NullessByteStr<'_>,
390 ) -> Result<security_context::SecurityContext, security_context::SecurityContextError> {
391 security_context::SecurityContext::parse(&self.0, security_context)
392 }
393
394 pub fn validate_security_context(
396 &self,
397 security_context: &SecurityContext,
398 ) -> Result<(), SecurityContextError> {
399 security_context.validate(&self.0)
400 }
401
402 pub fn serialize_security_context(&self, security_context: &SecurityContext) -> Vec<u8> {
404 security_context.serialize(&self.0)
405 }
406
407 pub fn compute_create_context_with_name(
415 &self,
416 source: &SecurityContext,
417 target: &SecurityContext,
418 class: impl Into<ObjectClass>,
419 name: NullessByteStr<'_>,
420 ) -> Option<SecurityContext> {
421 self.0.compute_create_context_with_name(source, target, class.into(), name)
422 }
423
424 pub fn compute_create_context(
442 &self,
443 source: &SecurityContext,
444 target: &SecurityContext,
445 class: impl Into<ObjectClass>,
446 ) -> SecurityContext {
447 self.0.compute_create_context(source, target, class.into())
448 }
449
450 pub fn compute_access_decision(
460 &self,
461 source_context: &SecurityContext,
462 target_context: &SecurityContext,
463 object_class: impl Into<ObjectClass>,
464 ) -> AccessDecision {
465 if let Some(target_class) = self.0.class(object_class.into()) {
466 self.0.parsed_policy().compute_access_decision(
467 source_context,
468 target_context,
469 &target_class,
470 )
471 } else {
472 let mut decision = AccessDecision::allow(AccessVector::NONE);
473 if self.is_permissive(source_context.type_()) {
474 decision.flags |= SELINUX_AVD_FLAGS_PERMISSIVE;
475 }
476 decision
477 }
478 }
479
480 pub fn compute_xperms_access_decision(
484 &self,
485 xperms_kind: XpermsKind,
486 source_context: &SecurityContext,
487 target_context: &SecurityContext,
488 object_class: impl Into<ObjectClass>,
489 xperms_prefix: u8,
490 ) -> XpermsAccessDecision {
491 if let Some(target_class) = self.0.class(object_class.into()) {
492 self.0.parsed_policy().compute_xperms_access_decision(
493 xperms_kind,
494 source_context,
495 target_context,
496 &target_class,
497 xperms_prefix,
498 )
499 } else {
500 XpermsAccessDecision::DENY_ALL
501 }
502 }
503
504 pub fn is_bounded_by(&self, bounded_type: TypeId, parent_type: TypeId) -> bool {
505 self.0.parsed_policy().type_(bounded_type).bounded_by() == Some(parent_type)
506 }
507
508 pub fn is_permissive(&self, type_: TypeId) -> bool {
510 self.0.parsed_policy().permissive_types().is_set(type_.0.get())
511 }
512
513 pub fn has_policycap(&self, policy_cap: PolicyCap) -> bool {
515 self.0.parsed_policy().has_policycap(policy_cap)
516 }
517}
518
519impl AccessVectorComputer for Policy {
520 fn access_decision_to_kernel_access_decision(
521 &self,
522 class: KernelClass,
523 av: AccessDecision,
524 ) -> KernelAccessDecision {
525 let mut kernel_allow;
526 let mut kernel_audit;
527 if self.0.parsed_policy().handle_unknown() == HandleUnknown::Allow {
530 kernel_allow = 0xffffffffu32;
532 kernel_audit = 0u32;
533 } else {
534 kernel_allow = 0u32;
536 kernel_audit = 0xffffffffu32;
537 }
538
539 let decision_allow = av.allow;
540 let decision_audit = (av.allow & av.auditallow) | (!av.allow & av.auditdeny);
541 for permission in class.permissions() {
542 if let Some(permission_access_vector) =
543 self.0.kernel_permission_to_access_vector(permission.clone())
544 {
545 let bit = 1 << permission.id();
548 let allow = decision_allow & permission_access_vector == permission_access_vector;
549 let audit = decision_audit & permission_access_vector == permission_access_vector;
550 kernel_allow = (kernel_allow & !bit) | ((allow as u32) << permission.id());
551 kernel_audit = (kernel_audit & !bit) | ((audit as u32) << permission.id());
552 }
553 }
554 KernelAccessDecision {
555 allow: AccessVector::from(kernel_allow),
556 audit: AccessVector::from(kernel_audit),
557 flags: av.flags,
558 todo_bug: av.todo_bug,
559 }
560 }
561}
562
563pub struct Unvalidated(ParsedPolicy);
565
566impl Unvalidated {
567 pub fn validate(self) -> Result<Policy, anyhow::Error> {
568 self.0.validate().context("validating parsed policy")?;
569 let index = PolicyIndex::new(self.0).context("building index")?;
570 Ok(Policy(index))
571 }
572}
573
574#[derive(Clone, Copy, Debug, PartialEq, Eq)]
575pub struct KernelAccessDecision {
576 pub allow: AccessVector,
577 pub audit: AccessVector,
578 pub flags: u32,
579 pub todo_bug: Option<NonZeroU32>,
580}
581
582pub trait AccessVectorComputer {
585 fn access_decision_to_kernel_access_decision(
592 &self,
593 class: KernelClass,
594 av: AccessDecision,
595 ) -> KernelAccessDecision;
596}
597
598pub trait Parse: Sized {
600 type Error: Into<anyhow::Error>;
603
604 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error>;
607}
608
609pub(super) struct PolicyValidationContext {
611 #[allow(unused)]
613 pub(super) data: PolicyData,
614}
615
616pub(super) trait Validate {
618 type Error: Into<anyhow::Error>;
621
622 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error>;
624}
625
626pub(super) trait ValidateArray<M, D> {
627 type Error: Into<anyhow::Error>;
630
631 fn validate_array(
633 context: &PolicyValidationContext,
634 metadata: &M,
635 items: &[D],
636 ) -> Result<(), Self::Error>;
637}
638
639pub(super) trait Counted {
641 fn count(&self) -> u32;
643}
644
645impl<T: Validate> Validate for Option<T> {
646 type Error = <T as Validate>::Error;
647
648 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
649 match self {
650 Some(value) => value.validate(context),
651 None => Ok(()),
652 }
653 }
654}
655
656impl<T: Validate> Validate for Vec<T> {
657 type Error = <T as Validate>::Error;
658
659 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
660 for item in self {
661 item.validate(context)?;
662 }
663 Ok(())
664 }
665}
666
667impl Validate for le::U32 {
668 type Error = anyhow::Error;
669
670 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
673 Ok(())
674 }
675}
676
677impl Validate for u8 {
678 type Error = anyhow::Error;
679
680 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
683 Ok(())
684 }
685}
686
687impl<B: SplitByteSlice, T: Validate + FromBytes + KnownLayout + Immutable> Validate for Ref<B, T> {
688 type Error = <T as Validate>::Error;
689
690 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
691 self.deref().validate(context)
692 }
693}
694
695impl<B: SplitByteSlice, T: Counted + FromBytes + KnownLayout + Immutable> Counted for Ref<B, T> {
696 fn count(&self) -> u32 {
697 self.deref().count()
698 }
699}
700
701#[derive(Clone, Debug, PartialEq)]
703struct Array<M, T> {
704 metadata: M,
705 data: Vec<T>,
706}
707
708impl<M: Counted + Parse, T: Parse> Parse for Array<M, T> {
709 type Error = anyhow::Error;
712
713 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
715 let tail = bytes;
716
717 let (metadata, tail) = M::parse(tail).map_err(Into::<anyhow::Error>::into)?;
718
719 let count = metadata.count() as usize;
720 let mut data = Vec::with_capacity(count);
721 let mut cur_tail = tail;
722 for _ in 0..count {
723 let (item, next_tail) = T::parse(cur_tail).map_err(Into::<anyhow::Error>::into)?;
724 data.push(item);
725 cur_tail = next_tail;
726 }
727 let tail = cur_tail;
728
729 let array = Self { metadata, data };
730
731 Ok((array, tail))
732 }
733}
734
735impl<T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned> Parse for T {
736 type Error = anyhow::Error;
737
738 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
739 bytes.parse::<T>().map_err(anyhow::Error::from)
740 }
741}
742
743macro_rules! array_type {
747 ($type_name:ident, $metadata_type:ty, $data_type:ty, $metadata_type_name:expr, $data_type_name:expr) => {
748 #[doc = "An [`Array`] with [`"]
749 #[doc = $metadata_type_name]
750 #[doc = "`] metadata and [`"]
751 #[doc = $data_type_name]
752 #[doc = "`] data items."]
753 #[derive(Debug, PartialEq)]
754 pub(super) struct $type_name(super::Array<$metadata_type, $data_type>);
755
756 impl std::ops::Deref for $type_name {
757 type Target = super::Array<$metadata_type, $data_type>;
758
759 fn deref(&self) -> &Self::Target {
760 &self.0
761 }
762 }
763
764 impl super::Parse for $type_name
765 where
766 super::Array<$metadata_type, $data_type>: super::Parse,
767 {
768 type Error = <Array<$metadata_type, $data_type> as super::Parse>::Error;
769
770 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
771 let (array, tail) = Array::<$metadata_type, $data_type>::parse(bytes)?;
772 Ok((Self(array), tail))
773 }
774 }
775 };
776
777 ($type_name:ident, $metadata_type:ty, $data_type:ty) => {
778 array_type!(
779 $type_name,
780 $metadata_type,
781 $data_type,
782 stringify!($metadata_type),
783 stringify!($data_type)
784 );
785 };
786}
787
788pub(super) use array_type;
789
790macro_rules! array_type_validate_deref_both {
791 ($type_name:ident) => {
792 impl Validate for $type_name {
793 type Error = anyhow::Error;
794
795 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
796 let metadata = &self.metadata;
797 metadata.validate(context)?;
798
799 self.data.validate(context).map_err(Into::<anyhow::Error>::into)?;
800
801 Self::validate_array(context, metadata, &self.data)
802 .map_err(Into::<anyhow::Error>::into)
803 }
804 }
805 };
806}
807
808pub(super) use array_type_validate_deref_both;
809
810macro_rules! array_type_validate_deref_data {
811 ($type_name:ident) => {
812 impl Validate for $type_name {
813 type Error = anyhow::Error;
814
815 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
816 let metadata = &self.metadata;
817 metadata.validate(context)?;
818
819 self.data.validate(context).map_err(Into::<anyhow::Error>::into)?;
820
821 Self::validate_array(context, metadata, &self.data)
822 }
823 }
824 };
825}
826
827pub(super) use array_type_validate_deref_data;
828
829macro_rules! array_type_validate_deref_metadata_data_vec {
830 ($type_name:ident) => {
831 impl Validate for $type_name {
832 type Error = anyhow::Error;
833
834 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
835 let metadata = &self.metadata;
836 metadata.validate(context)?;
837
838 self.data.validate(context).map_err(Into::<anyhow::Error>::into)?;
839
840 Self::validate_array(context, metadata, self.data.as_slice())
841 }
842 }
843 };
844}
845
846pub(super) use array_type_validate_deref_metadata_data_vec;
847
848macro_rules! array_type_validate_deref_none_data_vec {
849 ($type_name:ident) => {
850 impl Validate for $type_name {
851 type Error = anyhow::Error;
852
853 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
854 let metadata = &self.metadata;
855 metadata.validate(context)?;
856
857 self.data.validate(context).map_err(Into::<anyhow::Error>::into)?;
858
859 Self::validate_array(context, metadata, self.data.as_slice())
860 }
861 }
862 };
863}
864
865pub(super) use array_type_validate_deref_none_data_vec;
866
867#[cfg(test)]
868pub(super) mod testing {
869 use super::error::{ParseError, ValidateError};
870
871 pub(super) fn as_parse_error(error: anyhow::Error) -> ParseError {
873 error.downcast::<ParseError>().expect("parse error")
874 }
875
876 pub(super) fn as_validate_error(error: anyhow::Error) -> ValidateError {
878 error.downcast::<ValidateError>().expect("validate error")
879 }
880}
881
882#[cfg(test)]
883pub(super) mod tests {
884 use super::arrays::XpermsBitmap;
885 use super::metadata::HandleUnknown;
886 use super::security_context::SecurityContext;
887 use super::symbols::find_class_by_name;
888 use super::{
889 AccessVector, Policy, TypeId, XpermsAccessDecision, XpermsKind, parse_policy_by_value,
890 };
891 use crate::{FileClass, InitialSid, KernelClass};
892
893 use anyhow::Context as _;
894 use serde::Deserialize;
895 use std::ops::{Deref, Shl};
896 use zerocopy::little_endian as le;
897
898 fn is_explicitly_allowed(
906 policy: &Policy,
907 source_type: TypeId,
908 target_type: TypeId,
909 target_class: &str,
910 permission: &str,
911 ) -> bool {
912 let classes = policy.0.parsed_policy().classes();
913 let class = classes
914 .iter()
915 .find(|class| class.name_bytes() == target_class.as_bytes())
916 .expect("class not found");
917 let class_permissions = policy
918 .find_class_permissions_by_name(target_class)
919 .expect("class permissions not found");
920 let (permission_id, _) = class_permissions
921 .iter()
922 .find(|(_, name)| permission.as_bytes() == name)
923 .expect("permission not found");
924 let permission_bit = AccessVector::from_class_permission_id(*permission_id);
925 let access_decision =
926 policy.0.parsed_policy().compute_explicitly_allowed(source_type, target_type, class);
927 permission_bit == access_decision.allow & permission_bit
928 }
929
930 #[derive(Debug, Deserialize)]
931 struct Expectations {
932 expected_policy_version: u32,
933 expected_handle_unknown: LocalHandleUnknown,
934 }
935
936 #[derive(Debug, Deserialize, PartialEq)]
937 #[serde(rename_all = "snake_case")]
938 enum LocalHandleUnknown {
939 Deny,
940 Reject,
941 Allow,
942 }
943
944 impl PartialEq<HandleUnknown> for LocalHandleUnknown {
945 fn eq(&self, other: &HandleUnknown) -> bool {
946 match self {
947 LocalHandleUnknown::Deny => *other == HandleUnknown::Deny,
948 LocalHandleUnknown::Reject => *other == HandleUnknown::Reject,
949 LocalHandleUnknown::Allow => *other == HandleUnknown::Allow,
950 }
951 }
952 }
953
954 fn xperms_bitmap_from_elements(elements: &[u8]) -> XpermsBitmap {
957 let mut bitmap = [le::U32::ZERO; 8];
958 for element in elements {
959 let block_index = (*element as usize) / 32;
960 let bit_index = ((*element as usize) % 32) as u32;
961 let bitmask = le::U32::new(1).shl(bit_index);
962 bitmap[block_index] = bitmap[block_index] | bitmask;
963 }
964 XpermsBitmap::new(bitmap)
965 }
966
967 #[test]
968 fn known_policies() {
969 let policies_and_expectations = [
970 [
971 b"testdata/policies/emulator".to_vec(),
972 include_bytes!("../../testdata/policies/emulator").to_vec(),
973 include_bytes!("../../testdata/expectations/emulator").to_vec(),
974 ],
975 [
976 b"testdata/policies/selinux_testsuite".to_vec(),
977 include_bytes!("../../testdata/policies/selinux_testsuite").to_vec(),
978 include_bytes!("../../testdata/expectations/selinux_testsuite").to_vec(),
979 ],
980 ];
981
982 for [policy_path, policy_bytes, expectations_bytes] in policies_and_expectations {
983 let expectations = serde_json5::from_reader::<_, Expectations>(
984 &mut std::io::Cursor::new(expectations_bytes),
985 )
986 .expect("deserialize expectations");
987
988 let unvalidated_policy =
991 parse_policy_by_value(policy_bytes.clone()).expect("parse policy");
992
993 let policy = unvalidated_policy
994 .validate()
995 .with_context(|| {
996 format!(
997 "policy path: {:?}",
998 std::str::from_utf8(policy_path.as_slice()).unwrap()
999 )
1000 })
1001 .expect("validate policy");
1002
1003 assert_eq!(expectations.expected_policy_version, policy.policy_version());
1004 assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
1005
1006 let binary_policy = policy.binary().clone();
1008 assert_eq!(&policy_bytes, binary_policy.deref());
1009 }
1010 }
1011
1012 #[test]
1013 fn policy_lookup() {
1014 let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
1015 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1016 let policy = policy.validate().expect("validate selinux testsuite policy");
1017
1018 let unconfined_t = policy.type_id_by_name("unconfined_t").expect("look up type id");
1019
1020 assert!(is_explicitly_allowed(&policy, unconfined_t, unconfined_t, "process", "fork",));
1021 }
1022
1023 #[test]
1024 fn initial_contexts() {
1025 let policy_bytes = include_bytes!(
1026 "../../testdata/micro_policies/multiple_levels_and_categories_policy.pp"
1027 );
1028 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1029 let policy = policy.validate().expect("validate policy");
1030
1031 let kernel_context = policy.initial_context(InitialSid::Kernel);
1032 assert_eq!(
1033 policy.serialize_security_context(&kernel_context),
1034 b"user0:object_r:type0:s0:c0-s1:c0.c2,c4"
1035 )
1036 }
1037
1038 #[test]
1039 fn explicit_allow_type_type() {
1040 let policy_bytes =
1041 include_bytes!("../../testdata/micro_policies/allow_a_t_b_t_class0_perm0_policy.pp");
1042 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1043 let policy = policy.validate().expect("validate policy");
1044
1045 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1046 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1047
1048 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1049 }
1050
1051 #[test]
1052 fn no_explicit_allow_type_type() {
1053 let policy_bytes =
1054 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_t_class0_perm0_policy.pp");
1055 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1056 let policy = policy.validate().expect("validate policy");
1057
1058 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1059 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1060
1061 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1062 }
1063
1064 #[test]
1065 fn explicit_allow_type_attr() {
1066 let policy_bytes =
1067 include_bytes!("../../testdata/micro_policies/allow_a_t_b_attr_class0_perm0_policy.pp");
1068 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1069 let policy = policy.validate().expect("validate policy");
1070
1071 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1072 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1073
1074 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1075 }
1076
1077 #[test]
1078 fn no_explicit_allow_type_attr() {
1079 let policy_bytes = include_bytes!(
1080 "../../testdata/micro_policies/no_allow_a_t_b_attr_class0_perm0_policy.pp"
1081 );
1082 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1083 let policy = policy.validate().expect("validate policy");
1084
1085 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1086 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1087
1088 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1089 }
1090
1091 #[test]
1092 fn explicit_allow_attr_attr() {
1093 let policy_bytes = include_bytes!(
1094 "../../testdata/micro_policies/allow_a_attr_b_attr_class0_perm0_policy.pp"
1095 );
1096 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1097 let policy = policy.validate().expect("validate policy");
1098
1099 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1100 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1101
1102 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1103 }
1104
1105 #[test]
1106 fn no_explicit_allow_attr_attr() {
1107 let policy_bytes = include_bytes!(
1108 "../../testdata/micro_policies/no_allow_a_attr_b_attr_class0_perm0_policy.pp"
1109 );
1110 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1111 let policy = policy.validate().expect("validate policy");
1112
1113 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1114 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1115
1116 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1117 }
1118
1119 #[test]
1120 fn compute_explicitly_allowed_multiple_attributes() {
1121 let policy_bytes = include_bytes!(
1122 "../../testdata/micro_policies/allow_a_t_a1_attr_class0_perm0_a2_attr_class0_perm1_policy.pp"
1123 );
1124 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1125 let policy = policy.validate().expect("validate policy");
1126
1127 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1128
1129 let classes = policy.0.parsed_policy().classes();
1130 let class =
1131 classes.iter().find(|class| class.name_bytes() == b"class0").expect("class not found");
1132 let raw_access_vector =
1133 policy.0.parsed_policy().compute_explicitly_allowed(a_t, a_t, class).allow.0;
1134
1135 assert_eq!(2, raw_access_vector.count_ones());
1140 }
1141
1142 #[test]
1143 fn compute_access_decision_with_constraints() {
1144 let policy_bytes =
1145 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1146 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1147 let policy = policy.validate().expect("validate policy");
1148
1149 let source_context: SecurityContext = policy
1150 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1151 .expect("create source security context");
1152
1153 let target_context_satisfied: SecurityContext = source_context.clone();
1154 let decision_satisfied = policy.compute_access_decision(
1155 &source_context,
1156 &target_context_satisfied,
1157 KernelClass::File,
1158 );
1159 assert_eq!(decision_satisfied.allow, AccessVector(7));
1163
1164 let target_context_unsatisfied: SecurityContext = policy
1165 .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1166 .expect("create target security context failing some constraints");
1167 let decision_unsatisfied = policy.compute_access_decision(
1168 &source_context,
1169 &target_context_unsatisfied,
1170 KernelClass::File,
1171 );
1172 assert_eq!(decision_unsatisfied.allow, AccessVector(4));
1175 }
1176
1177 #[test]
1178 fn compute_ioctl_access_decision_explicitly_allowed() {
1179 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1180 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1181 let policy = policy.validate().expect("validate policy");
1182
1183 let source_context: SecurityContext = policy
1184 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1185 .expect("create source security context");
1186 let target_context_matched: SecurityContext = source_context.clone();
1187
1188 let decision_single = policy.compute_xperms_access_decision(
1206 XpermsKind::Ioctl,
1207 &source_context,
1208 &target_context_matched,
1209 KernelClass::File,
1210 0xab,
1211 );
1212
1213 let mut expected_auditdeny =
1214 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1215 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1216
1217 let expected_decision_single = XpermsAccessDecision {
1218 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1219 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1220 auditdeny: expected_auditdeny,
1221 };
1222 assert_eq!(decision_single, expected_decision_single);
1223
1224 let decision_range = policy.compute_xperms_access_decision(
1225 XpermsKind::Ioctl,
1226 &source_context,
1227 &target_context_matched,
1228 KernelClass::File,
1229 0x10,
1230 );
1231 let expected_decision_range = XpermsAccessDecision {
1232 allow: XpermsBitmap::ALL,
1233 auditallow: XpermsBitmap::ALL,
1234 auditdeny: XpermsBitmap::NONE,
1235 };
1236 assert_eq!(decision_range, expected_decision_range);
1237 }
1238
1239 #[test]
1240 fn compute_ioctl_access_decision_denied() {
1241 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1242 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1243 let class_id = find_class_by_name(&unvalidated.0.classes(), "class_one_ioctl")
1244 .expect("look up class_one_ioctl")
1245 .id();
1246 let policy = unvalidated.validate().expect("validate policy");
1247 let source_context: SecurityContext = policy
1248 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1249 .expect("create source security context");
1250 let target_context_matched: SecurityContext = source_context.clone();
1251
1252 let decision_single = policy.compute_xperms_access_decision(
1256 XpermsKind::Ioctl,
1257 &source_context,
1258 &target_context_matched,
1259 class_id,
1260 0xdb,
1261 );
1262
1263 let expected_decision = XpermsAccessDecision {
1264 allow: XpermsBitmap::NONE,
1265 auditallow: XpermsBitmap::NONE,
1266 auditdeny: XpermsBitmap::ALL,
1267 };
1268 assert_eq!(decision_single, expected_decision);
1269 }
1270
1271 #[test]
1272 fn compute_ioctl_access_decision_unmatched() {
1273 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1274 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1275 let policy = policy.validate().expect("validate policy");
1276
1277 let source_context: SecurityContext = policy
1278 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1279 .expect("create source security context");
1280
1281 let target_context_unmatched: SecurityContext = policy
1283 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1284 .expect("create source security context");
1285
1286 for prefix in 0x0..=0xff {
1287 let decision = policy.compute_xperms_access_decision(
1288 XpermsKind::Ioctl,
1289 &source_context,
1290 &target_context_unmatched,
1291 KernelClass::File,
1292 prefix,
1293 );
1294 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1295 }
1296 }
1297
1298 #[test]
1299 fn compute_ioctl_earlier_redundant_prefixful_not_coalesced_into_prefixless() {
1300 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1301 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1302 let class_id = find_class_by_name(
1303 &unvalidated.0.classes(),
1304 "class_earlier_redundant_prefixful_not_coalesced_into_prefixless",
1305 )
1306 .expect("look up class_earlier_redundant_prefixful_not_coalesced_into_prefixless")
1307 .id();
1308 let policy = unvalidated.validate().expect("validate policy");
1309 let source_context: SecurityContext = policy
1310 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1311 .expect("create source security context");
1312 let target_context_matched: SecurityContext = source_context.clone();
1313
1314 let decision = policy.compute_xperms_access_decision(
1319 XpermsKind::Ioctl,
1320 &source_context,
1321 &target_context_matched,
1322 class_id,
1323 0x7f,
1324 );
1325 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1326 let decision = policy.compute_xperms_access_decision(
1327 XpermsKind::Ioctl,
1328 &source_context,
1329 &target_context_matched,
1330 class_id,
1331 0x80,
1332 );
1333 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1334 let decision = policy.compute_xperms_access_decision(
1335 XpermsKind::Ioctl,
1336 &source_context,
1337 &target_context_matched,
1338 class_id,
1339 0x81,
1340 );
1341 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1342 }
1343
1344 #[test]
1345 fn compute_ioctl_later_redundant_prefixful_not_coalesced_into_prefixless() {
1346 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1347 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1348 let class_id = find_class_by_name(
1349 &unvalidated.0.classes(),
1350 "class_later_redundant_prefixful_not_coalesced_into_prefixless",
1351 )
1352 .expect("look up class_later_redundant_prefixful_not_coalesced_into_prefixless")
1353 .id();
1354 let policy = unvalidated.validate().expect("validate policy");
1355 let source_context: SecurityContext = policy
1356 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1357 .expect("create source security context");
1358 let target_context_matched: SecurityContext = source_context.clone();
1359
1360 let decision = policy.compute_xperms_access_decision(
1365 XpermsKind::Ioctl,
1366 &source_context,
1367 &target_context_matched,
1368 class_id,
1369 0x8f,
1370 );
1371 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1372 let decision = policy.compute_xperms_access_decision(
1373 XpermsKind::Ioctl,
1374 &source_context,
1375 &target_context_matched,
1376 class_id,
1377 0x90,
1378 );
1379 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1380 let decision = policy.compute_xperms_access_decision(
1381 XpermsKind::Ioctl,
1382 &source_context,
1383 &target_context_matched,
1384 class_id,
1385 0x91,
1386 );
1387 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1388 }
1389
1390 #[test]
1391 fn compute_ioctl_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless() {
1392 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1393 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1394 let class_id = find_class_by_name(
1395 &unvalidated.0.classes(),
1396 "class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless",
1397 )
1398 .expect("look up class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless")
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(
1412 XpermsKind::Ioctl,
1413 &source_context,
1414 &target_context_matched,
1415 class_id,
1416 0x9f,
1417 );
1418 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1419 let decision = policy.compute_xperms_access_decision(
1420 XpermsKind::Ioctl,
1421 &source_context,
1422 &target_context_matched,
1423 class_id,
1424 0xa0,
1425 );
1426 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1427 let decision = policy.compute_xperms_access_decision(
1428 XpermsKind::Ioctl,
1429 &source_context,
1430 &target_context_matched,
1431 class_id,
1432 0xa1,
1433 );
1434 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1435 }
1436
1437 #[test]
1438 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless() {
1439 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1440 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1441 let class_id = find_class_by_name(
1442 &unvalidated.0.classes(),
1443 "class_prefixfuls_that_coalesce_to_prefixless",
1444 )
1445 .expect("look up class_prefixfuls_that_coalesce_to_prefixless")
1446 .id();
1447 let policy = unvalidated.validate().expect("validate policy");
1448 let source_context: SecurityContext = policy
1449 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1450 .expect("create source security context");
1451 let target_context_matched: SecurityContext = source_context.clone();
1452
1453 let decision = policy.compute_xperms_access_decision(
1459 XpermsKind::Ioctl,
1460 &source_context,
1461 &target_context_matched,
1462 class_id,
1463 0xaf,
1464 );
1465 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1466 let decision = policy.compute_xperms_access_decision(
1467 XpermsKind::Ioctl,
1468 &source_context,
1469 &target_context_matched,
1470 class_id,
1471 0xb0,
1472 );
1473 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1474 let decision = policy.compute_xperms_access_decision(
1475 XpermsKind::Ioctl,
1476 &source_context,
1477 &target_context_matched,
1478 class_id,
1479 0xb1,
1480 );
1481 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1482 }
1483
1484 #[test]
1485 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless() {
1486 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1487 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1488 let class_id = find_class_by_name(
1489 &unvalidated.0.classes(),
1490 "class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless",
1491 )
1492 .expect("look up class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless")
1493 .id();
1494 let policy = unvalidated.validate().expect("validate policy");
1495 let source_context: SecurityContext = policy
1496 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1497 .expect("create source security context");
1498 let target_context_matched: SecurityContext = source_context.clone();
1499
1500 let decision = policy.compute_xperms_access_decision(
1507 XpermsKind::Ioctl,
1508 &source_context,
1509 &target_context_matched,
1510 class_id,
1511 0xbf,
1512 );
1513 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1514 let decision = policy.compute_xperms_access_decision(
1515 XpermsKind::Ioctl,
1516 &source_context,
1517 &target_context_matched,
1518 class_id,
1519 0xc0,
1520 );
1521 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1522 let decision = policy.compute_xperms_access_decision(
1523 XpermsKind::Ioctl,
1524 &source_context,
1525 &target_context_matched,
1526 class_id,
1527 0xc1,
1528 );
1529 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1530 let decision = policy.compute_xperms_access_decision(
1531 XpermsKind::Ioctl,
1532 &source_context,
1533 &target_context_matched,
1534 class_id,
1535 0xc2,
1536 );
1537 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1538 }
1539
1540 #[test]
1541 fn compute_ioctl_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless() {
1542 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1543 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1544 let class_id = find_class_by_name(
1545 &unvalidated.0.classes(),
1546 "class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless",
1547 )
1548 .expect("look up class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless")
1549 .id();
1550 let policy = unvalidated.validate().expect("validate policy");
1551 let source_context: SecurityContext = policy
1552 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1553 .expect("create source security context");
1554 let target_context_matched: SecurityContext = source_context.clone();
1555
1556 let decision = policy.compute_xperms_access_decision(
1563 XpermsKind::Ioctl,
1564 &source_context,
1565 &target_context_matched,
1566 class_id,
1567 0xd5,
1568 );
1569 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1570 let decision = policy.compute_xperms_access_decision(
1571 XpermsKind::Ioctl,
1572 &source_context,
1573 &target_context_matched,
1574 class_id,
1575 0xd6,
1576 );
1577 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1578 let decision = policy.compute_xperms_access_decision(
1579 XpermsKind::Ioctl,
1580 &source_context,
1581 &target_context_matched,
1582 class_id,
1583 0xd7,
1584 );
1585 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1586 let decision = policy.compute_xperms_access_decision(
1587 XpermsKind::Ioctl,
1588 &source_context,
1589 &target_context_matched,
1590 class_id,
1591 0xd8,
1592 );
1593 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1594 }
1595
1596 #[test]
1607 fn compute_ioctl_ridiculous_permission_ordering() {
1608 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1609 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1610 let class_id =
1611 find_class_by_name(&unvalidated.0.classes(), "class_ridiculous_permission_ordering")
1612 .expect("look up class_ridiculous_permission_ordering")
1613 .id();
1614 let policy = unvalidated.validate().expect("validate policy");
1615 let source_context: SecurityContext = policy
1616 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1617 .expect("create source security context");
1618 let target_context_matched: SecurityContext = source_context.clone();
1619
1620 let decision = policy.compute_xperms_access_decision(
1625 XpermsKind::Ioctl,
1626 &source_context,
1627 &target_context_matched,
1628 class_id,
1629 0x00,
1630 );
1631 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1632 let decision = policy.compute_xperms_access_decision(
1633 XpermsKind::Ioctl,
1634 &source_context,
1635 &target_context_matched,
1636 class_id,
1637 0x01,
1638 );
1639 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1640 let decision = policy.compute_xperms_access_decision(
1641 XpermsKind::Ioctl,
1642 &source_context,
1643 &target_context_matched,
1644 class_id,
1645 0xbf,
1646 );
1647 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1648 let decision = policy.compute_xperms_access_decision(
1649 XpermsKind::Ioctl,
1650 &source_context,
1651 &target_context_matched,
1652 class_id,
1653 0xc0,
1654 );
1655 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1656 let decision = policy.compute_xperms_access_decision(
1657 XpermsKind::Ioctl,
1658 &source_context,
1659 &target_context_matched,
1660 class_id,
1661 0xce,
1662 );
1663 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1664 let decision = policy.compute_xperms_access_decision(
1665 XpermsKind::Ioctl,
1666 &source_context,
1667 &target_context_matched,
1668 class_id,
1669 0xcf,
1670 );
1671 assert_eq!(
1672 decision,
1673 XpermsAccessDecision {
1674 allow: xperms_bitmap_from_elements((0x0..=0xf2).collect::<Vec<_>>().as_slice()),
1675 auditallow: XpermsBitmap::NONE,
1676 auditdeny: XpermsBitmap::ALL,
1677 }
1678 );
1679 let decision = policy.compute_xperms_access_decision(
1680 XpermsKind::Ioctl,
1681 &source_context,
1682 &target_context_matched,
1683 class_id,
1684 0xd0,
1685 );
1686 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1687 let decision = policy.compute_xperms_access_decision(
1688 XpermsKind::Ioctl,
1689 &source_context,
1690 &target_context_matched,
1691 class_id,
1692 0xe9,
1693 );
1694 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1695 let decision = policy.compute_xperms_access_decision(
1696 XpermsKind::Ioctl,
1697 &source_context,
1698 &target_context_matched,
1699 class_id,
1700 0xf0,
1701 );
1702 assert_eq!(
1703 decision,
1704 XpermsAccessDecision {
1705 allow: xperms_bitmap_from_elements(&[0x01]),
1706 auditallow: XpermsBitmap::NONE,
1707 auditdeny: XpermsBitmap::ALL,
1708 }
1709 );
1710 let decision = policy.compute_xperms_access_decision(
1711 XpermsKind::Ioctl,
1712 &source_context,
1713 &target_context_matched,
1714 class_id,
1715 0xf1,
1716 );
1717 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1718 let decision = policy.compute_xperms_access_decision(
1719 XpermsKind::Ioctl,
1720 &source_context,
1721 &target_context_matched,
1722 class_id,
1723 0xfc,
1724 );
1725 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1726 let decision = policy.compute_xperms_access_decision(
1727 XpermsKind::Ioctl,
1728 &source_context,
1729 &target_context_matched,
1730 class_id,
1731 0xfd,
1732 );
1733 assert_eq!(
1734 decision,
1735 XpermsAccessDecision {
1736 allow: xperms_bitmap_from_elements((0xfa..=0xfd).collect::<Vec<_>>().as_slice()),
1737 auditallow: XpermsBitmap::NONE,
1738 auditdeny: XpermsBitmap::ALL,
1739 }
1740 );
1741 let decision = policy.compute_xperms_access_decision(
1742 XpermsKind::Ioctl,
1743 &source_context,
1744 &target_context_matched,
1745 class_id,
1746 0xfe,
1747 );
1748 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1749 }
1750
1751 #[test]
1752 fn compute_nlmsg_access_decision_explicitly_allowed() {
1753 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1754 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1755 let policy = policy.validate().expect("validate policy");
1756
1757 let source_context: SecurityContext = policy
1758 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1759 .expect("create source security context");
1760 let target_context_matched: SecurityContext = source_context.clone();
1761
1762 let decision_single = policy.compute_xperms_access_decision(
1780 XpermsKind::Nlmsg,
1781 &source_context,
1782 &target_context_matched,
1783 KernelClass::NetlinkRouteSocket,
1784 0xab,
1785 );
1786
1787 let mut expected_auditdeny =
1788 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1789 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1790
1791 let expected_decision_single = XpermsAccessDecision {
1792 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1793 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1794 auditdeny: expected_auditdeny,
1795 };
1796 assert_eq!(decision_single, expected_decision_single);
1797
1798 let decision_range = policy.compute_xperms_access_decision(
1799 XpermsKind::Nlmsg,
1800 &source_context,
1801 &target_context_matched,
1802 KernelClass::NetlinkRouteSocket,
1803 0x10,
1804 );
1805 let expected_decision_range = XpermsAccessDecision {
1806 allow: XpermsBitmap::ALL,
1807 auditallow: XpermsBitmap::ALL,
1808 auditdeny: XpermsBitmap::NONE,
1809 };
1810 assert_eq!(decision_range, expected_decision_range);
1811 }
1812
1813 #[test]
1814 fn compute_nlmsg_access_decision_unmatched() {
1815 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1816 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1817 let policy = policy.validate().expect("validate policy");
1818
1819 let source_context: SecurityContext = policy
1820 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1821 .expect("create source security context");
1822
1823 let target_context_unmatched: SecurityContext = policy
1825 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1826 .expect("create source security context");
1827
1828 for prefix in 0x0..=0xff {
1829 let decision = policy.compute_xperms_access_decision(
1830 XpermsKind::Nlmsg,
1831 &source_context,
1832 &target_context_unmatched,
1833 KernelClass::NetlinkRouteSocket,
1834 prefix,
1835 );
1836 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1837 }
1838 }
1839
1840 #[test]
1841 fn compute_ioctl_grant_does_not_cause_nlmsg_deny() {
1842 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1843 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1844 let class_id = find_class_by_name(
1845 &unvalidated.0.classes(),
1846 "class_ioctl_grant_does_not_cause_nlmsg_deny",
1847 )
1848 .expect("look up class_ioctl_grant_does_not_cause_nlmsg_deny")
1849 .id();
1850 let policy = unvalidated.validate().expect("validate policy");
1851 let source_context: SecurityContext = policy
1852 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1853 .expect("create source security context");
1854 let target_context_matched: SecurityContext = source_context.clone();
1855
1856 let ioctl_decision = policy.compute_xperms_access_decision(
1860 XpermsKind::Ioctl,
1861 &source_context,
1862 &target_context_matched,
1863 class_id,
1864 0x00,
1865 );
1866 assert_eq!(
1867 ioctl_decision,
1868 XpermsAccessDecision {
1869 allow: xperms_bitmap_from_elements(&[0x0002]),
1870 auditallow: XpermsBitmap::NONE,
1871 auditdeny: XpermsBitmap::ALL,
1872 }
1873 );
1874 let nlmsg_decision = policy.compute_xperms_access_decision(
1875 XpermsKind::Nlmsg,
1876 &source_context,
1877 &target_context_matched,
1878 class_id,
1879 0x00,
1880 );
1881 assert_eq!(nlmsg_decision, XpermsAccessDecision::ALLOW_ALL);
1882 }
1883
1884 #[test]
1885 fn compute_nlmsg_grant_does_not_cause_ioctl_deny() {
1886 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1887 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1888 let class_id = find_class_by_name(
1889 &unvalidated.0.classes(),
1890 "class_nlmsg_grant_does_not_cause_ioctl_deny",
1891 )
1892 .expect("look up class_nlmsg_grant_does_not_cause_ioctl_deny")
1893 .id();
1894 let policy = unvalidated.validate().expect("validate policy");
1895 let source_context: SecurityContext = policy
1896 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1897 .expect("create source security context");
1898 let target_context_matched: SecurityContext = source_context.clone();
1899
1900 let nlmsg_decision = policy.compute_xperms_access_decision(
1904 XpermsKind::Nlmsg,
1905 &source_context,
1906 &target_context_matched,
1907 class_id,
1908 0x00,
1909 );
1910 assert_eq!(
1911 nlmsg_decision,
1912 XpermsAccessDecision {
1913 allow: xperms_bitmap_from_elements(&[0x0003]),
1914 auditallow: XpermsBitmap::NONE,
1915 auditdeny: XpermsBitmap::ALL,
1916 }
1917 );
1918 let ioctl_decision = policy.compute_xperms_access_decision(
1919 XpermsKind::Ioctl,
1920 &source_context,
1921 &target_context_matched,
1922 class_id,
1923 0x00,
1924 );
1925 assert_eq!(ioctl_decision, XpermsAccessDecision::ALLOW_ALL);
1926 }
1927
1928 #[test]
1929 fn compute_create_context_minimal() {
1930 let policy_bytes =
1931 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1932 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1933 let policy = policy.validate().expect("validate policy");
1934 let source = policy
1935 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1936 .expect("valid source security context");
1937 let target = policy
1938 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1939 .expect("valid target security context");
1940
1941 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1942 let expected: SecurityContext = policy
1943 .parse_security_context(b"source_u:object_r:target_t:s0:c0".into())
1944 .expect("valid expected security context");
1945
1946 assert_eq!(expected, actual);
1947 }
1948
1949 #[test]
1950 fn new_security_context_minimal() {
1951 let policy_bytes =
1952 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1953 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1954 let policy = policy.validate().expect("validate policy");
1955 let source = policy
1956 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1957 .expect("valid source security context");
1958 let target = policy
1959 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1960 .expect("valid target security context");
1961
1962 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1963
1964 assert_eq!(source, actual);
1965 }
1966
1967 #[test]
1968 fn compute_create_context_class_defaults() {
1969 let policy_bytes =
1970 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1971 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1972 let policy = policy.validate().expect("validate policy");
1973 let source = policy
1974 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1975 .expect("valid source security context");
1976 let target = policy
1977 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1978 .expect("valid target security context");
1979
1980 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1981 let expected: SecurityContext = policy
1982 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1983 .expect("valid expected security context");
1984
1985 assert_eq!(expected, actual);
1986 }
1987
1988 #[test]
1989 fn new_security_context_class_defaults() {
1990 let policy_bytes =
1991 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1992 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1993 let policy = policy.validate().expect("validate policy");
1994 let source = policy
1995 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1996 .expect("valid source security context");
1997 let target = policy
1998 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1999 .expect("valid target security context");
2000
2001 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2002 let expected: SecurityContext = policy
2003 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
2004 .expect("valid expected security context");
2005
2006 assert_eq!(expected, actual);
2007 }
2008
2009 #[test]
2010 fn compute_create_context_role_transition() {
2011 let policy_bytes =
2012 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
2013 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2014 let policy = policy.validate().expect("validate policy");
2015 let source = policy
2016 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2017 .expect("valid source security context");
2018 let target = policy
2019 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2020 .expect("valid target security context");
2021
2022 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2023 let expected: SecurityContext = policy
2024 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
2025 .expect("valid expected security context");
2026
2027 assert_eq!(expected, actual);
2028 }
2029
2030 #[test]
2031 fn new_security_context_role_transition() {
2032 let policy_bytes =
2033 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
2034 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2035 let policy = policy.validate().expect("validate policy");
2036 let source = policy
2037 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2038 .expect("valid source security context");
2039 let target = policy
2040 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2041 .expect("valid target security context");
2042
2043 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2044 let expected: SecurityContext = policy
2045 .parse_security_context(b"source_u:transition_r:source_t:s0:c0-s2:c0.c1".into())
2046 .expect("valid expected security context");
2047
2048 assert_eq!(expected, actual);
2049 }
2050
2051 #[test]
2052 #[ignore]
2054 fn compute_create_context_role_transition_not_allowed() {
2055 let policy_bytes = include_bytes!(
2056 "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy.pp"
2057 );
2058 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2059 let policy = policy.validate().expect("validate policy");
2060 let source = policy
2061 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2062 .expect("valid source security context");
2063 let target = policy
2064 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2065 .expect("valid target security context");
2066
2067 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2068
2069 assert!(policy.validate_security_context(&actual).is_err());
2071 }
2072
2073 #[test]
2074 fn compute_create_context_type_transition() {
2075 let policy_bytes =
2076 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
2077 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2078 let policy = policy.validate().expect("validate policy");
2079 let source = policy
2080 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2081 .expect("valid source security context");
2082 let target = policy
2083 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2084 .expect("valid target security context");
2085
2086 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2087 let expected: SecurityContext = policy
2088 .parse_security_context(b"source_u:object_r:transition_t:s0:c0".into())
2089 .expect("valid expected security context");
2090
2091 assert_eq!(expected, actual);
2092 }
2093
2094 #[test]
2095 fn new_security_context_type_transition() {
2096 let policy_bytes =
2097 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
2098 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2099 let policy = policy.validate().expect("validate policy");
2100 let source = policy
2101 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2102 .expect("valid source security context");
2103 let target = policy
2104 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2105 .expect("valid target security context");
2106
2107 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2108 let expected: SecurityContext = policy
2109 .parse_security_context(b"source_u:source_r:transition_t:s0:c0-s2:c0.c1".into())
2110 .expect("valid expected security context");
2111
2112 assert_eq!(expected, actual);
2113 }
2114
2115 #[test]
2116 fn compute_create_context_range_transition() {
2117 let policy_bytes =
2118 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
2119 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2120 let policy = policy.validate().expect("validate policy");
2121 let source = policy
2122 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2123 .expect("valid source security context");
2124 let target = policy
2125 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2126 .expect("valid target security context");
2127
2128 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2129 let expected: SecurityContext = policy
2130 .parse_security_context(b"source_u:object_r:target_t:s1:c1-s2:c1.c2".into())
2131 .expect("valid expected security context");
2132
2133 assert_eq!(expected, actual);
2134 }
2135
2136 #[test]
2137 fn new_security_context_range_transition() {
2138 let policy_bytes =
2139 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
2140 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2141 let policy = policy.validate().expect("validate policy");
2142 let source = policy
2143 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2144 .expect("valid source security context");
2145 let target = policy
2146 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2147 .expect("valid target security context");
2148
2149 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2150 let expected: SecurityContext = policy
2151 .parse_security_context(b"source_u:source_r:source_t:s1:c1-s2:c1.c2".into())
2152 .expect("valid expected security context");
2153
2154 assert_eq!(expected, actual);
2155 }
2156
2157 #[test]
2158 fn access_vector_formats() {
2159 assert_eq!(format!("{:x}", AccessVector::NONE), "0");
2160 assert_eq!(format!("{:x}", AccessVector::ALL), "ffffffff");
2161 assert_eq!(format!("{:?}", AccessVector::NONE), "AccessVector(00000000)");
2162 assert_eq!(format!("{:?}", AccessVector::ALL), "AccessVector(ffffffff)");
2163 }
2164
2165 #[test]
2166 fn policy_genfscon_root_path() {
2167 let policy_bytes =
2168 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy.pp");
2169 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2170 let policy = policy.validate().expect("validate selinux policy");
2171
2172 {
2173 let context = policy.genfscon_label_for_fs_and_path(
2174 "fs_with_path_rules".into(),
2175 "/".into(),
2176 None,
2177 );
2178 assert_eq!(
2179 policy.serialize_security_context(&context.unwrap()),
2180 b"system_u:object_r:fs_with_path_rules_t:s0"
2181 )
2182 }
2183 {
2184 let context = policy.genfscon_label_for_fs_and_path(
2185 "fs_2_with_path_rules".into(),
2186 "/".into(),
2187 None,
2188 );
2189 assert_eq!(
2190 policy.serialize_security_context(&context.unwrap()),
2191 b"system_u:object_r:fs_2_with_path_rules_t:s0"
2192 )
2193 }
2194 }
2195
2196 #[test]
2197 fn policy_genfscon_subpaths() {
2198 let policy_bytes =
2199 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy.pp");
2200 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2201 let policy = policy.validate().expect("validate selinux policy");
2202
2203 let path_label_expectations = [
2204 ("/a1/", "system_u:object_r:fs_with_path_rules_a1_t:s0"),
2208 ("/a1/b", "system_u:object_r:fs_with_path_rules_a1_t:s0"),
2209 ("/a1/b/c", "system_u:object_r:fs_with_path_rules_a1_b_c_t:s0"),
2210 ("/a2/", "system_u:object_r:fs_with_path_rules_t:s0"),
2213 ("/a2/b/c/d", "system_u:object_r:fs_with_path_rules_a2_b_t:s0"),
2214 ("/a3/b/c/d", "system_u:object_r:fs_with_path_rules_a3_t:s0"),
2217 ];
2218 for (path, expected_label) in path_label_expectations {
2219 let context = policy.genfscon_label_for_fs_and_path(
2220 "fs_with_path_rules".into(),
2221 path.into(),
2222 None,
2223 );
2224 assert_eq!(
2225 policy.serialize_security_context(&context.unwrap()),
2226 expected_label.as_bytes()
2227 )
2228 }
2229 }
2230
2231 #[test]
2232 fn policy_genfscon_mixed_order() {
2233 let policy_bytes =
2234 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy.pp");
2235 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2236 let policy = policy.validate().expect("validate selinux policy");
2237
2238 let path_label_expectations = [
2239 ("/", "system_u:object_r:fs_mixed_order_t:s0"),
2240 ("/a", "system_u:object_r:fs_mixed_order_a_t:s0"),
2241 ("/a/a", "system_u:object_r:fs_mixed_order_a_a_t:s0"),
2242 ("/a/b", "system_u:object_r:fs_mixed_order_a_b_t:s0"),
2243 ("/a/b/c", "system_u:object_r:fs_mixed_order_a_b_t:s0"),
2244 ];
2245 for (path, expected_label) in path_label_expectations {
2246 let context =
2247 policy.genfscon_label_for_fs_and_path("fs_mixed_order".into(), path.into(), None);
2248 assert_eq!(
2249 policy.serialize_security_context(&context.unwrap()),
2250 expected_label.as_bytes()
2251 );
2252 }
2253 }
2254}