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 pub(super) data: PolicyData,
613
614 pub(super) need_init_sid: bool,
616}
617
618pub(super) trait Validate {
620 type Error: Into<anyhow::Error>;
623
624 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error>;
626}
627
628pub(super) trait ValidateArray<M, D> {
629 type Error: Into<anyhow::Error>;
632
633 fn validate_array(
635 context: &PolicyValidationContext,
636 metadata: &M,
637 items: &[D],
638 ) -> Result<(), Self::Error>;
639}
640
641pub(super) trait Counted {
643 fn count(&self) -> u32;
645}
646
647impl<T: Validate> Validate for Option<T> {
648 type Error = <T as Validate>::Error;
649
650 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
651 match self {
652 Some(value) => value.validate(context),
653 None => Ok(()),
654 }
655 }
656}
657
658impl<T: Validate> Validate for Vec<T> {
659 type Error = <T as Validate>::Error;
660
661 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
662 for item in self {
663 item.validate(context)?;
664 }
665 Ok(())
666 }
667}
668
669impl Validate for le::U32 {
670 type Error = anyhow::Error;
671
672 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
675 Ok(())
676 }
677}
678
679impl Validate for u8 {
680 type Error = anyhow::Error;
681
682 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
685 Ok(())
686 }
687}
688
689impl<B: SplitByteSlice, T: Validate + FromBytes + KnownLayout + Immutable> Validate for Ref<B, T> {
690 type Error = <T as Validate>::Error;
691
692 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
693 self.deref().validate(context)
694 }
695}
696
697impl<B: SplitByteSlice, T: Counted + FromBytes + KnownLayout + Immutable> Counted for Ref<B, T> {
698 fn count(&self) -> u32 {
699 self.deref().count()
700 }
701}
702
703#[derive(Clone, Debug, PartialEq)]
705struct Array<M, T> {
706 metadata: M,
707 data: Vec<T>,
708}
709
710impl<M: Counted + Parse, T: Parse> Parse for Array<M, T> {
711 type Error = anyhow::Error;
714
715 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
717 let tail = bytes;
718
719 let (metadata, tail) = M::parse(tail).map_err(Into::<anyhow::Error>::into)?;
720
721 let count = metadata.count() as usize;
722 let mut data = Vec::with_capacity(count);
723 let mut cur_tail = tail;
724 for _ in 0..count {
725 let (item, next_tail) = T::parse(cur_tail).map_err(Into::<anyhow::Error>::into)?;
726 data.push(item);
727 cur_tail = next_tail;
728 }
729 let tail = cur_tail;
730
731 let array = Self { metadata, data };
732
733 Ok((array, tail))
734 }
735}
736
737impl<T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned> Parse for T {
738 type Error = anyhow::Error;
739
740 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
741 bytes.parse::<T>().map_err(anyhow::Error::from)
742 }
743}
744
745macro_rules! array_type {
749 ($type_name:ident, $metadata_type:ty, $data_type:ty, $metadata_type_name:expr, $data_type_name:expr) => {
750 #[doc = "An [`Array`] with [`"]
751 #[doc = $metadata_type_name]
752 #[doc = "`] metadata and [`"]
753 #[doc = $data_type_name]
754 #[doc = "`] data items."]
755 #[derive(Debug, PartialEq)]
756 pub(super) struct $type_name(super::Array<$metadata_type, $data_type>);
757
758 impl std::ops::Deref for $type_name {
759 type Target = super::Array<$metadata_type, $data_type>;
760
761 fn deref(&self) -> &Self::Target {
762 &self.0
763 }
764 }
765
766 impl super::Parse for $type_name
767 where
768 super::Array<$metadata_type, $data_type>: super::Parse,
769 {
770 type Error = <Array<$metadata_type, $data_type> as super::Parse>::Error;
771
772 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
773 let (array, tail) = Array::<$metadata_type, $data_type>::parse(bytes)?;
774 Ok((Self(array), tail))
775 }
776 }
777 };
778
779 ($type_name:ident, $metadata_type:ty, $data_type:ty) => {
780 array_type!(
781 $type_name,
782 $metadata_type,
783 $data_type,
784 stringify!($metadata_type),
785 stringify!($data_type)
786 );
787 };
788}
789
790pub(super) use array_type;
791
792macro_rules! array_type_validate_deref_both {
793 ($type_name:ident) => {
794 impl Validate for $type_name {
795 type Error = anyhow::Error;
796
797 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
798 let metadata = &self.metadata;
799 metadata.validate(context)?;
800
801 self.data.validate(context).map_err(Into::<anyhow::Error>::into)?;
802
803 Self::validate_array(context, metadata, &self.data)
804 .map_err(Into::<anyhow::Error>::into)
805 }
806 }
807 };
808}
809
810pub(super) use array_type_validate_deref_both;
811
812macro_rules! array_type_validate_deref_data {
813 ($type_name:ident) => {
814 impl Validate for $type_name {
815 type Error = anyhow::Error;
816
817 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
818 let metadata = &self.metadata;
819 metadata.validate(context)?;
820
821 self.data.validate(context).map_err(Into::<anyhow::Error>::into)?;
822
823 Self::validate_array(context, metadata, &self.data)
824 }
825 }
826 };
827}
828
829pub(super) use array_type_validate_deref_data;
830
831macro_rules! array_type_validate_deref_metadata_data_vec {
832 ($type_name:ident) => {
833 impl Validate for $type_name {
834 type Error = anyhow::Error;
835
836 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
837 let metadata = &self.metadata;
838 metadata.validate(context)?;
839
840 self.data.validate(context).map_err(Into::<anyhow::Error>::into)?;
841
842 Self::validate_array(context, metadata, self.data.as_slice())
843 }
844 }
845 };
846}
847
848pub(super) use array_type_validate_deref_metadata_data_vec;
849
850macro_rules! array_type_validate_deref_none_data_vec {
851 ($type_name:ident) => {
852 impl Validate for $type_name {
853 type Error = anyhow::Error;
854
855 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
856 let metadata = &self.metadata;
857 metadata.validate(context)?;
858
859 self.data.validate(context).map_err(Into::<anyhow::Error>::into)?;
860
861 Self::validate_array(context, metadata, self.data.as_slice())
862 }
863 }
864 };
865}
866
867pub(super) use array_type_validate_deref_none_data_vec;
868
869#[cfg(test)]
870pub(super) mod testing {
871 use super::error::{ParseError, ValidateError};
872
873 pub(super) fn as_parse_error(error: anyhow::Error) -> ParseError {
875 error.downcast::<ParseError>().expect("parse error")
876 }
877
878 pub(super) fn as_validate_error(error: anyhow::Error) -> ValidateError {
880 error.downcast::<ValidateError>().expect("validate error")
881 }
882}
883
884#[cfg(test)]
885pub(super) mod tests {
886 use super::arrays::XpermsBitmap;
887 use super::metadata::HandleUnknown;
888 use super::security_context::SecurityContext;
889 use super::symbols::find_class_by_name;
890 use super::{
891 AccessVector, Policy, TypeId, XpermsAccessDecision, XpermsKind, parse_policy_by_value,
892 };
893 use crate::{FileClass, InitialSid, KernelClass};
894
895 use anyhow::Context as _;
896 use serde::Deserialize;
897 use std::ops::{Deref, Shl};
898 use zerocopy::little_endian as le;
899
900 fn is_explicitly_allowed(
908 policy: &Policy,
909 source_type: TypeId,
910 target_type: TypeId,
911 target_class: &str,
912 permission: &str,
913 ) -> bool {
914 let classes = policy.0.parsed_policy().classes();
915 let class = classes
916 .iter()
917 .find(|class| class.name_bytes() == target_class.as_bytes())
918 .expect("class not found");
919 let class_permissions = policy
920 .find_class_permissions_by_name(target_class)
921 .expect("class permissions not found");
922 let (permission_id, _) = class_permissions
923 .iter()
924 .find(|(_, name)| permission.as_bytes() == name)
925 .expect("permission not found");
926 let permission_bit = AccessVector::from_class_permission_id(*permission_id);
927 let access_decision =
928 policy.0.parsed_policy().compute_explicitly_allowed(source_type, target_type, class);
929 permission_bit == access_decision.allow & permission_bit
930 }
931
932 #[derive(Debug, Deserialize)]
933 struct Expectations {
934 expected_policy_version: u32,
935 expected_handle_unknown: LocalHandleUnknown,
936 }
937
938 #[derive(Debug, Deserialize, PartialEq)]
939 #[serde(rename_all = "snake_case")]
940 enum LocalHandleUnknown {
941 Deny,
942 Reject,
943 Allow,
944 }
945
946 impl PartialEq<HandleUnknown> for LocalHandleUnknown {
947 fn eq(&self, other: &HandleUnknown) -> bool {
948 match self {
949 LocalHandleUnknown::Deny => *other == HandleUnknown::Deny,
950 LocalHandleUnknown::Reject => *other == HandleUnknown::Reject,
951 LocalHandleUnknown::Allow => *other == HandleUnknown::Allow,
952 }
953 }
954 }
955
956 fn xperms_bitmap_from_elements(elements: &[u8]) -> XpermsBitmap {
959 let mut bitmap = [le::U32::ZERO; 8];
960 for element in elements {
961 let block_index = (*element as usize) / 32;
962 let bit_index = ((*element as usize) % 32) as u32;
963 let bitmask = le::U32::new(1).shl(bit_index);
964 bitmap[block_index] = bitmap[block_index] | bitmask;
965 }
966 XpermsBitmap::new(bitmap)
967 }
968
969 #[test]
970 fn known_policies() {
971 let policies_and_expectations = [
972 [
973 b"testdata/policies/emulator".to_vec(),
974 include_bytes!("../../testdata/policies/emulator").to_vec(),
975 include_bytes!("../../testdata/expectations/emulator").to_vec(),
976 ],
977 [
978 b"testdata/policies/selinux_testsuite".to_vec(),
979 include_bytes!("../../testdata/policies/selinux_testsuite").to_vec(),
980 include_bytes!("../../testdata/expectations/selinux_testsuite").to_vec(),
981 ],
982 ];
983
984 for [policy_path, policy_bytes, expectations_bytes] in policies_and_expectations {
985 let expectations = serde_json5::from_reader::<_, Expectations>(
986 &mut std::io::Cursor::new(expectations_bytes),
987 )
988 .expect("deserialize expectations");
989
990 let unvalidated_policy =
993 parse_policy_by_value(policy_bytes.clone()).expect("parse policy");
994
995 let policy = unvalidated_policy
996 .validate()
997 .with_context(|| {
998 format!(
999 "policy path: {:?}",
1000 std::str::from_utf8(policy_path.as_slice()).unwrap()
1001 )
1002 })
1003 .expect("validate policy");
1004
1005 assert_eq!(expectations.expected_policy_version, policy.policy_version());
1006 assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
1007
1008 let binary_policy = policy.binary().clone();
1010 assert_eq!(&policy_bytes, binary_policy.deref());
1011 }
1012 }
1013
1014 #[test]
1015 fn policy_lookup() {
1016 let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
1017 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1018 let policy = policy.validate().expect("validate selinux testsuite policy");
1019
1020 let unconfined_t = policy.type_id_by_name("unconfined_t").expect("look up type id");
1021
1022 assert!(is_explicitly_allowed(&policy, unconfined_t, unconfined_t, "process", "fork",));
1023 }
1024
1025 #[test]
1026 fn initial_contexts() {
1027 let policy_bytes =
1028 include_bytes!("../../testdata/micro_policies/multiple_levels_and_categories_policy");
1029 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1030 let policy = policy.validate().expect("validate policy");
1031
1032 let kernel_context = policy.initial_context(InitialSid::Kernel);
1033 assert_eq!(
1034 policy.serialize_security_context(&kernel_context),
1035 b"user0:object_r:type0:s0:c0-s1:c0.c2,c4"
1036 )
1037 }
1038
1039 #[test]
1040 fn explicit_allow_type_type() {
1041 let policy_bytes =
1042 include_bytes!("../../testdata/micro_policies/allow_a_t_b_t_class0_perm0_policy");
1043 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1044 let policy = policy.validate().expect("validate policy");
1045
1046 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1047 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1048
1049 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1050 }
1051
1052 #[test]
1053 fn no_explicit_allow_type_type() {
1054 let policy_bytes =
1055 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_t_class0_perm0_policy");
1056 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1057 let policy = policy.validate().expect("validate policy");
1058
1059 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1060 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1061
1062 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1063 }
1064
1065 #[test]
1066 fn explicit_allow_type_attr() {
1067 let policy_bytes =
1068 include_bytes!("../../testdata/micro_policies/allow_a_t_b_attr_class0_perm0_policy");
1069 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1070 let policy = policy.validate().expect("validate policy");
1071
1072 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1073 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1074
1075 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1076 }
1077
1078 #[test]
1079 fn no_explicit_allow_type_attr() {
1080 let policy_bytes =
1081 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_attr_class0_perm0_policy");
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 =
1094 include_bytes!("../../testdata/micro_policies/allow_a_attr_b_attr_class0_perm0_policy");
1095 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1096 let policy = policy.validate().expect("validate policy");
1097
1098 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1099 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1100
1101 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1102 }
1103
1104 #[test]
1105 fn no_explicit_allow_attr_attr() {
1106 let policy_bytes = include_bytes!(
1107 "../../testdata/micro_policies/no_allow_a_attr_b_attr_class0_perm0_policy"
1108 );
1109 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1110 let policy = policy.validate().expect("validate policy");
1111
1112 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1113 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1114
1115 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1116 }
1117
1118 #[test]
1119 fn compute_explicitly_allowed_multiple_attributes() {
1120 let policy_bytes = include_bytes!(
1121 "../../testdata/micro_policies/allow_a_t_a1_attr_class0_perm0_a2_attr_class0_perm1_policy"
1122 );
1123 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1124 let policy = policy.validate().expect("validate policy");
1125
1126 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1127
1128 let classes = policy.0.parsed_policy().classes();
1129 let class =
1130 classes.iter().find(|class| class.name_bytes() == b"class0").expect("class not found");
1131 let raw_access_vector =
1132 policy.0.parsed_policy().compute_explicitly_allowed(a_t, a_t, class).allow.0;
1133
1134 assert_eq!(2, raw_access_vector.count_ones());
1139 }
1140
1141 #[test]
1142 fn compute_access_decision_with_constraints() {
1143 let policy_bytes =
1144 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy");
1145 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1146 let policy = policy.validate().expect("validate policy");
1147
1148 let source_context: SecurityContext = policy
1149 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1150 .expect("create source security context");
1151
1152 let target_context_satisfied: SecurityContext = source_context.clone();
1153 let decision_satisfied = policy.compute_access_decision(
1154 &source_context,
1155 &target_context_satisfied,
1156 KernelClass::File,
1157 );
1158 assert_eq!(decision_satisfied.allow, AccessVector(7));
1162
1163 let target_context_unsatisfied: SecurityContext = policy
1164 .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1165 .expect("create target security context failing some constraints");
1166 let decision_unsatisfied = policy.compute_access_decision(
1167 &source_context,
1168 &target_context_unsatisfied,
1169 KernelClass::File,
1170 );
1171 assert_eq!(decision_unsatisfied.allow, AccessVector(4));
1174 }
1175
1176 #[test]
1177 fn compute_ioctl_access_decision_explicitly_allowed() {
1178 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1179 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1180 let policy = policy.validate().expect("validate policy");
1181
1182 let source_context: SecurityContext = policy
1183 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1184 .expect("create source security context");
1185 let target_context_matched: SecurityContext = source_context.clone();
1186
1187 let decision_single = policy.compute_xperms_access_decision(
1205 XpermsKind::Ioctl,
1206 &source_context,
1207 &target_context_matched,
1208 KernelClass::File,
1209 0xab,
1210 );
1211
1212 let mut expected_auditdeny =
1213 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1214 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1215
1216 let expected_decision_single = XpermsAccessDecision {
1217 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1218 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1219 auditdeny: expected_auditdeny,
1220 };
1221 assert_eq!(decision_single, expected_decision_single);
1222
1223 let decision_range = policy.compute_xperms_access_decision(
1224 XpermsKind::Ioctl,
1225 &source_context,
1226 &target_context_matched,
1227 KernelClass::File,
1228 0x10,
1229 );
1230 let expected_decision_range = XpermsAccessDecision {
1231 allow: XpermsBitmap::ALL,
1232 auditallow: XpermsBitmap::ALL,
1233 auditdeny: XpermsBitmap::NONE,
1234 };
1235 assert_eq!(decision_range, expected_decision_range);
1236 }
1237
1238 #[test]
1239 fn compute_ioctl_access_decision_denied() {
1240 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1241 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1242 let class_id = find_class_by_name(&unvalidated.0.classes(), "class_one_ioctl")
1243 .expect("look up class_one_ioctl")
1244 .id();
1245 let policy = unvalidated.validate().expect("validate policy");
1246 let source_context: SecurityContext = policy
1247 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1248 .expect("create source security context");
1249 let target_context_matched: SecurityContext = source_context.clone();
1250
1251 let decision_single = policy.compute_xperms_access_decision(
1255 XpermsKind::Ioctl,
1256 &source_context,
1257 &target_context_matched,
1258 class_id,
1259 0xdb,
1260 );
1261
1262 let expected_decision = XpermsAccessDecision {
1263 allow: XpermsBitmap::NONE,
1264 auditallow: XpermsBitmap::NONE,
1265 auditdeny: XpermsBitmap::ALL,
1266 };
1267 assert_eq!(decision_single, expected_decision);
1268 }
1269
1270 #[test]
1271 fn compute_ioctl_access_decision_unmatched() {
1272 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1273 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1274 let policy = policy.validate().expect("validate policy");
1275
1276 let source_context: SecurityContext = policy
1277 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1278 .expect("create source security context");
1279
1280 let target_context_unmatched: SecurityContext = policy
1282 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1283 .expect("create source security context");
1284
1285 for prefix in 0x0..=0xff {
1286 let decision = policy.compute_xperms_access_decision(
1287 XpermsKind::Ioctl,
1288 &source_context,
1289 &target_context_unmatched,
1290 KernelClass::File,
1291 prefix,
1292 );
1293 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1294 }
1295 }
1296
1297 #[test]
1298 fn compute_ioctl_earlier_redundant_prefixful_not_coalesced_into_prefixless() {
1299 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1300 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1301 let class_id = find_class_by_name(
1302 &unvalidated.0.classes(),
1303 "class_earlier_redundant_prefixful_not_coalesced_into_prefixless",
1304 )
1305 .expect("look up class_earlier_redundant_prefixful_not_coalesced_into_prefixless")
1306 .id();
1307 let policy = unvalidated.validate().expect("validate policy");
1308 let source_context: SecurityContext = policy
1309 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1310 .expect("create source security context");
1311 let target_context_matched: SecurityContext = source_context.clone();
1312
1313 let decision = policy.compute_xperms_access_decision(
1318 XpermsKind::Ioctl,
1319 &source_context,
1320 &target_context_matched,
1321 class_id,
1322 0x7f,
1323 );
1324 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1325 let decision = policy.compute_xperms_access_decision(
1326 XpermsKind::Ioctl,
1327 &source_context,
1328 &target_context_matched,
1329 class_id,
1330 0x80,
1331 );
1332 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1333 let decision = policy.compute_xperms_access_decision(
1334 XpermsKind::Ioctl,
1335 &source_context,
1336 &target_context_matched,
1337 class_id,
1338 0x81,
1339 );
1340 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1341 }
1342
1343 #[test]
1344 fn compute_ioctl_later_redundant_prefixful_not_coalesced_into_prefixless() {
1345 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1346 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1347 let class_id = find_class_by_name(
1348 &unvalidated.0.classes(),
1349 "class_later_redundant_prefixful_not_coalesced_into_prefixless",
1350 )
1351 .expect("look up class_later_redundant_prefixful_not_coalesced_into_prefixless")
1352 .id();
1353 let policy = unvalidated.validate().expect("validate policy");
1354 let source_context: SecurityContext = policy
1355 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1356 .expect("create source security context");
1357 let target_context_matched: SecurityContext = source_context.clone();
1358
1359 let decision = policy.compute_xperms_access_decision(
1364 XpermsKind::Ioctl,
1365 &source_context,
1366 &target_context_matched,
1367 class_id,
1368 0x8f,
1369 );
1370 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1371 let decision = policy.compute_xperms_access_decision(
1372 XpermsKind::Ioctl,
1373 &source_context,
1374 &target_context_matched,
1375 class_id,
1376 0x90,
1377 );
1378 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1379 let decision = policy.compute_xperms_access_decision(
1380 XpermsKind::Ioctl,
1381 &source_context,
1382 &target_context_matched,
1383 class_id,
1384 0x91,
1385 );
1386 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1387 }
1388
1389 #[test]
1390 fn compute_ioctl_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless() {
1391 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1392 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1393 let class_id = find_class_by_name(
1394 &unvalidated.0.classes(),
1395 "class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless",
1396 )
1397 .expect("look up class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless")
1398 .id();
1399 let policy = unvalidated.validate().expect("validate policy");
1400 let source_context: SecurityContext = policy
1401 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1402 .expect("create source security context");
1403 let target_context_matched: SecurityContext = source_context.clone();
1404
1405 let decision = policy.compute_xperms_access_decision(
1411 XpermsKind::Ioctl,
1412 &source_context,
1413 &target_context_matched,
1414 class_id,
1415 0x9f,
1416 );
1417 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1418 let decision = policy.compute_xperms_access_decision(
1419 XpermsKind::Ioctl,
1420 &source_context,
1421 &target_context_matched,
1422 class_id,
1423 0xa0,
1424 );
1425 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1426 let decision = policy.compute_xperms_access_decision(
1427 XpermsKind::Ioctl,
1428 &source_context,
1429 &target_context_matched,
1430 class_id,
1431 0xa1,
1432 );
1433 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1434 }
1435
1436 #[test]
1437 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless() {
1438 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1439 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1440 let class_id = find_class_by_name(
1441 &unvalidated.0.classes(),
1442 "class_prefixfuls_that_coalesce_to_prefixless",
1443 )
1444 .expect("look up class_prefixfuls_that_coalesce_to_prefixless")
1445 .id();
1446 let policy = unvalidated.validate().expect("validate policy");
1447 let source_context: SecurityContext = policy
1448 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1449 .expect("create source security context");
1450 let target_context_matched: SecurityContext = source_context.clone();
1451
1452 let decision = policy.compute_xperms_access_decision(
1458 XpermsKind::Ioctl,
1459 &source_context,
1460 &target_context_matched,
1461 class_id,
1462 0xaf,
1463 );
1464 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1465 let decision = policy.compute_xperms_access_decision(
1466 XpermsKind::Ioctl,
1467 &source_context,
1468 &target_context_matched,
1469 class_id,
1470 0xb0,
1471 );
1472 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1473 let decision = policy.compute_xperms_access_decision(
1474 XpermsKind::Ioctl,
1475 &source_context,
1476 &target_context_matched,
1477 class_id,
1478 0xb1,
1479 );
1480 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1481 }
1482
1483 #[test]
1484 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless() {
1485 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1486 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1487 let class_id = find_class_by_name(
1488 &unvalidated.0.classes(),
1489 "class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless",
1490 )
1491 .expect("look up class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless")
1492 .id();
1493 let policy = unvalidated.validate().expect("validate policy");
1494 let source_context: SecurityContext = policy
1495 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1496 .expect("create source security context");
1497 let target_context_matched: SecurityContext = source_context.clone();
1498
1499 let decision = policy.compute_xperms_access_decision(
1506 XpermsKind::Ioctl,
1507 &source_context,
1508 &target_context_matched,
1509 class_id,
1510 0xbf,
1511 );
1512 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1513 let decision = policy.compute_xperms_access_decision(
1514 XpermsKind::Ioctl,
1515 &source_context,
1516 &target_context_matched,
1517 class_id,
1518 0xc0,
1519 );
1520 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1521 let decision = policy.compute_xperms_access_decision(
1522 XpermsKind::Ioctl,
1523 &source_context,
1524 &target_context_matched,
1525 class_id,
1526 0xc1,
1527 );
1528 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1529 let decision = policy.compute_xperms_access_decision(
1530 XpermsKind::Ioctl,
1531 &source_context,
1532 &target_context_matched,
1533 class_id,
1534 0xc2,
1535 );
1536 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1537 }
1538
1539 #[test]
1540 fn compute_ioctl_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless() {
1541 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1542 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1543 let class_id = find_class_by_name(
1544 &unvalidated.0.classes(),
1545 "class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless",
1546 )
1547 .expect("look up class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless")
1548 .id();
1549 let policy = unvalidated.validate().expect("validate policy");
1550 let source_context: SecurityContext = policy
1551 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1552 .expect("create source security context");
1553 let target_context_matched: SecurityContext = source_context.clone();
1554
1555 let decision = policy.compute_xperms_access_decision(
1562 XpermsKind::Ioctl,
1563 &source_context,
1564 &target_context_matched,
1565 class_id,
1566 0xd5,
1567 );
1568 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1569 let decision = policy.compute_xperms_access_decision(
1570 XpermsKind::Ioctl,
1571 &source_context,
1572 &target_context_matched,
1573 class_id,
1574 0xd6,
1575 );
1576 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1577 let decision = policy.compute_xperms_access_decision(
1578 XpermsKind::Ioctl,
1579 &source_context,
1580 &target_context_matched,
1581 class_id,
1582 0xd7,
1583 );
1584 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1585 let decision = policy.compute_xperms_access_decision(
1586 XpermsKind::Ioctl,
1587 &source_context,
1588 &target_context_matched,
1589 class_id,
1590 0xd8,
1591 );
1592 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1593 }
1594
1595 #[test]
1606 fn compute_ioctl_ridiculous_permission_ordering() {
1607 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1608 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1609 let class_id =
1610 find_class_by_name(&unvalidated.0.classes(), "class_ridiculous_permission_ordering")
1611 .expect("look up class_ridiculous_permission_ordering")
1612 .id();
1613 let policy = unvalidated.validate().expect("validate policy");
1614 let source_context: SecurityContext = policy
1615 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1616 .expect("create source security context");
1617 let target_context_matched: SecurityContext = source_context.clone();
1618
1619 let decision = policy.compute_xperms_access_decision(
1624 XpermsKind::Ioctl,
1625 &source_context,
1626 &target_context_matched,
1627 class_id,
1628 0x00,
1629 );
1630 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1631 let decision = policy.compute_xperms_access_decision(
1632 XpermsKind::Ioctl,
1633 &source_context,
1634 &target_context_matched,
1635 class_id,
1636 0x01,
1637 );
1638 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1639 let decision = policy.compute_xperms_access_decision(
1640 XpermsKind::Ioctl,
1641 &source_context,
1642 &target_context_matched,
1643 class_id,
1644 0xbf,
1645 );
1646 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1647 let decision = policy.compute_xperms_access_decision(
1648 XpermsKind::Ioctl,
1649 &source_context,
1650 &target_context_matched,
1651 class_id,
1652 0xc0,
1653 );
1654 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1655 let decision = policy.compute_xperms_access_decision(
1656 XpermsKind::Ioctl,
1657 &source_context,
1658 &target_context_matched,
1659 class_id,
1660 0xce,
1661 );
1662 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1663 let decision = policy.compute_xperms_access_decision(
1664 XpermsKind::Ioctl,
1665 &source_context,
1666 &target_context_matched,
1667 class_id,
1668 0xcf,
1669 );
1670 assert_eq!(
1671 decision,
1672 XpermsAccessDecision {
1673 allow: xperms_bitmap_from_elements((0x0..=0xf2).collect::<Vec<_>>().as_slice()),
1674 auditallow: XpermsBitmap::NONE,
1675 auditdeny: XpermsBitmap::ALL,
1676 }
1677 );
1678 let decision = policy.compute_xperms_access_decision(
1679 XpermsKind::Ioctl,
1680 &source_context,
1681 &target_context_matched,
1682 class_id,
1683 0xd0,
1684 );
1685 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1686 let decision = policy.compute_xperms_access_decision(
1687 XpermsKind::Ioctl,
1688 &source_context,
1689 &target_context_matched,
1690 class_id,
1691 0xe9,
1692 );
1693 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1694 let decision = policy.compute_xperms_access_decision(
1695 XpermsKind::Ioctl,
1696 &source_context,
1697 &target_context_matched,
1698 class_id,
1699 0xf0,
1700 );
1701 assert_eq!(
1702 decision,
1703 XpermsAccessDecision {
1704 allow: xperms_bitmap_from_elements(&[0x01]),
1705 auditallow: XpermsBitmap::NONE,
1706 auditdeny: XpermsBitmap::ALL,
1707 }
1708 );
1709 let decision = policy.compute_xperms_access_decision(
1710 XpermsKind::Ioctl,
1711 &source_context,
1712 &target_context_matched,
1713 class_id,
1714 0xf1,
1715 );
1716 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1717 let decision = policy.compute_xperms_access_decision(
1718 XpermsKind::Ioctl,
1719 &source_context,
1720 &target_context_matched,
1721 class_id,
1722 0xfc,
1723 );
1724 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1725 let decision = policy.compute_xperms_access_decision(
1726 XpermsKind::Ioctl,
1727 &source_context,
1728 &target_context_matched,
1729 class_id,
1730 0xfd,
1731 );
1732 assert_eq!(
1733 decision,
1734 XpermsAccessDecision {
1735 allow: xperms_bitmap_from_elements((0xfa..=0xfd).collect::<Vec<_>>().as_slice()),
1736 auditallow: XpermsBitmap::NONE,
1737 auditdeny: XpermsBitmap::ALL,
1738 }
1739 );
1740 let decision = policy.compute_xperms_access_decision(
1741 XpermsKind::Ioctl,
1742 &source_context,
1743 &target_context_matched,
1744 class_id,
1745 0xfe,
1746 );
1747 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1748 }
1749
1750 #[test]
1751 fn compute_nlmsg_access_decision_explicitly_allowed() {
1752 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1753 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1754 let policy = policy.validate().expect("validate policy");
1755
1756 let source_context: SecurityContext = policy
1757 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1758 .expect("create source security context");
1759 let target_context_matched: SecurityContext = source_context.clone();
1760
1761 let decision_single = policy.compute_xperms_access_decision(
1779 XpermsKind::Nlmsg,
1780 &source_context,
1781 &target_context_matched,
1782 KernelClass::NetlinkRouteSocket,
1783 0xab,
1784 );
1785
1786 let mut expected_auditdeny =
1787 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1788 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1789
1790 let expected_decision_single = XpermsAccessDecision {
1791 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1792 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1793 auditdeny: expected_auditdeny,
1794 };
1795 assert_eq!(decision_single, expected_decision_single);
1796
1797 let decision_range = policy.compute_xperms_access_decision(
1798 XpermsKind::Nlmsg,
1799 &source_context,
1800 &target_context_matched,
1801 KernelClass::NetlinkRouteSocket,
1802 0x10,
1803 );
1804 let expected_decision_range = XpermsAccessDecision {
1805 allow: XpermsBitmap::ALL,
1806 auditallow: XpermsBitmap::ALL,
1807 auditdeny: XpermsBitmap::NONE,
1808 };
1809 assert_eq!(decision_range, expected_decision_range);
1810 }
1811
1812 #[test]
1813 fn compute_nlmsg_access_decision_unmatched() {
1814 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1815 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1816 let policy = policy.validate().expect("validate policy");
1817
1818 let source_context: SecurityContext = policy
1819 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1820 .expect("create source security context");
1821
1822 let target_context_unmatched: SecurityContext = policy
1824 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1825 .expect("create source security context");
1826
1827 for prefix in 0x0..=0xff {
1828 let decision = policy.compute_xperms_access_decision(
1829 XpermsKind::Nlmsg,
1830 &source_context,
1831 &target_context_unmatched,
1832 KernelClass::NetlinkRouteSocket,
1833 prefix,
1834 );
1835 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1836 }
1837 }
1838
1839 #[test]
1840 fn compute_ioctl_grant_does_not_cause_nlmsg_deny() {
1841 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1842 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1843 let class_id = find_class_by_name(
1844 &unvalidated.0.classes(),
1845 "class_ioctl_grant_does_not_cause_nlmsg_deny",
1846 )
1847 .expect("look up class_ioctl_grant_does_not_cause_nlmsg_deny")
1848 .id();
1849 let policy = unvalidated.validate().expect("validate policy");
1850 let source_context: SecurityContext = policy
1851 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1852 .expect("create source security context");
1853 let target_context_matched: SecurityContext = source_context.clone();
1854
1855 let ioctl_decision = policy.compute_xperms_access_decision(
1859 XpermsKind::Ioctl,
1860 &source_context,
1861 &target_context_matched,
1862 class_id,
1863 0x00,
1864 );
1865 assert_eq!(
1866 ioctl_decision,
1867 XpermsAccessDecision {
1868 allow: xperms_bitmap_from_elements(&[0x0002]),
1869 auditallow: XpermsBitmap::NONE,
1870 auditdeny: XpermsBitmap::ALL,
1871 }
1872 );
1873 let nlmsg_decision = policy.compute_xperms_access_decision(
1874 XpermsKind::Nlmsg,
1875 &source_context,
1876 &target_context_matched,
1877 class_id,
1878 0x00,
1879 );
1880 assert_eq!(nlmsg_decision, XpermsAccessDecision::ALLOW_ALL);
1881 }
1882
1883 #[test]
1884 fn compute_nlmsg_grant_does_not_cause_ioctl_deny() {
1885 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1886 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1887 let class_id = find_class_by_name(
1888 &unvalidated.0.classes(),
1889 "class_nlmsg_grant_does_not_cause_ioctl_deny",
1890 )
1891 .expect("look up class_nlmsg_grant_does_not_cause_ioctl_deny")
1892 .id();
1893 let policy = unvalidated.validate().expect("validate policy");
1894 let source_context: SecurityContext = policy
1895 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1896 .expect("create source security context");
1897 let target_context_matched: SecurityContext = source_context.clone();
1898
1899 let nlmsg_decision = policy.compute_xperms_access_decision(
1903 XpermsKind::Nlmsg,
1904 &source_context,
1905 &target_context_matched,
1906 class_id,
1907 0x00,
1908 );
1909 assert_eq!(
1910 nlmsg_decision,
1911 XpermsAccessDecision {
1912 allow: xperms_bitmap_from_elements(&[0x0003]),
1913 auditallow: XpermsBitmap::NONE,
1914 auditdeny: XpermsBitmap::ALL,
1915 }
1916 );
1917 let ioctl_decision = policy.compute_xperms_access_decision(
1918 XpermsKind::Ioctl,
1919 &source_context,
1920 &target_context_matched,
1921 class_id,
1922 0x00,
1923 );
1924 assert_eq!(ioctl_decision, XpermsAccessDecision::ALLOW_ALL);
1925 }
1926
1927 #[test]
1928 fn compute_create_context_minimal() {
1929 let policy_bytes =
1930 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy");
1931 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1932 let policy = policy.validate().expect("validate policy");
1933 let source = policy
1934 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1935 .expect("valid source security context");
1936 let target = policy
1937 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1938 .expect("valid target security context");
1939
1940 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1941 let expected: SecurityContext = policy
1942 .parse_security_context(b"source_u:object_r:target_t:s0:c0".into())
1943 .expect("valid expected security context");
1944
1945 assert_eq!(expected, actual);
1946 }
1947
1948 #[test]
1949 fn new_security_context_minimal() {
1950 let policy_bytes =
1951 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy");
1952 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1953 let policy = policy.validate().expect("validate policy");
1954 let source = policy
1955 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1956 .expect("valid source security context");
1957 let target = policy
1958 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1959 .expect("valid target security context");
1960
1961 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1962
1963 assert_eq!(source, actual);
1964 }
1965
1966 #[test]
1967 fn compute_create_context_class_defaults() {
1968 let policy_bytes =
1969 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy");
1970 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1971 let policy = policy.validate().expect("validate policy");
1972 let source = policy
1973 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1974 .expect("valid source security context");
1975 let target = policy
1976 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1977 .expect("valid target security context");
1978
1979 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1980 let expected: SecurityContext = policy
1981 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1982 .expect("valid expected security context");
1983
1984 assert_eq!(expected, actual);
1985 }
1986
1987 #[test]
1988 fn new_security_context_class_defaults() {
1989 let policy_bytes =
1990 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy");
1991 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1992 let policy = policy.validate().expect("validate policy");
1993 let source = policy
1994 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1995 .expect("valid source security context");
1996 let target = policy
1997 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1998 .expect("valid target security context");
1999
2000 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2001 let expected: SecurityContext = policy
2002 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
2003 .expect("valid expected security context");
2004
2005 assert_eq!(expected, actual);
2006 }
2007
2008 #[test]
2009 fn compute_create_context_role_transition() {
2010 let policy_bytes =
2011 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy");
2012 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2013 let policy = policy.validate().expect("validate policy");
2014 let source = policy
2015 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2016 .expect("valid source security context");
2017 let target = policy
2018 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2019 .expect("valid target security context");
2020
2021 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2022 let expected: SecurityContext = policy
2023 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
2024 .expect("valid expected security context");
2025
2026 assert_eq!(expected, actual);
2027 }
2028
2029 #[test]
2030 fn new_security_context_role_transition() {
2031 let policy_bytes =
2032 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy");
2033 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2034 let policy = policy.validate().expect("validate policy");
2035 let source = policy
2036 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2037 .expect("valid source security context");
2038 let target = policy
2039 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2040 .expect("valid target security context");
2041
2042 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2043 let expected: SecurityContext = policy
2044 .parse_security_context(b"source_u:transition_r:source_t:s0:c0-s2:c0.c1".into())
2045 .expect("valid expected security context");
2046
2047 assert_eq!(expected, actual);
2048 }
2049
2050 #[test]
2051 #[ignore]
2053 fn compute_create_context_role_transition_not_allowed() {
2054 let policy_bytes = include_bytes!(
2055 "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy"
2056 );
2057 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2058 let policy = policy.validate().expect("validate policy");
2059 let source = policy
2060 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2061 .expect("valid source security context");
2062 let target = policy
2063 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2064 .expect("valid target security context");
2065
2066 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2067
2068 assert!(policy.validate_security_context(&actual).is_err());
2070 }
2071
2072 #[test]
2073 fn compute_create_context_type_transition() {
2074 let policy_bytes =
2075 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy");
2076 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2077 let policy = policy.validate().expect("validate policy");
2078 let source = policy
2079 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2080 .expect("valid source security context");
2081 let target = policy
2082 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2083 .expect("valid target security context");
2084
2085 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2086 let expected: SecurityContext = policy
2087 .parse_security_context(b"source_u:object_r:transition_t:s0:c0".into())
2088 .expect("valid expected security context");
2089
2090 assert_eq!(expected, actual);
2091 }
2092
2093 #[test]
2094 fn new_security_context_type_transition() {
2095 let policy_bytes =
2096 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy");
2097 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2098 let policy = policy.validate().expect("validate policy");
2099 let source = policy
2100 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2101 .expect("valid source security context");
2102 let target = policy
2103 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2104 .expect("valid target security context");
2105
2106 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2107 let expected: SecurityContext = policy
2108 .parse_security_context(b"source_u:source_r:transition_t:s0:c0-s2:c0.c1".into())
2109 .expect("valid expected security context");
2110
2111 assert_eq!(expected, actual);
2112 }
2113
2114 #[test]
2115 fn compute_create_context_range_transition() {
2116 let policy_bytes =
2117 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy");
2118 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2119 let policy = policy.validate().expect("validate policy");
2120 let source = policy
2121 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2122 .expect("valid source security context");
2123 let target = policy
2124 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2125 .expect("valid target security context");
2126
2127 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2128 let expected: SecurityContext = policy
2129 .parse_security_context(b"source_u:object_r:target_t:s1:c1-s2:c1.c2".into())
2130 .expect("valid expected security context");
2131
2132 assert_eq!(expected, actual);
2133 }
2134
2135 #[test]
2136 fn new_security_context_range_transition() {
2137 let policy_bytes =
2138 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy");
2139 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2140 let policy = policy.validate().expect("validate policy");
2141 let source = policy
2142 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2143 .expect("valid source security context");
2144 let target = policy
2145 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2146 .expect("valid target security context");
2147
2148 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2149 let expected: SecurityContext = policy
2150 .parse_security_context(b"source_u:source_r:source_t:s1:c1-s2:c1.c2".into())
2151 .expect("valid expected security context");
2152
2153 assert_eq!(expected, actual);
2154 }
2155
2156 #[test]
2157 fn access_vector_formats() {
2158 assert_eq!(format!("{:x}", AccessVector::NONE), "0");
2159 assert_eq!(format!("{:x}", AccessVector::ALL), "ffffffff");
2160 assert_eq!(format!("{:?}", AccessVector::NONE), "AccessVector(00000000)");
2161 assert_eq!(format!("{:?}", AccessVector::ALL), "AccessVector(ffffffff)");
2162 }
2163
2164 #[test]
2165 fn policy_genfscon_root_path() {
2166 let policy_bytes =
2167 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy");
2168 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2169 let policy = policy.validate().expect("validate selinux policy");
2170
2171 {
2172 let context = policy.genfscon_label_for_fs_and_path(
2173 "fs_with_path_rules".into(),
2174 "/".into(),
2175 None,
2176 );
2177 assert_eq!(
2178 policy.serialize_security_context(&context.unwrap()),
2179 b"system_u:object_r:fs_with_path_rules_t:s0"
2180 )
2181 }
2182 {
2183 let context = policy.genfscon_label_for_fs_and_path(
2184 "fs_2_with_path_rules".into(),
2185 "/".into(),
2186 None,
2187 );
2188 assert_eq!(
2189 policy.serialize_security_context(&context.unwrap()),
2190 b"system_u:object_r:fs_2_with_path_rules_t:s0"
2191 )
2192 }
2193 }
2194
2195 #[test]
2196 fn policy_genfscon_subpaths() {
2197 let policy_bytes =
2198 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy");
2199 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2200 let policy = policy.validate().expect("validate selinux policy");
2201
2202 let path_label_expectations = [
2203 ("/a1/", "system_u:object_r:fs_with_path_rules_a1_t:s0"),
2207 ("/a1/b", "system_u:object_r:fs_with_path_rules_a1_t:s0"),
2208 ("/a1/b/c", "system_u:object_r:fs_with_path_rules_a1_b_c_t:s0"),
2209 ("/a2/", "system_u:object_r:fs_with_path_rules_t:s0"),
2212 ("/a2/b/c/d", "system_u:object_r:fs_with_path_rules_a2_b_t:s0"),
2213 ("/a3/b/c/d", "system_u:object_r:fs_with_path_rules_a3_t:s0"),
2216 ];
2217 for (path, expected_label) in path_label_expectations {
2218 let context = policy.genfscon_label_for_fs_and_path(
2219 "fs_with_path_rules".into(),
2220 path.into(),
2221 None,
2222 );
2223 assert_eq!(
2224 policy.serialize_security_context(&context.unwrap()),
2225 expected_label.as_bytes()
2226 )
2227 }
2228 }
2229
2230 #[test]
2231 fn policy_genfscon_mixed_order() {
2232 let policy_bytes =
2233 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy");
2234 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2235 let policy = policy.validate().expect("validate selinux policy");
2236
2237 let path_label_expectations = [
2238 ("/", "system_u:object_r:fs_mixed_order_t:s0"),
2239 ("/a", "system_u:object_r:fs_mixed_order_a_t:s0"),
2240 ("/a/a", "system_u:object_r:fs_mixed_order_a_a_t:s0"),
2241 ("/a/b", "system_u:object_r:fs_mixed_order_a_b_t:s0"),
2242 ("/a/b/c", "system_u:object_r:fs_mixed_order_a_b_t:s0"),
2243 ];
2244 for (path, expected_label) in path_label_expectations {
2245 let context =
2246 policy.genfscon_label_for_fs_and_path("fs_mixed_order".into(), path.into(), None);
2247 assert_eq!(
2248 policy.serialize_security_context(&context.unwrap()),
2249 expected_label.as_bytes()
2250 );
2251 }
2252 }
2253}