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 as sc;
24use anyhow::Context as _;
25use error::ParseError;
26use index::PolicyIndex;
27use metadata::HandleUnknown;
28use parsed_policy::ParsedPolicy;
29use parser::PolicyData;
30use std::fmt::{Debug, Display, LowerHex};
31use std::sync::Arc;
32
33use std::num::{NonZeroU32, NonZeroU64};
34use std::ops::Deref;
35use std::str::FromStr;
36use symbols::{find_class_by_name, find_common_symbol_by_name_bytes};
37use zerocopy::{
38 FromBytes, Immutable, KnownLayout, Ref, SplitByteSlice, Unaligned, little_endian as le,
39};
40
41pub const SUPPORTED_POLICY_VERSION: u32 = 33;
43
44#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
46pub struct UserId(NonZeroU32);
47
48#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
50pub struct RoleId(NonZeroU32);
51
52#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
54pub struct TypeId(NonZeroU32);
55
56#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
58pub struct SensitivityId(NonZeroU32);
59
60#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
62pub struct CategoryId(NonZeroU32);
63
64#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
67pub struct ClassId(NonZeroU32);
68
69impl ClassId {
70 pub fn new(id: NonZeroU32) -> Self {
72 Self(id)
73 }
74}
75
76impl Into<u32> for ClassId {
77 fn into(self) -> u32 {
78 self.0.into()
79 }
80}
81
82#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
84pub struct ClassPermissionId(NonZeroU32);
85
86impl Display for ClassPermissionId {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 write!(f, "{}", self.0)
89 }
90}
91
92#[derive(Debug, Clone, PartialEq)]
97pub struct AccessDecision {
98 pub allow: AccessVector,
99 pub auditallow: AccessVector,
100 pub auditdeny: AccessVector,
101 pub flags: u32,
102
103 pub todo_bug: Option<NonZeroU64>,
106}
107
108impl Default for AccessDecision {
109 fn default() -> Self {
110 Self::allow(AccessVector::NONE)
111 }
112}
113
114impl AccessDecision {
115 pub(super) const fn allow(allow: AccessVector) -> Self {
118 Self {
119 allow,
120 auditallow: AccessVector::NONE,
121 auditdeny: AccessVector::ALL,
122 flags: 0,
123 todo_bug: None,
124 }
125 }
126}
127
128pub(super) const SELINUX_AVD_FLAGS_PERMISSIVE: u32 = 1;
130
131#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
134pub struct AccessVector(u32);
135
136impl AccessVector {
137 pub const NONE: AccessVector = AccessVector(0);
138 pub const ALL: AccessVector = AccessVector(std::u32::MAX);
139
140 pub(super) fn from_class_permission_id(id: ClassPermissionId) -> Self {
141 Self((1 as u32) << (id.0.get() - 1))
142 }
143}
144
145impl Debug for AccessVector {
146 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147 write!(f, "AccessVector({:0>8x})", self)
148 }
149}
150
151impl FromStr for AccessVector {
152 type Err = <u32 as FromStr>::Err;
153
154 fn from_str(value: &str) -> Result<Self, Self::Err> {
155 Ok(AccessVector(u32::from_str_radix(value, 16)?))
157 }
158}
159
160impl LowerHex for AccessVector {
161 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162 LowerHex::fmt(&self.0, f)
163 }
164}
165
166impl std::ops::BitAnd for AccessVector {
167 type Output = Self;
168
169 fn bitand(self, rhs: Self) -> Self::Output {
170 AccessVector(self.0 & rhs.0)
171 }
172}
173
174impl std::ops::BitOr for AccessVector {
175 type Output = Self;
176
177 fn bitor(self, rhs: Self) -> Self::Output {
178 AccessVector(self.0 | rhs.0)
179 }
180}
181
182impl std::ops::BitAndAssign for AccessVector {
183 fn bitand_assign(&mut self, rhs: Self) {
184 self.0 &= rhs.0
185 }
186}
187
188impl std::ops::BitOrAssign for AccessVector {
189 fn bitor_assign(&mut self, rhs: Self) {
190 self.0 |= rhs.0
191 }
192}
193
194impl std::ops::SubAssign for AccessVector {
195 fn sub_assign(&mut self, rhs: Self) {
196 self.0 = self.0 ^ (self.0 & rhs.0);
197 }
198}
199
200impl std::ops::Sub for AccessVector {
201 type Output = Self;
202
203 fn sub(self, rhs: Self) -> Self::Output {
204 AccessVector(self.0 ^ (self.0 & rhs.0))
205 }
206}
207
208#[derive(Clone, Debug, Eq, Hash, PartialEq)]
211pub enum XpermsKind {
212 Ioctl,
213 Nlmsg,
214}
215
216#[derive(Debug, Clone, PartialEq)]
221pub struct XpermsAccessDecision {
222 pub allow: XpermsBitmap,
223 pub auditallow: XpermsBitmap,
224 pub auditdeny: XpermsBitmap,
225}
226
227impl XpermsAccessDecision {
228 pub const DENY_ALL: Self = Self {
229 allow: XpermsBitmap::NONE,
230 auditallow: XpermsBitmap::NONE,
231 auditdeny: XpermsBitmap::ALL,
232 };
233 pub const ALLOW_ALL: Self = Self {
234 allow: XpermsBitmap::ALL,
235 auditallow: XpermsBitmap::NONE,
236 auditdeny: XpermsBitmap::ALL,
237 };
238}
239
240pub fn parse_policy_by_value(binary_policy: Vec<u8>) -> Result<Unvalidated, anyhow::Error> {
249 let policy_data = Arc::new(binary_policy);
250 let policy = ParsedPolicy::parse(policy_data).context("parsing policy")?;
251 Ok(Unvalidated(policy))
252}
253
254pub struct ClassInfo<'a> {
256 pub class_name: &'a [u8],
258 pub class_id: ClassId,
260}
261
262#[derive(Debug)]
263pub struct Policy(PolicyIndex);
264
265impl Policy {
266 pub fn policy_version(&self) -> u32 {
268 self.0.parsed_policy().policy_version()
269 }
270
271 pub fn binary(&self) -> &PolicyData {
272 &self.0.parsed_policy().data
273 }
274
275 pub fn handle_unknown(&self) -> HandleUnknown {
278 self.0.parsed_policy().handle_unknown()
279 }
280
281 pub fn conditional_booleans<'a>(&'a self) -> Vec<(&'a [u8], bool)> {
282 self.0
283 .parsed_policy()
284 .conditional_booleans()
285 .iter()
286 .map(|boolean| (boolean.data.as_slice(), boolean.metadata.active()))
287 .collect()
288 }
289
290 pub fn classes<'a>(&'a self) -> Vec<ClassInfo<'a>> {
292 self.0
293 .parsed_policy()
294 .classes()
295 .iter()
296 .map(|class| ClassInfo { class_name: class.name_bytes(), class_id: class.id() })
297 .collect()
298 }
299
300 pub(super) fn type_id_by_name(&self, name: &str) -> Option<TypeId> {
302 self.0.parsed_policy().type_by_name(name).map(|x| x.id())
303 }
304
305 pub fn find_class_permissions_by_name(
310 &self,
311 class_name: &str,
312 ) -> Result<Vec<(ClassPermissionId, Vec<u8>)>, ()> {
313 let class = find_class_by_name(self.0.parsed_policy().classes(), class_name).ok_or(())?;
314 let owned_permissions = class.permissions();
315
316 let mut result: Vec<_> = owned_permissions
317 .iter()
318 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
319 .collect();
320
321 if class.common_name_bytes().is_empty() {
323 return Ok(result);
324 }
325
326 let common_symbol_permissions = find_common_symbol_by_name_bytes(
327 self.0.parsed_policy().common_symbols(),
328 class.common_name_bytes(),
329 )
330 .ok_or(())?
331 .permissions();
332
333 result.append(
334 &mut common_symbol_permissions
335 .iter()
336 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
337 .collect(),
338 );
339
340 Ok(result)
341 }
342
343 pub fn fs_use_label_and_type(
346 &self,
347 fs_type: sc::NullessByteStr<'_>,
348 ) -> Option<FsUseLabelAndType> {
349 self.0.fs_use_label_and_type(fs_type)
350 }
351
352 pub fn genfscon_label_for_fs_and_path(
355 &self,
356 fs_type: sc::NullessByteStr<'_>,
357 node_path: sc::NullessByteStr<'_>,
358 class_id: Option<ClassId>,
359 ) -> Option<SecurityContext> {
360 self.0.genfscon_label_for_fs_and_path(fs_type, node_path, class_id)
361 }
362
363 pub fn initial_context(&self, id: sc::InitialSid) -> security_context::SecurityContext {
366 self.0.initial_context(id)
367 }
368
369 pub fn parse_security_context(
371 &self,
372 security_context: sc::NullessByteStr<'_>,
373 ) -> Result<security_context::SecurityContext, security_context::SecurityContextError> {
374 security_context::SecurityContext::parse(&self.0, security_context)
375 }
376
377 pub fn validate_security_context(
379 &self,
380 security_context: &SecurityContext,
381 ) -> Result<(), SecurityContextError> {
382 security_context.validate(&self.0)
383 }
384
385 pub fn serialize_security_context(&self, security_context: &SecurityContext) -> Vec<u8> {
387 security_context.serialize(&self.0)
388 }
389
390 pub fn compute_create_context_with_name(
398 &self,
399 source: &SecurityContext,
400 target: &SecurityContext,
401 class: impl Into<sc::ObjectClass>,
402 name: sc::NullessByteStr<'_>,
403 ) -> Option<SecurityContext> {
404 self.0.compute_create_context_with_name(source, target, class.into(), name)
405 }
406
407 pub fn compute_create_context(
425 &self,
426 source: &SecurityContext,
427 target: &SecurityContext,
428 class: impl Into<sc::ObjectClass>,
429 ) -> SecurityContext {
430 self.0.compute_create_context(source, target, class.into())
431 }
432
433 pub fn compute_access_decision(
449 &self,
450 source_context: &SecurityContext,
451 target_context: &SecurityContext,
452 object_class: impl Into<sc::ObjectClass>,
453 ) -> AccessDecision {
454 if let Some(target_class) = self.0.class(object_class.into()) {
455 self.0.parsed_policy().compute_access_decision(
456 source_context,
457 target_context,
458 target_class,
459 )
460 } else {
461 AccessDecision::allow(AccessVector::NONE)
462 }
463 }
464
465 pub fn compute_xperms_access_decision(
469 &self,
470 xperms_kind: XpermsKind,
471 source_context: &SecurityContext,
472 target_context: &SecurityContext,
473 object_class: impl Into<sc::ObjectClass>,
474 xperms_prefix: u8,
475 ) -> XpermsAccessDecision {
476 if let Some(target_class) = self.0.class(object_class.into()) {
477 self.0.parsed_policy().compute_xperms_access_decision(
478 xperms_kind,
479 source_context,
480 target_context,
481 target_class,
482 xperms_prefix,
483 )
484 } else {
485 XpermsAccessDecision::DENY_ALL
486 }
487 }
488
489 pub fn is_bounded_by(&self, bounded_type: TypeId, parent_type: TypeId) -> bool {
490 let type_ = self.0.parsed_policy().type_(bounded_type);
491 type_.bounded_by() == Some(parent_type)
492 }
493
494 pub fn is_permissive(&self, type_: TypeId) -> bool {
496 self.0.parsed_policy().permissive_types().is_set(type_.0.get())
497 }
498}
499
500impl AccessVectorComputer for Policy {
501 fn access_vector_from_permissions<
502 P: sc::ClassPermission + Into<sc::KernelPermission> + Clone + 'static,
503 >(
504 &self,
505 permissions: &[P],
506 ) -> Option<AccessVector> {
507 let mut access_vector = AccessVector::NONE;
508 for permission in permissions {
509 if let Some(permission_info) = self.0.permission(&permission.clone().into()) {
510 access_vector |= AccessVector::from_class_permission_id(permission_info.id());
512 } else {
513 if self.0.parsed_policy().handle_unknown() != HandleUnknown::Allow {
515 return None;
516 }
517 }
518 }
519 Some(access_vector)
520 }
521}
522
523pub struct Unvalidated(ParsedPolicy);
525
526impl Unvalidated {
527 pub fn validate(self) -> Result<Policy, anyhow::Error> {
528 self.0.validate().context("validating parsed policy")?;
529 let index = PolicyIndex::new(self.0).context("building index")?;
530 Ok(Policy(index))
531 }
532}
533
534pub trait AccessVectorComputer {
537 fn access_vector_from_permissions<
544 P: sc::ClassPermission + Into<sc::KernelPermission> + Clone + 'static,
545 >(
546 &self,
547 permissions: &[P],
548 ) -> Option<AccessVector>;
549}
550
551pub trait Parse: Sized {
553 type Error: Into<anyhow::Error>;
556
557 fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error>;
560}
561
562pub(super) trait ParseSlice: Sized {
564 type Error: Into<anyhow::Error>;
567
568 fn parse_slice(bytes: PolicyCursor, count: usize) -> Result<(Self, PolicyCursor), Self::Error>;
571}
572
573pub(super) struct PolicyValidationContext {
575 #[allow(unused)]
577 pub(super) data: PolicyData,
578}
579
580pub(super) trait Validate {
582 type Error: Into<anyhow::Error>;
585
586 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error>;
588}
589
590pub(super) trait ValidateArray<M, D> {
591 type Error: Into<anyhow::Error>;
594
595 fn validate_array(
597 context: &mut PolicyValidationContext,
598 metadata: &M,
599 items: &[D],
600 ) -> Result<(), Self::Error>;
601}
602
603pub(super) trait Counted {
605 fn count(&self) -> u32;
607}
608
609impl<T: Validate> Validate for Option<T> {
610 type Error = <T as Validate>::Error;
611
612 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
613 match self {
614 Some(value) => value.validate(context),
615 None => Ok(()),
616 }
617 }
618}
619
620impl Validate for le::U32 {
621 type Error = anyhow::Error;
622
623 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
626 Ok(())
627 }
628}
629
630impl Validate for u8 {
631 type Error = anyhow::Error;
632
633 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
636 Ok(())
637 }
638}
639
640impl Validate for [u8] {
641 type Error = anyhow::Error;
642
643 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
646 Ok(())
647 }
648}
649
650impl<B: SplitByteSlice, T: Validate + FromBytes + KnownLayout + Immutable> Validate for Ref<B, T> {
651 type Error = <T as Validate>::Error;
652
653 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
654 self.deref().validate(context)
655 }
656}
657
658impl<B: SplitByteSlice, T: Counted + FromBytes + KnownLayout + Immutable> Counted for Ref<B, T> {
659 fn count(&self) -> u32 {
660 self.deref().count()
661 }
662}
663
664#[derive(Clone, Debug, PartialEq)]
667struct Array<M, D> {
668 metadata: M,
669 data: D,
670}
671
672impl<M: Counted + Parse, D: ParseSlice> Parse for Array<M, D> {
673 type Error = anyhow::Error;
676
677 fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
679 let tail = bytes;
680
681 let (metadata, tail) = M::parse(tail).map_err(Into::<anyhow::Error>::into)?;
682
683 let (data, tail) =
684 D::parse_slice(tail, metadata.count() as usize).map_err(Into::<anyhow::Error>::into)?;
685
686 let array = Self { metadata, data };
687
688 Ok((array, tail))
689 }
690}
691
692impl<T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned> Parse for T {
693 type Error = anyhow::Error;
694
695 fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
696 let num_bytes = bytes.len();
697 let (data, tail) =
698 PolicyCursor::parse::<T>(bytes).ok_or_else(|| ParseError::MissingData {
699 type_name: std::any::type_name::<T>(),
700 type_size: std::mem::size_of::<T>(),
701 num_bytes,
702 })?;
703
704 Ok((data, tail))
705 }
706}
707
708macro_rules! array_type {
712 ($type_name:ident, $metadata_type:ty, $data_type:ty, $metadata_type_name:expr, $data_type_name:expr) => {
713 #[doc = "An [`Array`] with [`"]
714 #[doc = $metadata_type_name]
715 #[doc = "`] metadata and [`"]
716 #[doc = $data_type_name]
717 #[doc = "`] data items."]
718 #[derive(Debug, PartialEq)]
719 pub(super) struct $type_name(crate::policy::Array<$metadata_type, $data_type>);
720
721 impl std::ops::Deref for $type_name {
722 type Target = crate::policy::Array<$metadata_type, $data_type>;
723
724 fn deref(&self) -> &Self::Target {
725 &self.0
726 }
727 }
728
729 impl crate::policy::Parse for $type_name
730 where
731 crate::policy::Array<$metadata_type, $data_type>: crate::policy::Parse,
732 {
733 type Error = <Array<$metadata_type, $data_type> as crate::policy::Parse>::Error;
734
735 fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
736 let (array, tail) = Array::<$metadata_type, $data_type>::parse(bytes)?;
737 Ok((Self(array), tail))
738 }
739 }
740 };
741
742 ($type_name:ident, $metadata_type:ty, $data_type:ty) => {
743 array_type!(
744 $type_name,
745 $metadata_type,
746 $data_type,
747 stringify!($metadata_type),
748 stringify!($data_type)
749 );
750 };
751}
752
753pub(super) use array_type;
754
755macro_rules! array_type_validate_deref_both {
756 ($type_name:ident) => {
757 impl Validate for $type_name {
758 type Error = anyhow::Error;
759
760 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
761 let metadata = &self.metadata;
762 metadata.validate(context)?;
763
764 let items = &self.data;
765 items.validate(context)?;
766
767 Self::validate_array(context, metadata, items).map_err(Into::<anyhow::Error>::into)
768 }
769 }
770 };
771}
772
773pub(super) use array_type_validate_deref_both;
774
775macro_rules! array_type_validate_deref_data {
776 ($type_name:ident) => {
777 impl Validate for $type_name {
778 type Error = anyhow::Error;
779
780 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
781 let metadata = &self.metadata;
782 metadata.validate(context)?;
783
784 let items = &self.data;
785 items.validate(context)?;
786
787 Self::validate_array(context, metadata, items)
788 }
789 }
790 };
791}
792
793pub(super) use array_type_validate_deref_data;
794
795macro_rules! array_type_validate_deref_metadata_data_vec {
796 ($type_name:ident) => {
797 impl Validate for $type_name {
798 type Error = anyhow::Error;
799
800 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
801 let metadata = &self.metadata;
802 metadata.validate(context)?;
803
804 let items = &self.data;
805 items.validate(context)?;
806
807 Self::validate_array(context, metadata, items.as_slice())
808 }
809 }
810 };
811}
812
813pub(super) use array_type_validate_deref_metadata_data_vec;
814
815macro_rules! array_type_validate_deref_none_data_vec {
816 ($type_name:ident) => {
817 impl Validate for $type_name {
818 type Error = anyhow::Error;
819
820 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
821 let metadata = &self.metadata;
822 metadata.validate(context)?;
823
824 let items = &self.data;
825 items.validate(context)?;
826
827 Self::validate_array(context, metadata, items.as_slice())
828 }
829 }
830 };
831}
832
833pub(super) use array_type_validate_deref_none_data_vec;
834
835impl<T: Parse> ParseSlice for Vec<T> {
836 type Error = anyhow::Error;
839
840 fn parse_slice(bytes: PolicyCursor, count: usize) -> Result<(Self, PolicyCursor), Self::Error> {
842 let mut slice = Vec::with_capacity(count);
843 let mut tail = bytes;
844
845 for _ in 0..count {
846 let (item, next_tail) = T::parse(tail).map_err(Into::<anyhow::Error>::into)?;
847 slice.push(item);
848 tail = next_tail;
849 }
850
851 Ok((slice, tail))
852 }
853}
854
855#[cfg(test)]
856pub(super) mod testing {
857 use crate::policy::error::ValidateError;
858 use crate::policy::{AccessVector, ParseError};
859
860 pub const ACCESS_VECTOR_0001: AccessVector = AccessVector(0b0001u32);
861 pub const ACCESS_VECTOR_0010: AccessVector = AccessVector(0b0010u32);
862
863 pub(super) fn as_parse_error(error: anyhow::Error) -> ParseError {
865 error.downcast::<ParseError>().expect("parse error")
866 }
867
868 pub(super) fn as_validate_error(error: anyhow::Error) -> ValidateError {
870 error.downcast::<ValidateError>().expect("validate error")
871 }
872}
873
874#[cfg(test)]
875pub(super) mod tests {
876 use super::*;
877
878 use crate::policy::metadata::HandleUnknown;
879 use crate::policy::{SecurityContext, parse_policy_by_value};
880 use crate::{FileClass, InitialSid, KernelClass};
881
882 use serde::Deserialize;
883 use std::ops::Shl;
884
885 fn is_explicitly_allowed(
893 policy: &Policy,
894 source_type: TypeId,
895 target_type: TypeId,
896 target_class: &str,
897 permission: &str,
898 ) -> bool {
899 let class = policy
900 .0
901 .parsed_policy()
902 .classes()
903 .iter()
904 .find(|class| class.name_bytes() == target_class.as_bytes())
905 .expect("class not found");
906 let class_permissions = policy
907 .find_class_permissions_by_name(target_class)
908 .expect("class permissions not found");
909 let (permission_id, _) = class_permissions
910 .iter()
911 .find(|(_, name)| permission.as_bytes() == name)
912 .expect("permission not found");
913 let permission_bit = AccessVector::from_class_permission_id(*permission_id);
914 let access_decision =
915 policy.0.parsed_policy().compute_explicitly_allowed(source_type, target_type, class);
916 permission_bit == access_decision.allow & permission_bit
917 }
918
919 #[derive(Debug, Deserialize)]
920 struct Expectations {
921 expected_policy_version: u32,
922 expected_handle_unknown: LocalHandleUnknown,
923 }
924
925 #[derive(Debug, Deserialize, PartialEq)]
926 #[serde(rename_all = "snake_case")]
927 enum LocalHandleUnknown {
928 Deny,
929 Reject,
930 Allow,
931 }
932
933 impl PartialEq<HandleUnknown> for LocalHandleUnknown {
934 fn eq(&self, other: &HandleUnknown) -> bool {
935 match self {
936 LocalHandleUnknown::Deny => *other == HandleUnknown::Deny,
937 LocalHandleUnknown::Reject => *other == HandleUnknown::Reject,
938 LocalHandleUnknown::Allow => *other == HandleUnknown::Allow,
939 }
940 }
941 }
942
943 fn xperms_bitmap_from_elements(elements: &[u8]) -> XpermsBitmap {
946 let mut bitmap = [le::U32::ZERO; 8];
947 for element in elements.iter() {
948 let block_index = (*element as usize) / 32;
949 let bit_index = ((*element as usize) % 32) as u32;
950 let bitmask = le::U32::new(1).shl(bit_index);
951 bitmap[block_index] = bitmap[block_index] | bitmask;
952 }
953 XpermsBitmap::new(bitmap)
954 }
955
956 #[test]
957 fn known_policies() {
958 let policies_and_expectations = [
959 [
960 b"testdata/policies/emulator".to_vec(),
961 include_bytes!("../../testdata/policies/emulator").to_vec(),
962 include_bytes!("../../testdata/expectations/emulator").to_vec(),
963 ],
964 [
965 b"testdata/policies/selinux_testsuite".to_vec(),
966 include_bytes!("../../testdata/policies/selinux_testsuite").to_vec(),
967 include_bytes!("../../testdata/expectations/selinux_testsuite").to_vec(),
968 ],
969 ];
970
971 for [policy_path, policy_bytes, expectations_bytes] in policies_and_expectations {
972 let expectations = serde_json5::from_reader::<_, Expectations>(
973 &mut std::io::Cursor::new(expectations_bytes),
974 )
975 .expect("deserialize expectations");
976
977 let unvalidated_policy =
980 parse_policy_by_value(policy_bytes.clone()).expect("parse policy");
981
982 let policy = unvalidated_policy
983 .validate()
984 .with_context(|| {
985 format!(
986 "policy path: {:?}",
987 std::str::from_utf8(policy_path.as_slice()).unwrap()
988 )
989 })
990 .expect("validate policy");
991
992 assert_eq!(expectations.expected_policy_version, policy.policy_version());
993 assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
994
995 let binary_policy = policy.binary().clone();
997 assert_eq!(&policy_bytes, binary_policy.deref());
998 }
999 }
1000
1001 #[test]
1002 fn policy_lookup() {
1003 let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
1004 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1005 let policy = policy.validate().expect("validate selinux testsuite policy");
1006
1007 let unconfined_t = policy.type_id_by_name("unconfined_t").expect("look up type id");
1008
1009 assert!(is_explicitly_allowed(&policy, unconfined_t, unconfined_t, "process", "fork",));
1010 }
1011
1012 #[test]
1013 fn initial_contexts() {
1014 let policy_bytes = include_bytes!(
1015 "../../testdata/micro_policies/multiple_levels_and_categories_policy.pp"
1016 );
1017 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1018 let policy = policy.validate().expect("validate policy");
1019
1020 let kernel_context = policy.initial_context(InitialSid::Kernel);
1021 assert_eq!(
1022 policy.serialize_security_context(&kernel_context),
1023 b"user0:object_r:type0:s0:c0-s1:c0.c2,c4"
1024 )
1025 }
1026
1027 #[test]
1028 fn explicit_allow_type_type() {
1029 let policy_bytes =
1030 include_bytes!("../../testdata/micro_policies/allow_a_t_b_t_class0_perm0_policy.pp");
1031 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1032 let policy = policy.validate().expect("validate policy");
1033
1034 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1035 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1036
1037 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1038 }
1039
1040 #[test]
1041 fn no_explicit_allow_type_type() {
1042 let policy_bytes =
1043 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_t_class0_perm0_policy.pp");
1044 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1045 let policy = policy.validate().expect("validate policy");
1046
1047 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1048 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1049
1050 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1051 }
1052
1053 #[test]
1054 fn explicit_allow_type_attr() {
1055 let policy_bytes =
1056 include_bytes!("../../testdata/micro_policies/allow_a_t_b_attr_class0_perm0_policy.pp");
1057 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1058 let policy = policy.validate().expect("validate policy");
1059
1060 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1061 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1062
1063 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1064 }
1065
1066 #[test]
1067 fn no_explicit_allow_type_attr() {
1068 let policy_bytes = include_bytes!(
1069 "../../testdata/micro_policies/no_allow_a_t_b_attr_class0_perm0_policy.pp"
1070 );
1071 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1072 let policy = policy.validate().expect("validate policy");
1073
1074 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1075 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1076
1077 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1078 }
1079
1080 #[test]
1081 fn explicit_allow_attr_attr() {
1082 let policy_bytes = include_bytes!(
1083 "../../testdata/micro_policies/allow_a_attr_b_attr_class0_perm0_policy.pp"
1084 );
1085 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1086 let policy = policy.validate().expect("validate policy");
1087
1088 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1089 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1090
1091 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1092 }
1093
1094 #[test]
1095 fn no_explicit_allow_attr_attr() {
1096 let policy_bytes = include_bytes!(
1097 "../../testdata/micro_policies/no_allow_a_attr_b_attr_class0_perm0_policy.pp"
1098 );
1099 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1100 let policy = policy.validate().expect("validate policy");
1101
1102 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1103 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1104
1105 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1106 }
1107
1108 #[test]
1109 fn compute_explicitly_allowed_multiple_attributes() {
1110 let policy_bytes = include_bytes!(
1111 "../../testdata/micro_policies/allow_a_t_a1_attr_class0_perm0_a2_attr_class0_perm1_policy.pp"
1112 );
1113 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1114 let policy = policy.validate().expect("validate policy");
1115
1116 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1117
1118 let class = policy
1119 .0
1120 .parsed_policy()
1121 .classes()
1122 .iter()
1123 .find(|class| class.name_bytes() == b"class0")
1124 .expect("class not found");
1125 let raw_access_vector =
1126 policy.0.parsed_policy().compute_explicitly_allowed(a_t, a_t, class).allow.0;
1127
1128 assert_eq!(2, raw_access_vector.count_ones());
1133 }
1134
1135 #[test]
1136 fn compute_access_decision_with_constraints() {
1137 let policy_bytes =
1138 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1139 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1140 let policy = policy.validate().expect("validate policy");
1141
1142 let source_context: SecurityContext = policy
1143 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1144 .expect("create source security context");
1145
1146 let target_context_satisfied: SecurityContext = source_context.clone();
1147 let decision_satisfied = policy.compute_access_decision(
1148 &source_context,
1149 &target_context_satisfied,
1150 KernelClass::File,
1151 );
1152 assert_eq!(decision_satisfied.allow, AccessVector(7));
1156
1157 let target_context_unsatisfied: SecurityContext = policy
1158 .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1159 .expect("create target security context failing some constraints");
1160 let decision_unsatisfied = policy.compute_access_decision(
1161 &source_context,
1162 &target_context_unsatisfied,
1163 KernelClass::File,
1164 );
1165 assert_eq!(decision_unsatisfied.allow, AccessVector(4));
1168 }
1169
1170 #[test]
1171 fn compute_ioctl_access_decision_explicitly_allowed() {
1172 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1173 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1174 let policy = policy.validate().expect("validate policy");
1175
1176 let source_context: SecurityContext = policy
1177 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1178 .expect("create source security context");
1179 let target_context_matched: SecurityContext = source_context.clone();
1180
1181 let decision_single = policy.compute_xperms_access_decision(
1199 XpermsKind::Ioctl,
1200 &source_context,
1201 &target_context_matched,
1202 KernelClass::File,
1203 0xab,
1204 );
1205
1206 let mut expected_auditdeny =
1207 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1208 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1209
1210 let expected_decision_single = XpermsAccessDecision {
1211 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1212 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1213 auditdeny: expected_auditdeny,
1214 };
1215 assert_eq!(decision_single, expected_decision_single);
1216
1217 let decision_range = policy.compute_xperms_access_decision(
1218 XpermsKind::Ioctl,
1219 &source_context,
1220 &target_context_matched,
1221 KernelClass::File,
1222 0x10,
1223 );
1224 let expected_decision_range = XpermsAccessDecision {
1225 allow: XpermsBitmap::ALL,
1226 auditallow: XpermsBitmap::ALL,
1227 auditdeny: XpermsBitmap::NONE,
1228 };
1229 assert_eq!(decision_range, expected_decision_range);
1230 }
1231
1232 #[test]
1233 fn compute_ioctl_access_decision_unmatched() {
1234 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1235 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1236 let policy = policy.validate().expect("validate policy");
1237
1238 let source_context: SecurityContext = policy
1239 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1240 .expect("create source security context");
1241
1242 let target_context_unmatched: SecurityContext = policy
1244 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1245 .expect("create source security context");
1246
1247 for prefix in 0x0..=0xff {
1248 let decision = policy.compute_xperms_access_decision(
1249 XpermsKind::Ioctl,
1250 &source_context,
1251 &target_context_unmatched,
1252 KernelClass::File,
1253 prefix,
1254 );
1255 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1256 }
1257 }
1258
1259 #[test]
1260 fn compute_nlmsg_access_decision_explicitly_allowed() {
1261 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1262 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1263 let policy = policy.validate().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 let target_context_matched: SecurityContext = source_context.clone();
1269
1270 let decision_single = policy.compute_xperms_access_decision(
1288 XpermsKind::Nlmsg,
1289 &source_context,
1290 &target_context_matched,
1291 KernelClass::NetlinkRouteSocket,
1292 0xab,
1293 );
1294
1295 let mut expected_auditdeny =
1296 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1297 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1298
1299 let expected_decision_single = XpermsAccessDecision {
1300 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1301 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1302 auditdeny: expected_auditdeny,
1303 };
1304 assert_eq!(decision_single, expected_decision_single);
1305
1306 let decision_range = policy.compute_xperms_access_decision(
1307 XpermsKind::Nlmsg,
1308 &source_context,
1309 &target_context_matched,
1310 KernelClass::NetlinkRouteSocket,
1311 0x10,
1312 );
1313 let expected_decision_range = XpermsAccessDecision {
1314 allow: XpermsBitmap::ALL,
1315 auditallow: XpermsBitmap::ALL,
1316 auditdeny: XpermsBitmap::NONE,
1317 };
1318 assert_eq!(decision_range, expected_decision_range);
1319 }
1320
1321 #[test]
1322 fn compute_nlmsg_access_decision_unmatched() {
1323 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1324 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1325 let policy = policy.validate().expect("validate policy");
1326
1327 let source_context: SecurityContext = policy
1328 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1329 .expect("create source security context");
1330
1331 let target_context_unmatched: SecurityContext = policy
1333 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1334 .expect("create source security context");
1335
1336 for prefix in 0x0..=0xff {
1337 let decision = policy.compute_xperms_access_decision(
1338 XpermsKind::Nlmsg,
1339 &source_context,
1340 &target_context_unmatched,
1341 KernelClass::NetlinkRouteSocket,
1342 prefix,
1343 );
1344 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1345 }
1346 }
1347
1348 #[test]
1349 fn compute_create_context_minimal() {
1350 let policy_bytes =
1351 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1352 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1353 let policy = policy.validate().expect("validate policy");
1354 let source = policy
1355 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1356 .expect("valid source security context");
1357 let target = policy
1358 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1359 .expect("valid target security context");
1360
1361 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1362 let expected: SecurityContext = policy
1363 .parse_security_context(b"source_u:object_r:target_t:s0:c0".into())
1364 .expect("valid expected security context");
1365
1366 assert_eq!(expected, actual);
1367 }
1368
1369 #[test]
1370 fn new_security_context_minimal() {
1371 let policy_bytes =
1372 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1373 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1374 let policy = policy.validate().expect("validate policy");
1375 let source = policy
1376 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1377 .expect("valid source security context");
1378 let target = policy
1379 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1380 .expect("valid target security context");
1381
1382 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1383
1384 assert_eq!(source, actual);
1385 }
1386
1387 #[test]
1388 fn compute_create_context_class_defaults() {
1389 let policy_bytes =
1390 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1391 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1392 let policy = policy.validate().expect("validate policy");
1393 let source = policy
1394 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1395 .expect("valid source security context");
1396 let target = policy
1397 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1398 .expect("valid target security context");
1399
1400 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1401 let expected: SecurityContext = policy
1402 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1403 .expect("valid expected security context");
1404
1405 assert_eq!(expected, actual);
1406 }
1407
1408 #[test]
1409 fn new_security_context_class_defaults() {
1410 let policy_bytes =
1411 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1412 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1413 let policy = policy.validate().expect("validate policy");
1414 let source = policy
1415 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1416 .expect("valid source security context");
1417 let target = policy
1418 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1419 .expect("valid target security context");
1420
1421 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1422 let expected: SecurityContext = policy
1423 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1424 .expect("valid expected security context");
1425
1426 assert_eq!(expected, actual);
1427 }
1428
1429 #[test]
1430 fn compute_create_context_role_transition() {
1431 let policy_bytes =
1432 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
1433 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1434 let policy = policy.validate().expect("validate policy");
1435 let source = policy
1436 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1437 .expect("valid source security context");
1438 let target = policy
1439 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1440 .expect("valid target security context");
1441
1442 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1443 let expected: SecurityContext = policy
1444 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
1445 .expect("valid expected security context");
1446
1447 assert_eq!(expected, actual);
1448 }
1449
1450 #[test]
1451 fn new_security_context_role_transition() {
1452 let policy_bytes =
1453 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
1454 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1455 let policy = policy.validate().expect("validate policy");
1456 let source = policy
1457 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1458 .expect("valid source security context");
1459 let target = policy
1460 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1461 .expect("valid target security context");
1462
1463 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1464 let expected: SecurityContext = policy
1465 .parse_security_context(b"source_u:transition_r:source_t:s0:c0-s2:c0.c1".into())
1466 .expect("valid expected security context");
1467
1468 assert_eq!(expected, actual);
1469 }
1470
1471 #[test]
1472 #[ignore]
1474 fn compute_create_context_role_transition_not_allowed() {
1475 let policy_bytes = include_bytes!(
1476 "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy.pp"
1477 );
1478 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1479 let policy = policy.validate().expect("validate policy");
1480 let source = policy
1481 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1482 .expect("valid source security context");
1483 let target = policy
1484 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1485 .expect("valid target security context");
1486
1487 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1488
1489 assert!(policy.validate_security_context(&actual).is_err());
1491 }
1492
1493 #[test]
1494 fn compute_create_context_type_transition() {
1495 let policy_bytes =
1496 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
1497 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1498 let policy = policy.validate().expect("validate policy");
1499 let source = policy
1500 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1501 .expect("valid source security context");
1502 let target = policy
1503 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1504 .expect("valid target security context");
1505
1506 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1507 let expected: SecurityContext = policy
1508 .parse_security_context(b"source_u:object_r:transition_t:s0:c0".into())
1509 .expect("valid expected security context");
1510
1511 assert_eq!(expected, actual);
1512 }
1513
1514 #[test]
1515 fn new_security_context_type_transition() {
1516 let policy_bytes =
1517 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
1518 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1519 let policy = policy.validate().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.compute_create_context(&source, &target, KernelClass::Process);
1528 let expected: SecurityContext = policy
1529 .parse_security_context(b"source_u:source_r:transition_t:s0:c0-s2:c0.c1".into())
1530 .expect("valid expected security context");
1531
1532 assert_eq!(expected, actual);
1533 }
1534
1535 #[test]
1536 fn compute_create_context_range_transition() {
1537 let policy_bytes =
1538 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
1539 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1540 let policy = policy.validate().expect("validate policy");
1541 let source = policy
1542 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1543 .expect("valid source security context");
1544 let target = policy
1545 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1546 .expect("valid target security context");
1547
1548 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1549 let expected: SecurityContext = policy
1550 .parse_security_context(b"source_u:object_r:target_t:s1:c1-s2:c1.c2".into())
1551 .expect("valid expected security context");
1552
1553 assert_eq!(expected, actual);
1554 }
1555
1556 #[test]
1557 fn new_security_context_range_transition() {
1558 let policy_bytes =
1559 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
1560 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1561 let policy = policy.validate().expect("validate policy");
1562 let source = policy
1563 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1564 .expect("valid source security context");
1565 let target = policy
1566 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1567 .expect("valid target security context");
1568
1569 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1570 let expected: SecurityContext = policy
1571 .parse_security_context(b"source_u:source_r:source_t:s1:c1-s2:c1.c2".into())
1572 .expect("valid expected security context");
1573
1574 assert_eq!(expected, actual);
1575 }
1576
1577 #[test]
1578 fn access_vector_formats() {
1579 assert_eq!(format!("{:x}", AccessVector::NONE), "0");
1580 assert_eq!(format!("{:x}", AccessVector::ALL), "ffffffff");
1581 assert_eq!(format!("{:?}", AccessVector::NONE), "AccessVector(00000000)");
1582 assert_eq!(format!("{:?}", AccessVector::ALL), "AccessVector(ffffffff)");
1583 }
1584}