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