1pub mod arrays;
6pub mod error;
7pub mod index;
8pub mod metadata;
9pub mod parsed_policy;
10pub mod parser;
11
12mod constraints;
13mod extensible_bitmap;
14mod security_context;
15mod symbols;
16
17pub use arrays::{FsUseType, XpermsBitmap};
18pub use index::FsUseLabelAndType;
19pub use security_context::{SecurityContext, SecurityContextError};
20
21use crate::{self as sc, FsNodeClass, KernelClass, NullessByteStr};
22use anyhow::Context as _;
23use error::ParseError;
24use index::PolicyIndex;
25use metadata::HandleUnknown;
26use parsed_policy::ParsedPolicy;
27use parser::{ByRef, ByValue, ParseStrategy};
28use std::fmt::{Debug, Display};
29use std::marker::PhantomData;
30use std::num::{NonZeroU32, NonZeroU64};
31use std::ops::Deref;
32use symbols::{find_class_by_name, find_common_symbol_by_name_bytes};
33use zerocopy::{
34 little_endian as le, FromBytes, Immutable, KnownLayout, Ref, SplitByteSlice, Unaligned,
35};
36
37pub const SUPPORTED_POLICY_VERSION: u32 = 33;
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)]
62pub struct ClassId(NonZeroU32);
63
64impl Into<u32> for ClassId {
65 fn into(self) -> u32 {
66 self.0.into()
67 }
68}
69
70#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
72pub struct ClassPermissionId(NonZeroU32);
73
74impl Display for ClassPermissionId {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 write!(f, "{}", self.0)
77 }
78}
79
80#[derive(Debug, Clone, PartialEq)]
85pub struct AccessDecision {
86 pub allow: AccessVector,
87 pub auditallow: AccessVector,
88 pub auditdeny: AccessVector,
89 pub flags: u32,
90
91 pub todo_bug: Option<NonZeroU64>,
94}
95
96impl Default for AccessDecision {
97 fn default() -> Self {
98 Self::allow(AccessVector::NONE)
99 }
100}
101
102impl AccessDecision {
103 pub(super) const fn allow(allow: AccessVector) -> Self {
106 Self {
107 allow,
108 auditallow: AccessVector::NONE,
109 auditdeny: AccessVector::ALL,
110 flags: 0,
111 todo_bug: None,
112 }
113 }
114}
115
116pub(super) const SELINUX_AVD_FLAGS_PERMISSIVE: u32 = 1;
118
119#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
122pub struct AccessVector(u32);
123
124impl AccessVector {
125 pub const NONE: AccessVector = AccessVector(0);
126 pub const ALL: AccessVector = AccessVector(std::u32::MAX);
127
128 pub(super) fn from_class_permission_id(id: ClassPermissionId) -> Self {
129 Self((1 as u32) << (id.0.get() - 1))
130 }
131}
132
133impl std::ops::BitAnd for AccessVector {
134 type Output = Self;
135
136 fn bitand(self, rhs: Self) -> Self::Output {
137 AccessVector(self.0 & rhs.0)
138 }
139}
140
141impl std::ops::BitOr for AccessVector {
142 type Output = Self;
143
144 fn bitor(self, rhs: Self) -> Self::Output {
145 AccessVector(self.0 | rhs.0)
146 }
147}
148
149impl std::ops::BitAndAssign for AccessVector {
150 fn bitand_assign(&mut self, rhs: Self) {
151 self.0 &= rhs.0
152 }
153}
154
155impl std::ops::BitOrAssign for AccessVector {
156 fn bitor_assign(&mut self, rhs: Self) {
157 self.0 |= rhs.0
158 }
159}
160
161impl std::ops::SubAssign for AccessVector {
162 fn sub_assign(&mut self, rhs: Self) {
163 self.0 = self.0 ^ (self.0 & rhs.0);
164 }
165}
166
167#[derive(Debug, Clone, PartialEq)]
177pub struct IoctlAccessDecision {
178 pub allow: XpermsBitmap,
179 pub auditallow: XpermsBitmap,
180 pub auditdeny: XpermsBitmap,
181}
182
183impl IoctlAccessDecision {
184 pub const DENY_ALL: Self = Self {
185 allow: XpermsBitmap::NONE,
186 auditallow: XpermsBitmap::NONE,
187 auditdeny: XpermsBitmap::ALL,
188 };
189 pub const ALLOW_ALL: Self = Self {
190 allow: XpermsBitmap::ALL,
191 auditallow: XpermsBitmap::NONE,
192 auditdeny: XpermsBitmap::ALL,
193 };
194}
195
196pub fn parse_policy_by_value(
223 binary_policy: Vec<u8>,
224) -> Result<(Unvalidated<ByValue<Vec<u8>>>, Vec<u8>), anyhow::Error> {
225 let (parsed_policy, binary_policy) =
226 ParsedPolicy::parse(ByValue::new(binary_policy)).context("parsing policy")?;
227 Ok((Unvalidated(parsed_policy), binary_policy))
228}
229
230pub fn parse_policy_by_reference<'a>(
237 binary_policy: &'a [u8],
238) -> Result<Unvalidated<ByRef<&'a [u8]>>, anyhow::Error> {
239 let (parsed_policy, _) =
240 ParsedPolicy::parse(ByRef::new(binary_policy)).context("parsing policy")?;
241 Ok(Unvalidated(parsed_policy))
242}
243
244pub struct ClassInfo<'a> {
246 pub class_name: &'a [u8],
248 pub class_id: ClassId,
250}
251
252#[derive(Debug)]
253pub struct Policy<PS: ParseStrategy>(PolicyIndex<PS>);
254
255impl<PS: ParseStrategy> Policy<PS> {
256 pub fn policy_version(&self) -> u32 {
258 self.0.parsed_policy().policy_version()
259 }
260
261 pub fn handle_unknown(&self) -> HandleUnknown {
264 self.0.parsed_policy().handle_unknown()
265 }
266
267 pub fn conditional_booleans<'a>(&'a self) -> Vec<(&'a [u8], bool)> {
268 self.0
269 .parsed_policy()
270 .conditional_booleans()
271 .iter()
272 .map(|boolean| (PS::deref_slice(&boolean.data), PS::deref(&boolean.metadata).active()))
273 .collect()
274 }
275
276 pub fn classes<'a>(&'a self) -> Vec<ClassInfo<'a>> {
278 self.0
279 .parsed_policy()
280 .classes()
281 .iter()
282 .map(|class| ClassInfo { class_name: class.name_bytes(), class_id: class.id() })
283 .collect()
284 }
285
286 pub(super) fn type_id_by_name(&self, name: &str) -> Option<TypeId> {
288 self.0.parsed_policy().type_by_name(name).map(|x| x.id())
289 }
290
291 pub fn find_class_permissions_by_name(
296 &self,
297 class_name: &str,
298 ) -> Result<Vec<(ClassPermissionId, Vec<u8>)>, ()> {
299 let class = find_class_by_name(self.0.parsed_policy().classes(), class_name).ok_or(())?;
300 let owned_permissions = class.permissions();
301
302 let mut result: Vec<_> = owned_permissions
303 .iter()
304 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
305 .collect();
306
307 if class.common_name_bytes().is_empty() {
309 return Ok(result);
310 }
311
312 let common_symbol_permissions = find_common_symbol_by_name_bytes(
313 self.0.parsed_policy().common_symbols(),
314 class.common_name_bytes(),
315 )
316 .ok_or(())?
317 .permissions();
318
319 result.append(
320 &mut common_symbol_permissions
321 .iter()
322 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
323 .collect(),
324 );
325
326 Ok(result)
327 }
328
329 pub fn fs_use_label_and_type(&self, fs_type: NullessByteStr<'_>) -> Option<FsUseLabelAndType> {
332 self.0.fs_use_label_and_type(fs_type)
333 }
334
335 pub fn genfscon_label_for_fs_and_path(
338 &self,
339 fs_type: NullessByteStr<'_>,
340 node_path: NullessByteStr<'_>,
341 class_id: Option<ClassId>,
342 ) -> Option<SecurityContext> {
343 self.0.genfscon_label_for_fs_and_path(fs_type, node_path, class_id)
344 }
345
346 pub fn initial_context(&self, id: sc::InitialSid) -> security_context::SecurityContext {
349 self.0.initial_context(id)
350 }
351
352 pub fn parse_security_context(
354 &self,
355 security_context: NullessByteStr<'_>,
356 ) -> Result<security_context::SecurityContext, security_context::SecurityContextError> {
357 security_context::SecurityContext::parse(&self.0, security_context)
358 }
359
360 pub fn validate_security_context(
362 &self,
363 security_context: &SecurityContext,
364 ) -> Result<(), SecurityContextError> {
365 security_context.validate(&self.0)
366 }
367
368 pub fn serialize_security_context(&self, security_context: &SecurityContext) -> Vec<u8> {
370 security_context.serialize(&self.0)
371 }
372
373 pub fn new_file_security_context(
378 &self,
379 source: &SecurityContext,
380 target: &SecurityContext,
381 class: &FsNodeClass,
382 ) -> SecurityContext {
383 self.0.new_file_security_context(source, target, class)
384 }
385
386 pub fn new_file_security_context_by_name(
392 &self,
393 source: &SecurityContext,
394 target: &SecurityContext,
395 class: &FsNodeClass,
396 name: NullessByteStr<'_>,
397 ) -> Option<SecurityContext> {
398 self.0.new_file_security_context_by_name(source, target, class, name)
399 }
400
401 pub fn new_security_context(
410 &self,
411 source: &SecurityContext,
412 target: &SecurityContext,
413 class: &KernelClass,
414 ) -> SecurityContext {
415 self.0.new_security_context(
416 source,
417 target,
418 class,
419 source.role(),
420 source.type_(),
421 source.low_level(),
422 source.high_level(),
423 )
424 }
425
426 pub fn compute_access_decision(
442 &self,
443 source_context: &SecurityContext,
444 target_context: &SecurityContext,
445 object_class: &sc::KernelClass,
446 ) -> AccessDecision {
447 if let Some(target_class) = self.0.class(&object_class) {
448 self.0.parsed_policy().compute_access_decision(
449 source_context,
450 target_context,
451 target_class,
452 )
453 } else {
454 AccessDecision::allow(AccessVector::NONE)
455 }
456 }
457
458 pub fn compute_access_decision_custom(
465 &self,
466 source_context: &SecurityContext,
467 target_context: &SecurityContext,
468 target_class_name: &str,
469 ) -> AccessDecision {
470 self.0.parsed_policy().compute_access_decision_custom(
471 source_context,
472 target_context,
473 target_class_name,
474 )
475 }
476
477 pub fn compute_ioctl_access_decision(
481 &self,
482 source_context: &SecurityContext,
483 target_context: &SecurityContext,
484 object_class: &sc::KernelClass,
485 ioctl_prefix: u8,
486 ) -> IoctlAccessDecision {
487 if let Some(target_class) = self.0.class(&object_class) {
488 self.0.parsed_policy().compute_ioctl_access_decision(
489 source_context,
490 target_context,
491 target_class,
492 ioctl_prefix,
493 )
494 } else {
495 IoctlAccessDecision::DENY_ALL
496 }
497 }
498
499 pub fn compute_ioctl_access_decision_custom(
504 &self,
505 source_context: &SecurityContext,
506 target_context: &SecurityContext,
507 target_class_name: &str,
508 ioctl_prefix: u8,
509 ) -> IoctlAccessDecision {
510 self.0.parsed_policy().compute_ioctl_access_decision_custom(
511 source_context,
512 target_context,
513 target_class_name,
514 ioctl_prefix,
515 )
516 }
517
518 pub fn is_bounded_by(&self, bounded_type: TypeId, parent_type: TypeId) -> bool {
519 let type_ = self.0.parsed_policy().type_(bounded_type);
520 type_.bounded_by() == Some(parent_type)
521 }
522
523 pub fn is_permissive(&self, type_: TypeId) -> bool {
525 self.0.parsed_policy().permissive_types().is_set(type_.0.get())
526 }
527}
528
529impl<PS: ParseStrategy> AccessVectorComputer for Policy<PS> {
530 fn access_vector_from_permissions<
531 P: sc::ClassPermission + Into<sc::KernelPermission> + Clone + 'static,
532 >(
533 &self,
534 permissions: &[P],
535 ) -> Option<AccessVector> {
536 let mut access_vector = AccessVector::NONE;
537 for permission in permissions {
538 if let Some(permission_info) = self.0.permission(&permission.clone().into()) {
539 access_vector |= AccessVector::from_class_permission_id(permission_info.id());
541 } else {
542 if self.0.parsed_policy().handle_unknown() != HandleUnknown::Allow {
544 return None;
545 }
546 }
547 }
548 Some(access_vector)
549 }
550}
551
552impl<PS: ParseStrategy> Validate for Policy<PS> {
553 type Error = anyhow::Error;
554
555 fn validate(&self) -> Result<(), Self::Error> {
556 self.0.parsed_policy().validate()
557 }
558}
559
560pub struct Unvalidated<PS: ParseStrategy>(ParsedPolicy<PS>);
562
563impl<PS: ParseStrategy> Unvalidated<PS> {
564 pub fn validate(self) -> Result<Policy<PS>, anyhow::Error> {
565 Validate::validate(&self.0).context("validating parsed policy")?;
566 let index = PolicyIndex::new(self.0).context("building index")?;
567 Ok(Policy(index))
568 }
569}
570
571pub trait AccessVectorComputer {
574 fn access_vector_from_permissions<
581 P: sc::ClassPermission + Into<sc::KernelPermission> + Clone + 'static,
582 >(
583 &self,
584 permissions: &[P],
585 ) -> Option<AccessVector>;
586}
587
588pub trait Parse<PS: ParseStrategy>: Sized {
590 type Error: Into<anyhow::Error>;
593
594 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error>;
597}
598
599pub(super) trait ParseSlice<PS: ParseStrategy>: Sized {
601 type Error: Into<anyhow::Error>;
604
605 fn parse_slice(bytes: PS, count: usize) -> Result<(Self, PS), Self::Error>;
608}
609
610pub(super) trait Validate {
612 type Error: Into<anyhow::Error>;
615
616 fn validate(&self) -> Result<(), Self::Error>;
618}
619
620pub(super) trait ValidateArray<M, D> {
621 type Error: Into<anyhow::Error>;
624
625 fn validate_array<'a>(metadata: &'a M, data: &'a [D]) -> Result<(), Self::Error>;
627}
628
629pub(super) trait Counted {
631 fn count(&self) -> u32;
633}
634
635impl<T: Validate> Validate for Option<T> {
636 type Error = <T as Validate>::Error;
637
638 fn validate(&self) -> Result<(), Self::Error> {
639 match self {
640 Some(value) => value.validate(),
641 None => Ok(()),
642 }
643 }
644}
645
646impl Validate for le::U32 {
647 type Error = anyhow::Error;
648
649 fn validate(&self) -> Result<(), Self::Error> {
652 Ok(())
653 }
654}
655
656impl Validate for u8 {
657 type Error = anyhow::Error;
658
659 fn validate(&self) -> Result<(), Self::Error> {
662 Ok(())
663 }
664}
665
666impl Validate for [u8] {
667 type Error = anyhow::Error;
668
669 fn validate(&self) -> Result<(), Self::Error> {
672 Ok(())
673 }
674}
675
676impl<B: SplitByteSlice, T: Validate + FromBytes + KnownLayout + Immutable> Validate for Ref<B, T> {
677 type Error = <T as Validate>::Error;
678
679 fn validate(&self) -> Result<(), Self::Error> {
680 self.deref().validate()
681 }
682}
683
684impl<B: SplitByteSlice, T: Counted + FromBytes + KnownLayout + Immutable> Counted for Ref<B, T> {
685 fn count(&self) -> u32 {
686 self.deref().count()
687 }
688}
689
690#[derive(Clone, Debug, PartialEq)]
693struct Array<PS, M, D> {
694 metadata: M,
695 data: D,
696 _marker: PhantomData<PS>,
697}
698
699impl<PS: ParseStrategy, M: Counted + Parse<PS>, D: ParseSlice<PS>> Parse<PS> for Array<PS, M, D> {
700 type Error = anyhow::Error;
703
704 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
706 let tail = bytes;
707
708 let (metadata, tail) = M::parse(tail).map_err(Into::<anyhow::Error>::into)?;
709
710 let (data, tail) =
711 D::parse_slice(tail, metadata.count() as usize).map_err(Into::<anyhow::Error>::into)?;
712
713 let array = Self { metadata, data, _marker: PhantomData };
714
715 Ok((array, tail))
716 }
717}
718
719impl<
720 T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned,
721 PS: ParseStrategy<Output<T> = T>,
722 > Parse<PS> for T
723{
724 type Error = anyhow::Error;
725
726 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
727 let num_bytes = bytes.len();
728 let (data, tail) = PS::parse::<T>(bytes).ok_or(ParseError::MissingData {
729 type_name: std::any::type_name::<T>(),
730 type_size: std::mem::size_of::<T>(),
731 num_bytes,
732 })?;
733
734 Ok((data, tail))
735 }
736}
737
738macro_rules! array_type {
742 ($type_name:ident, $parse_strategy:ident, $metadata_type:ty, $data_type:ty, $metadata_type_name:expr, $data_type_name:expr) => {
743 #[doc = "An [`Array`] with [`"]
744 #[doc = $metadata_type_name]
745 #[doc = "`] metadata and [`"]
746 #[doc = $data_type_name]
747 #[doc = "`] data items."]
748 #[derive(Debug, PartialEq)]
749 pub(super) struct $type_name<$parse_strategy: crate::policy::parser::ParseStrategy>(
750 crate::policy::Array<PS, $metadata_type, $data_type>,
751 );
752
753 impl<PS: crate::policy::parser::ParseStrategy> std::ops::Deref for $type_name<PS> {
754 type Target = crate::policy::Array<PS, $metadata_type, $data_type>;
755
756 fn deref(&self) -> &Self::Target {
757 &self.0
758 }
759 }
760
761 impl<PS: crate::policy::parser::ParseStrategy> crate::policy::Parse<PS> for $type_name<PS>
762 where
763 crate::policy::Array<PS, $metadata_type, $data_type>: crate::policy::Parse<PS>,
764 {
765 type Error = <Array<PS, $metadata_type, $data_type> as crate::policy::Parse<PS>>::Error;
766
767 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
768 let (array, tail) = Array::<PS, $metadata_type, $data_type>::parse(bytes)?;
769 Ok((Self(array), tail))
770 }
771 }
772 };
773
774 ($type_name:ident, $parse_strategy:ident, $metadata_type:ty, $data_type:ty) => {
775 array_type!(
776 $type_name,
777 $parse_strategy,
778 $metadata_type,
779 $data_type,
780 stringify!($metadata_type),
781 stringify!($data_type)
782 );
783 };
784}
785
786pub(super) use array_type;
787
788macro_rules! array_type_validate_deref_both {
789 ($type_name:ident) => {
790 impl<PS: crate::policy::parser::ParseStrategy> Validate for $type_name<PS> {
791 type Error = anyhow::Error;
792
793 fn validate(&self) -> Result<(), Self::Error> {
794 let metadata = PS::deref(&self.metadata);
795 metadata.validate()?;
796
797 let data = PS::deref_slice(&self.data);
798 data.validate()?;
799
800 Self::validate_array(metadata, data).map_err(Into::<anyhow::Error>::into)
801 }
802 }
803 };
804}
805
806pub(super) use array_type_validate_deref_both;
807
808macro_rules! array_type_validate_deref_data {
809 ($type_name:ident) => {
810 impl<PS: crate::policy::parser::ParseStrategy> Validate for $type_name<PS> {
811 type Error = anyhow::Error;
812
813 fn validate(&self) -> Result<(), Self::Error> {
814 let metadata = &self.metadata;
815 metadata.validate()?;
816
817 let data = PS::deref_slice(&self.data);
818 data.validate()?;
819
820 Self::validate_array(metadata, data)
821 }
822 }
823 };
824}
825
826pub(super) use array_type_validate_deref_data;
827
828macro_rules! array_type_validate_deref_metadata_data_vec {
829 ($type_name:ident) => {
830 impl<PS: crate::policy::parser::ParseStrategy> Validate for $type_name<PS> {
831 type Error = anyhow::Error;
832
833 fn validate(&self) -> Result<(), Self::Error> {
834 let metadata = PS::deref(&self.metadata);
835 metadata.validate()?;
836
837 let data = &self.data;
838 data.validate()?;
839
840 Self::validate_array(metadata, 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<PS: crate::policy::parser::ParseStrategy> Validate for $type_name<PS> {
851 type Error = anyhow::Error;
852
853 fn validate(&self) -> Result<(), Self::Error> {
854 let metadata = &self.metadata;
855 metadata.validate()?;
856
857 let data = &self.data;
858 data.validate()?;
859
860 Self::validate_array(metadata, data.as_slice())
861 }
862 }
863 };
864}
865
866pub(super) use array_type_validate_deref_none_data_vec;
867
868impl<
869 B: Debug + SplitByteSlice + PartialEq,
870 T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned,
871 > Parse<ByRef<B>> for Ref<B, T>
872{
873 type Error = anyhow::Error;
874
875 fn parse(bytes: ByRef<B>) -> Result<(Self, ByRef<B>), Self::Error> {
876 let num_bytes = bytes.len();
877 let (data, tail) = ByRef::<B>::parse::<T>(bytes).ok_or(ParseError::MissingData {
878 type_name: std::any::type_name::<T>(),
879 type_size: std::mem::size_of::<T>(),
880 num_bytes,
881 })?;
882
883 Ok((data, tail))
884 }
885}
886
887impl<
888 B: Debug + SplitByteSlice + PartialEq,
889 T: Clone + Debug + FromBytes + Immutable + PartialEq + Unaligned,
890 > ParseSlice<ByRef<B>> for Ref<B, [T]>
891{
892 type Error = anyhow::Error;
895
896 fn parse_slice(bytes: ByRef<B>, count: usize) -> Result<(Self, ByRef<B>), Self::Error> {
899 let num_bytes = bytes.len();
900 let (data, tail) =
901 ByRef::<B>::parse_slice::<T>(bytes, count).ok_or(ParseError::MissingSliceData {
902 type_name: std::any::type_name::<T>(),
903 type_size: std::mem::size_of::<T>(),
904 num_items: count,
905 num_bytes,
906 })?;
907
908 Ok((data, tail))
909 }
910}
911
912impl<PS: ParseStrategy, T: Parse<PS>> ParseSlice<PS> for Vec<T> {
913 type Error = anyhow::Error;
916
917 fn parse_slice(bytes: PS, count: usize) -> Result<(Self, PS), Self::Error> {
919 let mut slice = Vec::with_capacity(count);
920 let mut tail = bytes;
921
922 for _ in 0..count {
923 let (item, next_tail) = T::parse(tail).map_err(Into::<anyhow::Error>::into)?;
924 slice.push(item);
925 tail = next_tail;
926 }
927
928 Ok((slice, tail))
929 }
930}
931
932#[cfg(test)]
933pub(super) mod testing {
934 use crate::policy::error::ValidateError;
935 use crate::policy::{AccessVector, ParseError};
936
937 pub const ACCESS_VECTOR_0001: AccessVector = AccessVector(0b0001u32);
938 pub const ACCESS_VECTOR_0010: AccessVector = AccessVector(0b0010u32);
939
940 pub(super) fn as_parse_error(error: anyhow::Error) -> ParseError {
942 error.downcast::<ParseError>().expect("parse error")
943 }
944
945 pub(super) fn as_validate_error(error: anyhow::Error) -> ValidateError {
947 error.downcast::<ValidateError>().expect("validate error")
948 }
949}
950
951#[cfg(test)]
952pub(super) mod tests {
953 use super::*;
954
955 use crate::policy::metadata::HandleUnknown;
956 use crate::policy::{parse_policy_by_reference, parse_policy_by_value, SecurityContext};
957 use crate::{
958 ClassPermission as _, FileClass, InitialSid, KernelClass, KernelPermission,
959 ProcessPermission,
960 };
961
962 use serde::Deserialize;
963 use std::ops::Shl;
964
965 fn is_explicitly_allowed<PS: ParseStrategy>(
972 policy: &Policy<PS>,
973 source_type: TypeId,
974 target_type: TypeId,
975 permission: sc::KernelPermission,
976 ) -> Result<bool, &'static str> {
977 let object_class = permission.class();
978 let target_class = policy.0.class(&object_class).ok_or("class lookup failed")?;
979 let permission = policy.0.permission(&permission).ok_or("permission lookup failed")?;
980 let access_decision = policy.0.parsed_policy().compute_explicitly_allowed(
981 source_type,
982 target_type,
983 target_class,
984 );
985 let permission_bit = AccessVector::from_class_permission_id(permission.id());
986 Ok(permission_bit == access_decision.allow & permission_bit)
987 }
988
989 fn is_explicitly_allowed_custom<PS: ParseStrategy>(
996 policy: &Policy<PS>,
997 source_type: TypeId,
998 target_type: TypeId,
999 target_class_name: &str,
1000 permission_name: &str,
1001 ) -> Result<bool, &'static str> {
1002 let (permission_id, _) = policy
1003 .find_class_permissions_by_name(target_class_name)
1004 .or(Err("class name lookup failed"))?
1005 .into_iter()
1006 .find(|(_, name)| name == permission_name.as_bytes())
1007 .ok_or("permission name lookup failed")?;
1008 let access_decision = policy.0.parsed_policy().compute_explicitly_allowed_custom(
1009 source_type,
1010 target_type,
1011 target_class_name,
1012 );
1013 let permission_bit = AccessVector::from_class_permission_id(permission_id);
1014 Ok(permission_bit == access_decision.allow & permission_bit)
1015 }
1016
1017 #[derive(Debug, Deserialize)]
1018 struct Expectations {
1019 expected_policy_version: u32,
1020 expected_handle_unknown: LocalHandleUnknown,
1021 }
1022
1023 #[derive(Debug, Deserialize, PartialEq)]
1024 #[serde(rename_all = "snake_case")]
1025 enum LocalHandleUnknown {
1026 Deny,
1027 Reject,
1028 Allow,
1029 }
1030
1031 impl PartialEq<HandleUnknown> for LocalHandleUnknown {
1032 fn eq(&self, other: &HandleUnknown) -> bool {
1033 match self {
1034 LocalHandleUnknown::Deny => *other == HandleUnknown::Deny,
1035 LocalHandleUnknown::Reject => *other == HandleUnknown::Reject,
1036 LocalHandleUnknown::Allow => *other == HandleUnknown::Allow,
1037 }
1038 }
1039 }
1040
1041 fn xperms_bitmap_from_elements(elements: &[u8]) -> XpermsBitmap {
1044 let mut bitmap = [le::U32::ZERO; 8];
1045 for element in elements.iter() {
1046 let block_index = (*element as usize) / 32;
1047 let bit_index = ((*element as usize) % 32) as u32;
1048 let bitmask = le::U32::new(1).shl(bit_index);
1049 bitmap[block_index] = bitmap[block_index] | bitmask;
1050 }
1051 XpermsBitmap::new(bitmap)
1052 }
1053
1054 #[test]
1055 fn known_policies() {
1056 let policies_and_expectations = [
1057 [
1058 b"testdata/policies/emulator".to_vec(),
1059 include_bytes!("../../testdata/policies/emulator").to_vec(),
1060 include_bytes!("../../testdata/expectations/emulator").to_vec(),
1061 ],
1062 [
1063 b"testdata/policies/selinux_testsuite".to_vec(),
1064 include_bytes!("../../testdata/policies/selinux_testsuite").to_vec(),
1065 include_bytes!("../../testdata/expectations/selinux_testsuite").to_vec(),
1066 ],
1067 ];
1068
1069 for [policy_path, policy_bytes, expectations_bytes] in policies_and_expectations {
1070 let expectations = serde_json5::from_reader::<_, Expectations>(
1071 &mut std::io::Cursor::new(expectations_bytes),
1072 )
1073 .expect("deserialize expectations");
1074
1075 let (policy, returned_policy_bytes) =
1078 parse_policy_by_value(policy_bytes.clone()).expect("parse policy");
1079
1080 let policy = policy
1081 .validate()
1082 .with_context(|| {
1083 format!(
1084 "policy path: {:?}",
1085 std::str::from_utf8(policy_path.as_slice()).unwrap()
1086 )
1087 })
1088 .expect("validate policy");
1089
1090 assert_eq!(expectations.expected_policy_version, policy.policy_version());
1091 assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
1092
1093 assert_eq!(policy_bytes, returned_policy_bytes);
1095
1096 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1098 let policy = policy.validate().expect("validate policy");
1099
1100 assert_eq!(expectations.expected_policy_version, policy.policy_version());
1101 assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
1102 }
1103 }
1104
1105 #[test]
1106 fn policy_lookup() {
1107 let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
1108 let (policy, _) = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1109 let policy = policy.validate().expect("validate selinux testsuite policy");
1110
1111 let unconfined_t = policy.type_id_by_name("unconfined_t").expect("look up type id");
1112
1113 assert!(is_explicitly_allowed(
1114 &policy,
1115 unconfined_t,
1116 unconfined_t,
1117 KernelPermission::Process(ProcessPermission::Fork),
1118 )
1119 .expect("check for `allow unconfined_t unconfined_t:process fork;"));
1120 }
1121
1122 #[test]
1123 fn initial_contexts() {
1124 let policy_bytes = include_bytes!(
1125 "../../testdata/micro_policies/multiple_levels_and_categories_policy.pp"
1126 );
1127 let (policy, _) = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1128 let policy = policy.validate().expect("validate policy");
1129
1130 let kernel_context = policy.initial_context(InitialSid::Kernel);
1131 assert_eq!(
1132 policy.serialize_security_context(&kernel_context),
1133 b"user0:object_r:type0:s0:c0-s1:c0.c2,c4"
1134 )
1135 }
1136
1137 #[test]
1138 fn explicit_allow_type_type() {
1139 let policy_bytes =
1140 include_bytes!("../../testdata/micro_policies/allow_a_t_b_t_class0_perm0_policy.pp");
1141 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1142 .expect("parse policy")
1143 .validate()
1144 .expect("validate policy");
1145
1146 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1147 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1148
1149 assert!(is_explicitly_allowed_custom(&policy, a_t, b_t, "class0", "perm0")
1150 .expect("query well-formed"));
1151 }
1152
1153 #[test]
1154 fn no_explicit_allow_type_type() {
1155 let policy_bytes =
1156 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_t_class0_perm0_policy.pp");
1157 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1158 .expect("parse policy")
1159 .validate()
1160 .expect("validate policy");
1161
1162 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1163 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1164
1165 assert!(!is_explicitly_allowed_custom(&policy, a_t, b_t, "class0", "perm0")
1166 .expect("query well-formed"));
1167 }
1168
1169 #[test]
1170 fn explicit_allow_type_attr() {
1171 let policy_bytes =
1172 include_bytes!("../../testdata/micro_policies/allow_a_t_b_attr_class0_perm0_policy.pp");
1173 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1174 .expect("parse policy")
1175 .validate()
1176 .expect("validate policy");
1177
1178 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1179 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1180
1181 assert!(is_explicitly_allowed_custom(&policy, a_t, b_t, "class0", "perm0")
1182 .expect("query well-formed"));
1183 }
1184
1185 #[test]
1186 fn no_explicit_allow_type_attr() {
1187 let policy_bytes = include_bytes!(
1188 "../../testdata/micro_policies/no_allow_a_t_b_attr_class0_perm0_policy.pp"
1189 );
1190 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1191 .expect("parse policy")
1192 .validate()
1193 .expect("validate policy");
1194
1195 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1196 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1197
1198 assert!(!is_explicitly_allowed_custom(&policy, a_t, b_t, "class0", "perm0")
1199 .expect("query well-formed"));
1200 }
1201
1202 #[test]
1203 fn explicit_allow_attr_attr() {
1204 let policy_bytes = include_bytes!(
1205 "../../testdata/micro_policies/allow_a_attr_b_attr_class0_perm0_policy.pp"
1206 );
1207 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1208 .expect("parse policy")
1209 .validate()
1210 .expect("validate policy");
1211
1212 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1213 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1214
1215 assert!(is_explicitly_allowed_custom(&policy, a_t, b_t, "class0", "perm0")
1216 .expect("query well-formed"));
1217 }
1218
1219 #[test]
1220 fn no_explicit_allow_attr_attr() {
1221 let policy_bytes = include_bytes!(
1222 "../../testdata/micro_policies/no_allow_a_attr_b_attr_class0_perm0_policy.pp"
1223 );
1224 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1225 .expect("parse policy")
1226 .validate()
1227 .expect("validate policy");
1228
1229 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1230 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1231
1232 assert!(!is_explicitly_allowed_custom(&policy, a_t, b_t, "class0", "perm0")
1233 .expect("query well-formed"));
1234 }
1235
1236 #[test]
1237 fn compute_explicitly_allowed_multiple_attributes() {
1238 let policy_bytes = include_bytes!("../../testdata/micro_policies/allow_a_t_a1_attr_class0_perm0_a2_attr_class0_perm1_policy.pp");
1239 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1240 .expect("parse policy")
1241 .validate()
1242 .expect("validate policy");
1243
1244 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1245
1246 let raw_access_vector =
1247 policy.0.parsed_policy().compute_explicitly_allowed_custom(a_t, a_t, "class0").allow.0;
1248
1249 assert_eq!(2, raw_access_vector.count_ones());
1254 }
1255
1256 #[test]
1257 fn compute_access_decision_with_constraints() {
1258 let policy_bytes =
1259 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1260 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1261 .expect("parse policy")
1262 .validate()
1263 .expect("validate policy");
1264
1265 let source_context: SecurityContext = policy
1266 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1267 .expect("create source security context");
1268
1269 let target_context_satisfied: SecurityContext = source_context.clone();
1270 let decision_satisfied = policy.compute_access_decision(
1271 &source_context,
1272 &target_context_satisfied,
1273 &KernelClass::File,
1274 );
1275 assert_eq!(decision_satisfied.allow, AccessVector(7));
1279
1280 let target_context_unsatisfied: SecurityContext = policy
1281 .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1282 .expect("create target security context failing some constraints");
1283 let decision_unsatisfied = policy.compute_access_decision(
1284 &source_context,
1285 &target_context_unsatisfied,
1286 &KernelClass::File,
1287 );
1288 assert_eq!(decision_unsatisfied.allow, AccessVector(4));
1291 }
1292
1293 #[test]
1294 fn compute_access_decision_custom_with_mlsconstrain() {
1295 let policy_bytes =
1296 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1297 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1298 .expect("parse policy")
1299 .validate()
1300 .expect("validate policy");
1301
1302 let source_context: SecurityContext = policy
1303 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1304 .expect("create source security context");
1305
1306 let target_context_satisfied: SecurityContext = source_context.clone();
1307 let decision_satisfied = policy.compute_access_decision_custom(
1308 &source_context,
1309 &target_context_satisfied,
1310 "class_mlsconstrain",
1311 );
1312 assert_eq!(decision_satisfied.allow, AccessVector(3));
1316
1317 let target_context_unsatisfied: SecurityContext = policy
1318 .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1319 .expect("create target security context failing a constraint");
1320 let decision_unsatisfied = policy.compute_access_decision_custom(
1321 &source_context,
1322 &target_context_unsatisfied,
1323 "class_mlsconstrain",
1324 );
1325 assert_eq!(decision_unsatisfied.allow, AccessVector(2));
1328 }
1329
1330 #[test]
1331 fn compute_access_decision_custom_with_constrain() {
1332 let policy_bytes =
1333 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1334 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1335 .expect("parse policy")
1336 .validate()
1337 .expect("validate policy");
1338
1339 let source_context: SecurityContext = policy
1340 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1341 .expect("create source security context");
1342
1343 let target_context_satisfied: SecurityContext = source_context.clone();
1344 let decision_satisfied = policy.compute_access_decision_custom(
1345 &source_context,
1346 &target_context_satisfied,
1347 "class_mlsconstrain",
1348 );
1349 assert_eq!(decision_satisfied.allow, AccessVector(3));
1353
1354 let target_context_unsatisfied: SecurityContext = policy
1355 .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1356 .expect("create target security context failing a constraint");
1357 let decision_unsatisfied = policy.compute_access_decision_custom(
1358 &source_context,
1359 &target_context_unsatisfied,
1360 "class_constrain",
1361 );
1362 assert_eq!(decision_unsatisfied.allow, AccessVector(2));
1365 }
1366
1367 #[test]
1368 fn compute_ioctl_access_decision_explicitly_allowed() {
1369 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1370 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1371 .expect("parse policy")
1372 .validate()
1373 .expect("validate policy");
1374
1375 let source_context: SecurityContext = policy
1376 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1377 .expect("create source security context");
1378 let target_context_matched: SecurityContext = source_context.clone();
1379
1380 let decision_single = policy.compute_ioctl_access_decision(
1398 &source_context,
1399 &target_context_matched,
1400 &KernelClass::File,
1401 0xab,
1402 );
1403
1404 let mut expected_auditdeny =
1405 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1406 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1407
1408 let expected_decision_single = IoctlAccessDecision {
1409 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1410 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1411 auditdeny: expected_auditdeny,
1412 };
1413 assert_eq!(decision_single, expected_decision_single);
1414
1415 let decision_range = policy.compute_ioctl_access_decision(
1416 &source_context,
1417 &target_context_matched,
1418 &KernelClass::File,
1419 0x10,
1420 );
1421 let expected_decision_range = IoctlAccessDecision {
1422 allow: XpermsBitmap::ALL,
1423 auditallow: XpermsBitmap::ALL,
1424 auditdeny: XpermsBitmap::NONE,
1425 };
1426 assert_eq!(decision_range, expected_decision_range);
1427 }
1428
1429 #[test]
1430 fn compute_ioctl_access_decision_unmatched() {
1431 let policy_bytes =
1432 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1433 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1434 .expect("parse policy")
1435 .validate()
1436 .expect("validate policy");
1437
1438 let source_context: SecurityContext = policy
1439 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1440 .expect("create source security context");
1441
1442 let target_context_unmatched: SecurityContext = policy
1444 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1445 .expect("create source security context");
1446
1447 for prefix in 0x0..=0xff {
1448 let decision = policy.compute_ioctl_access_decision(
1449 &source_context,
1450 &target_context_unmatched,
1451 &KernelClass::File,
1452 prefix,
1453 );
1454 assert_eq!(decision, IoctlAccessDecision::ALLOW_ALL);
1455 }
1456 }
1457
1458 #[test]
1459 fn compute_ioctl_access_decision_custom() {
1460 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1461 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1462 .expect("parse policy")
1463 .validate()
1464 .expect("validate policy");
1465
1466 let source_context: SecurityContext = policy
1467 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1468 .expect("create source security context");
1469
1470 let target_context: SecurityContext = source_context.clone();
1474 let decision = policy.compute_ioctl_access_decision_custom(
1475 &source_context,
1476 &target_context,
1477 "class_two_ioctls_same_range",
1478 0x12,
1479 );
1480
1481 let expected_decision = IoctlAccessDecision {
1482 allow: xperms_bitmap_from_elements(&[0x34, 0x56]),
1483 auditallow: XpermsBitmap::NONE,
1484 auditdeny: XpermsBitmap::ALL,
1485 };
1486 assert_eq!(decision, expected_decision);
1487 }
1488
1489 #[test]
1490 fn new_file_security_context_minimal() {
1491 let policy_bytes =
1492 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1493 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1494 .expect("parse policy")
1495 .validate()
1496 .expect("validate policy");
1497 let source = policy
1498 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1499 .expect("valid source security context");
1500 let target = policy
1501 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1502 .expect("valid target security context");
1503
1504 let actual = policy.new_file_security_context(&source, &target, &FileClass::File.into());
1505 let expected: SecurityContext = policy
1506 .parse_security_context(b"source_u:object_r:target_t:s0:c0".into())
1507 .expect("valid expected security context");
1508
1509 assert_eq!(expected, actual);
1510 }
1511
1512 #[test]
1513 fn new_security_context_minimal() {
1514 let policy_bytes =
1515 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1516 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1517 .expect("parse policy")
1518 .validate()
1519 .expect("validate policy");
1520 let source = policy
1521 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1522 .expect("valid source security context");
1523 let target = policy
1524 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1525 .expect("valid target security context");
1526
1527 let actual = policy.new_security_context(&source, &target, &KernelClass::Process);
1528
1529 assert_eq!(source, actual);
1530 }
1531
1532 #[test]
1533 fn new_file_security_context_class_defaults() {
1534 let policy_bytes =
1535 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1536 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1537 .expect("parse policy")
1538 .validate()
1539 .expect("validate policy");
1540 let source = policy
1541 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1542 .expect("valid source security context");
1543 let target = policy
1544 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1545 .expect("valid target security context");
1546
1547 let actual = policy.new_file_security_context(&source, &target, &FileClass::File.into());
1548 let expected: SecurityContext = policy
1549 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1550 .expect("valid expected security context");
1551
1552 assert_eq!(expected, actual);
1553 }
1554
1555 #[test]
1556 fn new_security_context_class_defaults() {
1557 let policy_bytes =
1558 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1559 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1560 .expect("parse policy")
1561 .validate()
1562 .expect("validate policy");
1563 let source = policy
1564 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1565 .expect("valid source security context");
1566 let target = policy
1567 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1568 .expect("valid target security context");
1569
1570 let actual = policy.new_security_context(&source, &target, &KernelClass::Process);
1571 let expected: SecurityContext = policy
1572 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1573 .expect("valid expected security context");
1574
1575 assert_eq!(expected, actual);
1576 }
1577
1578 #[test]
1579 fn new_file_security_context_role_transition() {
1580 let policy_bytes =
1581 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
1582 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1583 .expect("parse policy")
1584 .validate()
1585 .expect("validate policy");
1586 let source = policy
1587 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1588 .expect("valid source security context");
1589 let target = policy
1590 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1591 .expect("valid target security context");
1592
1593 let actual = policy.new_file_security_context(&source, &target, &FileClass::File.into());
1594 let expected: SecurityContext = policy
1595 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
1596 .expect("valid expected security context");
1597
1598 assert_eq!(expected, actual);
1599 }
1600
1601 #[test]
1602 fn new_security_context_role_transition() {
1603 let policy_bytes =
1604 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
1605 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1606 .expect("parse policy")
1607 .validate()
1608 .expect("validate policy");
1609 let source = policy
1610 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1611 .expect("valid source security context");
1612 let target = policy
1613 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1614 .expect("valid target security context");
1615
1616 let actual = policy.new_security_context(&source, &target, &KernelClass::Process);
1617 let expected: SecurityContext = policy
1618 .parse_security_context(b"source_u:transition_r:source_t:s0:c0-s2:c0.c1".into())
1619 .expect("valid expected security context");
1620
1621 assert_eq!(expected, actual);
1622 }
1623
1624 #[test]
1625 #[ignore]
1627 fn new_file_security_context_role_transition_not_allowed() {
1628 let policy_bytes = include_bytes!(
1629 "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy.pp"
1630 );
1631 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1632 .expect("parse policy")
1633 .validate()
1634 .expect("validate policy");
1635 let source = policy
1636 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1637 .expect("valid source security context");
1638 let target = policy
1639 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1640 .expect("valid target security context");
1641
1642 let actual = policy.new_file_security_context(&source, &target, &FileClass::File.into());
1643
1644 assert!(policy.validate_security_context(&actual).is_err());
1646 }
1647
1648 #[test]
1649 fn new_file_security_context_type_transition() {
1650 let policy_bytes =
1651 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
1652 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1653 .expect("parse policy")
1654 .validate()
1655 .expect("validate policy");
1656 let source = policy
1657 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1658 .expect("valid source security context");
1659 let target = policy
1660 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1661 .expect("valid target security context");
1662
1663 let actual = policy.new_file_security_context(&source, &target, &FileClass::File.into());
1664 let expected: SecurityContext = policy
1665 .parse_security_context(b"source_u:object_r:transition_t:s0:c0".into())
1666 .expect("valid expected security context");
1667
1668 assert_eq!(expected, actual);
1669 }
1670
1671 #[test]
1672 fn new_security_context_type_transition() {
1673 let policy_bytes =
1674 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
1675 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1676 .expect("parse policy")
1677 .validate()
1678 .expect("validate policy");
1679 let source = policy
1680 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1681 .expect("valid source security context");
1682 let target = policy
1683 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1684 .expect("valid target security context");
1685
1686 let actual = policy.new_security_context(&source, &target, &KernelClass::Process);
1687 let expected: SecurityContext = policy
1688 .parse_security_context(b"source_u:source_r:transition_t:s0:c0-s2:c0.c1".into())
1689 .expect("valid expected security context");
1690
1691 assert_eq!(expected, actual);
1692 }
1693
1694 #[test]
1695 fn new_file_security_context_range_transition() {
1696 let policy_bytes =
1697 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
1698 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1699 .expect("parse policy")
1700 .validate()
1701 .expect("validate policy");
1702 let source = policy
1703 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1704 .expect("valid source security context");
1705 let target = policy
1706 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1707 .expect("valid target security context");
1708
1709 let actual = policy.new_file_security_context(&source, &target, &FileClass::File.into());
1710 let expected: SecurityContext = policy
1711 .parse_security_context(b"source_u:object_r:target_t:s1:c1-s2:c1.c2".into())
1712 .expect("valid expected security context");
1713
1714 assert_eq!(expected, actual);
1715 }
1716
1717 #[test]
1718 fn new_security_context_range_transition() {
1719 let policy_bytes =
1720 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
1721 let policy = parse_policy_by_reference(policy_bytes.as_slice())
1722 .expect("parse policy")
1723 .validate()
1724 .expect("validate policy");
1725 let source = policy
1726 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1727 .expect("valid source security context");
1728 let target = policy
1729 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1730 .expect("valid target security context");
1731
1732 let actual = policy.new_security_context(&source, &target, &KernelClass::Process);
1733 let expected: SecurityContext = policy
1734 .parse_security_context(b"source_u:source_r:source_t:s1:c1-s2:c1.c2".into())
1735 .expect("valid expected security context");
1736
1737 assert_eq!(expected, actual);
1738 }
1739}