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::{
24 ClassPermission, KernelClass, KernelPermission, NullessByteStr, ObjectClass, PolicyCap,
25};
26use index::PolicyIndex;
27use metadata::HandleUnknown;
28use parsed_policy::ParsedPolicy;
29use parser::PolicyData;
30use symbols::{find_class_by_name, find_common_symbol_by_name_bytes};
31
32use anyhow::Context as _;
33use std::fmt::{Debug, Display, LowerHex};
34use std::num::{NonZeroU8, NonZeroU32, NonZeroU64};
35use std::ops::Deref;
36use std::str::FromStr;
37use std::sync::Arc;
38use zerocopy::{
39 FromBytes, Immutable, KnownLayout, Ref, SplitByteSlice, Unaligned, little_endian as le,
40};
41
42#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
44pub struct UserId(NonZeroU32);
45
46#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
48pub struct RoleId(NonZeroU32);
49
50#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
52pub struct TypeId(NonZeroU32);
53
54#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
56pub struct SensitivityId(NonZeroU32);
57
58#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
60pub struct CategoryId(NonZeroU32);
61
62#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
65pub struct ClassId(NonZeroU32);
66
67impl ClassId {
68 pub fn new(id: NonZeroU32) -> Self {
70 Self(id)
71 }
72}
73
74impl Into<u32> for ClassId {
75 fn into(self) -> u32 {
76 self.0.into()
77 }
78}
79
80#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
82pub struct ClassPermissionId(NonZeroU8);
83
84impl Display for ClassPermissionId {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 write!(f, "{}", self.0)
87 }
88}
89
90#[derive(Debug, Clone, PartialEq)]
95pub struct AccessDecision {
96 pub allow: AccessVector,
97 pub auditallow: AccessVector,
98 pub auditdeny: AccessVector,
99 pub flags: u32,
100
101 pub todo_bug: Option<NonZeroU64>,
104}
105
106impl Default for AccessDecision {
107 fn default() -> Self {
108 Self::allow(AccessVector::NONE)
109 }
110}
111
112impl AccessDecision {
113 pub(super) const fn allow(allow: AccessVector) -> Self {
116 Self {
117 allow,
118 auditallow: AccessVector::NONE,
119 auditdeny: AccessVector::ALL,
120 flags: 0,
121 todo_bug: None,
122 }
123 }
124}
125
126pub(super) const SELINUX_AVD_FLAGS_PERMISSIVE: u32 = 1;
128
129#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
132pub struct AccessVector(u32);
133
134impl AccessVector {
135 pub const NONE: AccessVector = AccessVector(0);
136 pub const ALL: AccessVector = AccessVector(std::u32::MAX);
137
138 pub(super) fn from_class_permission_id(id: ClassPermissionId) -> Self {
139 Self((1 as u32) << (id.0.get() - 1))
140 }
141}
142
143impl Debug for AccessVector {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 write!(f, "AccessVector({:0>8x})", self)
146 }
147}
148
149impl FromStr for AccessVector {
150 type Err = <u32 as FromStr>::Err;
151
152 fn from_str(value: &str) -> Result<Self, Self::Err> {
153 Ok(AccessVector(u32::from_str_radix(value, 16)?))
155 }
156}
157
158impl LowerHex for AccessVector {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 LowerHex::fmt(&self.0, f)
161 }
162}
163
164impl std::ops::BitAnd for AccessVector {
165 type Output = Self;
166
167 fn bitand(self, rhs: Self) -> Self::Output {
168 AccessVector(self.0 & rhs.0)
169 }
170}
171
172impl std::ops::BitOr for AccessVector {
173 type Output = Self;
174
175 fn bitor(self, rhs: Self) -> Self::Output {
176 AccessVector(self.0 | rhs.0)
177 }
178}
179
180impl std::ops::BitAndAssign for AccessVector {
181 fn bitand_assign(&mut self, rhs: Self) {
182 self.0 &= rhs.0
183 }
184}
185
186impl std::ops::BitOrAssign for AccessVector {
187 fn bitor_assign(&mut self, rhs: Self) {
188 self.0 |= rhs.0
189 }
190}
191
192impl std::ops::SubAssign for AccessVector {
193 fn sub_assign(&mut self, rhs: Self) {
194 self.0 = self.0 ^ (self.0 & rhs.0);
195 }
196}
197
198impl std::ops::Sub for AccessVector {
199 type Output = Self;
200
201 fn sub(self, rhs: Self) -> Self::Output {
202 AccessVector(self.0 ^ (self.0 & rhs.0))
203 }
204}
205
206#[derive(Clone, Debug, Eq, Hash, PartialEq)]
209pub enum XpermsKind {
210 Ioctl,
211 Nlmsg,
212}
213
214#[derive(Debug, Clone, PartialEq)]
219pub struct XpermsAccessDecision {
220 pub allow: XpermsBitmap,
221 pub auditallow: XpermsBitmap,
222 pub auditdeny: XpermsBitmap,
223}
224
225impl XpermsAccessDecision {
226 pub const DENY_ALL: Self = Self {
227 allow: XpermsBitmap::NONE,
228 auditallow: XpermsBitmap::NONE,
229 auditdeny: XpermsBitmap::ALL,
230 };
231 pub const ALLOW_ALL: Self = Self {
232 allow: XpermsBitmap::ALL,
233 auditallow: XpermsBitmap::NONE,
234 auditdeny: XpermsBitmap::ALL,
235 };
236}
237
238pub fn parse_policy_by_value(binary_policy: Vec<u8>) -> Result<Unvalidated, anyhow::Error> {
247 let policy_data = Arc::new(binary_policy);
248 let policy = ParsedPolicy::parse(policy_data).context("parsing policy")?;
249 Ok(Unvalidated(policy))
250}
251
252pub struct ClassInfo {
254 pub class_name: Box<[u8]>,
256 pub class_id: ClassId,
258}
259
260#[derive(Debug)]
261pub struct Policy(PolicyIndex);
262
263impl Policy {
264 pub fn policy_version(&self) -> u32 {
266 self.0.parsed_policy().policy_version()
267 }
268
269 pub fn binary(&self) -> &PolicyData {
270 &self.0.parsed_policy().data
271 }
272
273 pub fn handle_unknown(&self) -> HandleUnknown {
276 self.0.parsed_policy().handle_unknown()
277 }
278
279 pub fn conditional_booleans<'a>(&'a self) -> Vec<(&'a [u8], bool)> {
280 self.0
281 .parsed_policy()
282 .conditional_booleans()
283 .iter()
284 .map(|boolean| (boolean.data.as_slice(), boolean.metadata.active()))
285 .collect()
286 }
287
288 pub fn classes(&self) -> Vec<ClassInfo> {
290 self.0
291 .parsed_policy()
292 .classes()
293 .into_iter()
294 .map(|class| ClassInfo {
295 class_name: Box::<[u8]>::from(class.name_bytes()),
296 class_id: class.id(),
297 })
298 .collect()
299 }
300
301 pub(super) fn type_id_by_name(&self, name: &str) -> Option<TypeId> {
303 self.0.parsed_policy().type_id_by_name(name)
304 }
305
306 pub fn find_class_permissions_by_name(
311 &self,
312 class_name: &str,
313 ) -> Result<Vec<(ClassPermissionId, Vec<u8>)>, ()> {
314 let classes = self.0.parsed_policy().classes();
315 let class = find_class_by_name(&classes, class_name).ok_or(())?;
316 let owned_permissions = class.permissions();
317
318 let mut result: Vec<_> = owned_permissions
319 .iter()
320 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
321 .collect();
322
323 if class.common_name_bytes().is_empty() {
325 return Ok(result);
326 }
327
328 let common_symbol_permissions = find_common_symbol_by_name_bytes(
329 self.0.parsed_policy().common_symbols(),
330 class.common_name_bytes(),
331 )
332 .ok_or(())?
333 .permissions();
334
335 result.append(
336 &mut common_symbol_permissions
337 .iter()
338 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
339 .collect(),
340 );
341
342 Ok(result)
343 }
344
345 pub fn fs_use_label_and_type(&self, fs_type: NullessByteStr<'_>) -> Option<FsUseLabelAndType> {
348 self.0.fs_use_label_and_type(fs_type)
349 }
350
351 pub fn genfscon_label_for_fs_and_path(
354 &self,
355 fs_type: NullessByteStr<'_>,
356 node_path: NullessByteStr<'_>,
357 class_id: Option<KernelClass>,
358 ) -> Option<SecurityContext> {
359 self.0.genfscon_label_for_fs_and_path(fs_type, node_path, class_id)
360 }
361
362 pub fn initial_context(&self, id: crate::InitialSid) -> security_context::SecurityContext {
365 self.0.initial_context(id)
366 }
367
368 pub fn parse_security_context(
370 &self,
371 security_context: NullessByteStr<'_>,
372 ) -> Result<security_context::SecurityContext, security_context::SecurityContextError> {
373 security_context::SecurityContext::parse(&self.0, security_context)
374 }
375
376 pub fn validate_security_context(
378 &self,
379 security_context: &SecurityContext,
380 ) -> Result<(), SecurityContextError> {
381 security_context.validate(&self.0)
382 }
383
384 pub fn serialize_security_context(&self, security_context: &SecurityContext) -> Vec<u8> {
386 security_context.serialize(&self.0)
387 }
388
389 pub fn compute_create_context_with_name(
397 &self,
398 source: &SecurityContext,
399 target: &SecurityContext,
400 class: impl Into<ObjectClass>,
401 name: NullessByteStr<'_>,
402 ) -> Option<SecurityContext> {
403 self.0.compute_create_context_with_name(source, target, class.into(), name)
404 }
405
406 pub fn compute_create_context(
424 &self,
425 source: &SecurityContext,
426 target: &SecurityContext,
427 class: impl Into<ObjectClass>,
428 ) -> SecurityContext {
429 self.0.compute_create_context(source, target, class.into())
430 }
431
432 pub fn compute_access_decision(
448 &self,
449 source_context: &SecurityContext,
450 target_context: &SecurityContext,
451 object_class: impl Into<ObjectClass>,
452 ) -> AccessDecision {
453 if let Some(target_class) = self.0.class(object_class.into()) {
454 self.0.parsed_policy().compute_access_decision(
455 source_context,
456 target_context,
457 &target_class,
458 )
459 } else {
460 AccessDecision::allow(AccessVector::NONE)
461 }
462 }
463
464 pub fn compute_xperms_access_decision(
468 &self,
469 xperms_kind: XpermsKind,
470 source_context: &SecurityContext,
471 target_context: &SecurityContext,
472 object_class: impl Into<ObjectClass>,
473 xperms_prefix: u8,
474 ) -> XpermsAccessDecision {
475 if let Some(target_class) = self.0.class(object_class.into()) {
476 self.0.parsed_policy().compute_xperms_access_decision(
477 xperms_kind,
478 source_context,
479 target_context,
480 &target_class,
481 xperms_prefix,
482 )
483 } else {
484 XpermsAccessDecision::DENY_ALL
485 }
486 }
487
488 pub fn is_bounded_by(&self, bounded_type: TypeId, parent_type: TypeId) -> bool {
489 self.0.parsed_policy().type_(bounded_type).bounded_by() == Some(parent_type)
490 }
491
492 pub fn is_permissive(&self, type_: TypeId) -> bool {
494 self.0.parsed_policy().permissive_types().is_set(type_.0.get())
495 }
496
497 pub fn has_policycap(&self, policy_cap: PolicyCap) -> bool {
499 self.0.parsed_policy().has_policycap(policy_cap)
500 }
501}
502
503impl AccessVectorComputer for Policy {
504 fn kernel_permissions_to_access_vector<
505 P: ClassPermission + Into<KernelPermission> + Clone + 'static,
506 >(
507 &self,
508 permissions: &[P],
509 ) -> Option<AccessVector> {
510 let mut access_vector = AccessVector::NONE;
511 for permission in permissions {
512 if let Some(permission_access_vector) =
513 self.0.kernel_permission_to_access_vector(permission.clone())
514 {
515 access_vector |= permission_access_vector;
516 } else {
517 if self.0.parsed_policy().handle_unknown() != HandleUnknown::Allow {
519 return None;
520 }
521 }
522 }
523 Some(access_vector)
524 }
525}
526
527pub struct Unvalidated(ParsedPolicy);
529
530impl Unvalidated {
531 pub fn validate(self) -> Result<Policy, anyhow::Error> {
532 self.0.validate().context("validating parsed policy")?;
533 let index = PolicyIndex::new(self.0).context("building index")?;
534 Ok(Policy(index))
535 }
536}
537
538pub trait AccessVectorComputer {
541 fn kernel_permissions_to_access_vector<
548 P: ClassPermission + Into<KernelPermission> + Clone + 'static,
549 >(
550 &self,
551 permissions: &[P],
552 ) -> Option<AccessVector>;
553}
554
555pub trait Parse: Sized {
557 type Error: Into<anyhow::Error>;
560
561 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error>;
564}
565
566pub(super) trait ParseSlice: Sized {
568 type Error: Into<anyhow::Error>;
571
572 fn parse_slice<'a>(
575 bytes: PolicyCursor<'a>,
576 count: usize,
577 ) -> Result<(Self, PolicyCursor<'a>), Self::Error>;
578}
579
580pub(super) struct PolicyValidationContext {
582 #[allow(unused)]
584 pub(super) data: PolicyData,
585}
586
587pub(super) trait Validate {
589 type Error: Into<anyhow::Error>;
592
593 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error>;
595}
596
597pub(super) trait ValidateArray<M, D> {
598 type Error: Into<anyhow::Error>;
601
602 fn validate_array(
604 context: &PolicyValidationContext,
605 metadata: &M,
606 items: &[D],
607 ) -> Result<(), Self::Error>;
608}
609
610pub(super) trait Counted {
612 fn count(&self) -> u32;
614}
615
616impl<T: Validate> Validate for Option<T> {
617 type Error = <T as Validate>::Error;
618
619 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
620 match self {
621 Some(value) => value.validate(context),
622 None => Ok(()),
623 }
624 }
625}
626
627impl Validate for le::U32 {
628 type Error = anyhow::Error;
629
630 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
633 Ok(())
634 }
635}
636
637impl Validate for u8 {
638 type Error = anyhow::Error;
639
640 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
643 Ok(())
644 }
645}
646
647impl Validate for [u8] {
648 type Error = anyhow::Error;
649
650 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
653 Ok(())
654 }
655}
656
657impl<B: SplitByteSlice, T: Validate + FromBytes + KnownLayout + Immutable> Validate for Ref<B, T> {
658 type Error = <T as Validate>::Error;
659
660 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
661 self.deref().validate(context)
662 }
663}
664
665impl<B: SplitByteSlice, T: Counted + FromBytes + KnownLayout + Immutable> Counted for Ref<B, T> {
666 fn count(&self) -> u32 {
667 self.deref().count()
668 }
669}
670
671#[derive(Clone, Debug, PartialEq)]
674struct Array<M, D> {
675 metadata: M,
676 data: D,
677}
678
679impl<M: Counted + Parse, D: ParseSlice> Parse for Array<M, D> {
680 type Error = anyhow::Error;
683
684 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
686 let tail = bytes;
687
688 let (metadata, tail) = M::parse(tail).map_err(Into::<anyhow::Error>::into)?;
689
690 let (data, tail) =
691 D::parse_slice(tail, metadata.count() as usize).map_err(Into::<anyhow::Error>::into)?;
692
693 let array = Self { metadata, data };
694
695 Ok((array, tail))
696 }
697}
698
699impl<T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned> Parse for T {
700 type Error = anyhow::Error;
701
702 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
703 bytes.parse::<T>().map_err(anyhow::Error::from)
704 }
705}
706
707macro_rules! array_type {
711 ($type_name:ident, $metadata_type:ty, $data_type:ty, $metadata_type_name:expr, $data_type_name:expr) => {
712 #[doc = "An [`Array`] with [`"]
713 #[doc = $metadata_type_name]
714 #[doc = "`] metadata and [`"]
715 #[doc = $data_type_name]
716 #[doc = "`] data items."]
717 #[derive(Debug, PartialEq)]
718 pub(super) struct $type_name(super::Array<$metadata_type, $data_type>);
719
720 impl std::ops::Deref for $type_name {
721 type Target = super::Array<$metadata_type, $data_type>;
722
723 fn deref(&self) -> &Self::Target {
724 &self.0
725 }
726 }
727
728 impl super::Parse for $type_name
729 where
730 super::Array<$metadata_type, $data_type>: super::Parse,
731 {
732 type Error = <Array<$metadata_type, $data_type> as super::Parse>::Error;
733
734 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
735 let (array, tail) = Array::<$metadata_type, $data_type>::parse(bytes)?;
736 Ok((Self(array), tail))
737 }
738 }
739 };
740
741 ($type_name:ident, $metadata_type:ty, $data_type:ty) => {
742 array_type!(
743 $type_name,
744 $metadata_type,
745 $data_type,
746 stringify!($metadata_type),
747 stringify!($data_type)
748 );
749 };
750}
751
752pub(super) use array_type;
753
754macro_rules! array_type_validate_deref_both {
755 ($type_name:ident) => {
756 impl Validate for $type_name {
757 type Error = anyhow::Error;
758
759 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
760 let metadata = &self.metadata;
761 metadata.validate(context)?;
762
763 let items = &self.data;
764 items.validate(context)?;
765
766 Self::validate_array(context, metadata, items).map_err(Into::<anyhow::Error>::into)
767 }
768 }
769 };
770}
771
772pub(super) use array_type_validate_deref_both;
773
774macro_rules! array_type_validate_deref_data {
775 ($type_name:ident) => {
776 impl Validate for $type_name {
777 type Error = anyhow::Error;
778
779 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
780 let metadata = &self.metadata;
781 metadata.validate(context)?;
782
783 let items = &self.data;
784 items.validate(context)?;
785
786 Self::validate_array(context, metadata, items)
787 }
788 }
789 };
790}
791
792pub(super) use array_type_validate_deref_data;
793
794macro_rules! array_type_validate_deref_metadata_data_vec {
795 ($type_name:ident) => {
796 impl Validate for $type_name {
797 type Error = anyhow::Error;
798
799 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
800 let metadata = &self.metadata;
801 metadata.validate(context)?;
802
803 let items = &self.data;
804 items.validate(context)?;
805
806 Self::validate_array(context, metadata, items.as_slice())
807 }
808 }
809 };
810}
811
812pub(super) use array_type_validate_deref_metadata_data_vec;
813
814macro_rules! array_type_validate_deref_none_data_vec {
815 ($type_name:ident) => {
816 impl Validate for $type_name {
817 type Error = anyhow::Error;
818
819 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
820 let metadata = &self.metadata;
821 metadata.validate(context)?;
822
823 let items = &self.data;
824 items.validate(context)?;
825
826 Self::validate_array(context, metadata, items.as_slice())
827 }
828 }
829 };
830}
831
832pub(super) use array_type_validate_deref_none_data_vec;
833
834impl<T: Parse> ParseSlice for Vec<T> {
835 type Error = anyhow::Error;
838
839 fn parse_slice<'a>(
841 bytes: PolicyCursor<'a>,
842 count: usize,
843 ) -> Result<(Self, PolicyCursor<'a>), 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 super::AccessVector;
860 use super::error::{ParseError, ValidateError};
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::arrays::XpermsBitmap;
879 use super::metadata::HandleUnknown;
880 use super::security_context::SecurityContext;
881 use super::symbols::find_class_by_name;
882 use super::{
883 AccessVector, Policy, TypeId, XpermsAccessDecision, XpermsKind, parse_policy_by_value,
884 };
885 use crate::{FileClass, InitialSid, KernelClass};
886
887 use anyhow::Context as _;
888 use serde::Deserialize;
889 use std::ops::{Deref, Shl};
890 use zerocopy::little_endian as le;
891
892 fn is_explicitly_allowed(
900 policy: &Policy,
901 source_type: TypeId,
902 target_type: TypeId,
903 target_class: &str,
904 permission: &str,
905 ) -> bool {
906 let classes = policy.0.parsed_policy().classes();
907 let class = classes
908 .iter()
909 .find(|class| class.name_bytes() == target_class.as_bytes())
910 .expect("class not found");
911 let class_permissions = policy
912 .find_class_permissions_by_name(target_class)
913 .expect("class permissions not found");
914 let (permission_id, _) = class_permissions
915 .iter()
916 .find(|(_, name)| permission.as_bytes() == name)
917 .expect("permission not found");
918 let permission_bit = AccessVector::from_class_permission_id(*permission_id);
919 let access_decision =
920 policy.0.parsed_policy().compute_explicitly_allowed(source_type, target_type, class);
921 permission_bit == access_decision.allow & permission_bit
922 }
923
924 #[derive(Debug, Deserialize)]
925 struct Expectations {
926 expected_policy_version: u32,
927 expected_handle_unknown: LocalHandleUnknown,
928 }
929
930 #[derive(Debug, Deserialize, PartialEq)]
931 #[serde(rename_all = "snake_case")]
932 enum LocalHandleUnknown {
933 Deny,
934 Reject,
935 Allow,
936 }
937
938 impl PartialEq<HandleUnknown> for LocalHandleUnknown {
939 fn eq(&self, other: &HandleUnknown) -> bool {
940 match self {
941 LocalHandleUnknown::Deny => *other == HandleUnknown::Deny,
942 LocalHandleUnknown::Reject => *other == HandleUnknown::Reject,
943 LocalHandleUnknown::Allow => *other == HandleUnknown::Allow,
944 }
945 }
946 }
947
948 fn xperms_bitmap_from_elements(elements: &[u8]) -> XpermsBitmap {
951 let mut bitmap = [le::U32::ZERO; 8];
952 for element in elements {
953 let block_index = (*element as usize) / 32;
954 let bit_index = ((*element as usize) % 32) as u32;
955 let bitmask = le::U32::new(1).shl(bit_index);
956 bitmap[block_index] = bitmap[block_index] | bitmask;
957 }
958 XpermsBitmap::new(bitmap)
959 }
960
961 #[test]
962 fn known_policies() {
963 let policies_and_expectations = [
964 [
965 b"testdata/policies/emulator".to_vec(),
966 include_bytes!("../../testdata/policies/emulator").to_vec(),
967 include_bytes!("../../testdata/expectations/emulator").to_vec(),
968 ],
969 [
970 b"testdata/policies/selinux_testsuite".to_vec(),
971 include_bytes!("../../testdata/policies/selinux_testsuite").to_vec(),
972 include_bytes!("../../testdata/expectations/selinux_testsuite").to_vec(),
973 ],
974 ];
975
976 for [policy_path, policy_bytes, expectations_bytes] in policies_and_expectations {
977 let expectations = serde_json5::from_reader::<_, Expectations>(
978 &mut std::io::Cursor::new(expectations_bytes),
979 )
980 .expect("deserialize expectations");
981
982 let unvalidated_policy =
985 parse_policy_by_value(policy_bytes.clone()).expect("parse policy");
986
987 let policy = unvalidated_policy
988 .validate()
989 .with_context(|| {
990 format!(
991 "policy path: {:?}",
992 std::str::from_utf8(policy_path.as_slice()).unwrap()
993 )
994 })
995 .expect("validate policy");
996
997 assert_eq!(expectations.expected_policy_version, policy.policy_version());
998 assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
999
1000 let binary_policy = policy.binary().clone();
1002 assert_eq!(&policy_bytes, binary_policy.deref());
1003 }
1004 }
1005
1006 #[test]
1007 fn policy_lookup() {
1008 let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
1009 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1010 let policy = policy.validate().expect("validate selinux testsuite policy");
1011
1012 let unconfined_t = policy.type_id_by_name("unconfined_t").expect("look up type id");
1013
1014 assert!(is_explicitly_allowed(&policy, unconfined_t, unconfined_t, "process", "fork",));
1015 }
1016
1017 #[test]
1018 fn initial_contexts() {
1019 let policy_bytes = include_bytes!(
1020 "../../testdata/micro_policies/multiple_levels_and_categories_policy.pp"
1021 );
1022 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1023 let policy = policy.validate().expect("validate policy");
1024
1025 let kernel_context = policy.initial_context(InitialSid::Kernel);
1026 assert_eq!(
1027 policy.serialize_security_context(&kernel_context),
1028 b"user0:object_r:type0:s0:c0-s1:c0.c2,c4"
1029 )
1030 }
1031
1032 #[test]
1033 fn explicit_allow_type_type() {
1034 let policy_bytes =
1035 include_bytes!("../../testdata/micro_policies/allow_a_t_b_t_class0_perm0_policy.pp");
1036 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1037 let policy = policy.validate().expect("validate policy");
1038
1039 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1040 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1041
1042 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1043 }
1044
1045 #[test]
1046 fn no_explicit_allow_type_type() {
1047 let policy_bytes =
1048 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_t_class0_perm0_policy.pp");
1049 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1050 let policy = policy.validate().expect("validate policy");
1051
1052 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1053 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1054
1055 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1056 }
1057
1058 #[test]
1059 fn explicit_allow_type_attr() {
1060 let policy_bytes =
1061 include_bytes!("../../testdata/micro_policies/allow_a_t_b_attr_class0_perm0_policy.pp");
1062 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1063 let policy = policy.validate().expect("validate policy");
1064
1065 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1066 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1067
1068 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1069 }
1070
1071 #[test]
1072 fn no_explicit_allow_type_attr() {
1073 let policy_bytes = include_bytes!(
1074 "../../testdata/micro_policies/no_allow_a_t_b_attr_class0_perm0_policy.pp"
1075 );
1076 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1077 let policy = policy.validate().expect("validate policy");
1078
1079 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1080 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1081
1082 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1083 }
1084
1085 #[test]
1086 fn explicit_allow_attr_attr() {
1087 let policy_bytes = include_bytes!(
1088 "../../testdata/micro_policies/allow_a_attr_b_attr_class0_perm0_policy.pp"
1089 );
1090 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1091 let policy = policy.validate().expect("validate policy");
1092
1093 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1094 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1095
1096 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1097 }
1098
1099 #[test]
1100 fn no_explicit_allow_attr_attr() {
1101 let policy_bytes = include_bytes!(
1102 "../../testdata/micro_policies/no_allow_a_attr_b_attr_class0_perm0_policy.pp"
1103 );
1104 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1105 let policy = policy.validate().expect("validate policy");
1106
1107 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1108 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1109
1110 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1111 }
1112
1113 #[test]
1114 fn compute_explicitly_allowed_multiple_attributes() {
1115 let policy_bytes = include_bytes!(
1116 "../../testdata/micro_policies/allow_a_t_a1_attr_class0_perm0_a2_attr_class0_perm1_policy.pp"
1117 );
1118 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1119 let policy = policy.validate().expect("validate policy");
1120
1121 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1122
1123 let classes = policy.0.parsed_policy().classes();
1124 let class =
1125 classes.iter().find(|class| class.name_bytes() == b"class0").expect("class not found");
1126 let raw_access_vector =
1127 policy.0.parsed_policy().compute_explicitly_allowed(a_t, a_t, class).allow.0;
1128
1129 assert_eq!(2, raw_access_vector.count_ones());
1134 }
1135
1136 #[test]
1137 fn compute_access_decision_with_constraints() {
1138 let policy_bytes =
1139 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1140 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1141 let policy = policy.validate().expect("validate policy");
1142
1143 let source_context: SecurityContext = policy
1144 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1145 .expect("create source security context");
1146
1147 let target_context_satisfied: SecurityContext = source_context.clone();
1148 let decision_satisfied = policy.compute_access_decision(
1149 &source_context,
1150 &target_context_satisfied,
1151 KernelClass::File,
1152 );
1153 assert_eq!(decision_satisfied.allow, AccessVector(7));
1157
1158 let target_context_unsatisfied: SecurityContext = policy
1159 .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1160 .expect("create target security context failing some constraints");
1161 let decision_unsatisfied = policy.compute_access_decision(
1162 &source_context,
1163 &target_context_unsatisfied,
1164 KernelClass::File,
1165 );
1166 assert_eq!(decision_unsatisfied.allow, AccessVector(4));
1169 }
1170
1171 #[test]
1172 fn compute_ioctl_access_decision_explicitly_allowed() {
1173 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1174 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1175 let policy = policy.validate().expect("validate policy");
1176
1177 let source_context: SecurityContext = policy
1178 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1179 .expect("create source security context");
1180 let target_context_matched: SecurityContext = source_context.clone();
1181
1182 let decision_single = policy.compute_xperms_access_decision(
1200 XpermsKind::Ioctl,
1201 &source_context,
1202 &target_context_matched,
1203 KernelClass::File,
1204 0xab,
1205 );
1206
1207 let mut expected_auditdeny =
1208 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1209 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1210
1211 let expected_decision_single = XpermsAccessDecision {
1212 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1213 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1214 auditdeny: expected_auditdeny,
1215 };
1216 assert_eq!(decision_single, expected_decision_single);
1217
1218 let decision_range = policy.compute_xperms_access_decision(
1219 XpermsKind::Ioctl,
1220 &source_context,
1221 &target_context_matched,
1222 KernelClass::File,
1223 0x10,
1224 );
1225 let expected_decision_range = XpermsAccessDecision {
1226 allow: XpermsBitmap::ALL,
1227 auditallow: XpermsBitmap::ALL,
1228 auditdeny: XpermsBitmap::NONE,
1229 };
1230 assert_eq!(decision_range, expected_decision_range);
1231 }
1232
1233 #[test]
1234 fn compute_ioctl_access_decision_denied() {
1235 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1236 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1237 let class_id = find_class_by_name(&unvalidated.0.classes(), "class_one_ioctl")
1238 .expect("look up class_one_ioctl")
1239 .id();
1240 let policy = unvalidated.validate().expect("validate policy");
1241 let source_context: SecurityContext = policy
1242 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1243 .expect("create source security context");
1244 let target_context_matched: SecurityContext = source_context.clone();
1245
1246 let decision_single = policy.compute_xperms_access_decision(
1250 XpermsKind::Ioctl,
1251 &source_context,
1252 &target_context_matched,
1253 class_id,
1254 0xdb,
1255 );
1256
1257 let expected_decision = XpermsAccessDecision {
1258 allow: XpermsBitmap::NONE,
1259 auditallow: XpermsBitmap::NONE,
1260 auditdeny: XpermsBitmap::ALL,
1261 };
1262 assert_eq!(decision_single, expected_decision);
1263 }
1264
1265 #[test]
1266 fn compute_ioctl_access_decision_unmatched() {
1267 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1268 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1269 let policy = policy.validate().expect("validate policy");
1270
1271 let source_context: SecurityContext = policy
1272 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1273 .expect("create source security context");
1274
1275 let target_context_unmatched: SecurityContext = policy
1277 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1278 .expect("create source security context");
1279
1280 for prefix in 0x0..=0xff {
1281 let decision = policy.compute_xperms_access_decision(
1282 XpermsKind::Ioctl,
1283 &source_context,
1284 &target_context_unmatched,
1285 KernelClass::File,
1286 prefix,
1287 );
1288 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1289 }
1290 }
1291
1292 #[test]
1293 fn compute_ioctl_earlier_redundant_prefixful_not_coalesced_into_prefixless() {
1294 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1295 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1296 let class_id = find_class_by_name(
1297 &unvalidated.0.classes(),
1298 "class_earlier_redundant_prefixful_not_coalesced_into_prefixless",
1299 )
1300 .expect("look up class_earlier_redundant_prefixful_not_coalesced_into_prefixless")
1301 .id();
1302 let policy = unvalidated.validate().expect("validate policy");
1303 let source_context: SecurityContext = policy
1304 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1305 .expect("create source security context");
1306 let target_context_matched: SecurityContext = source_context.clone();
1307
1308 let decision = policy.compute_xperms_access_decision(
1313 XpermsKind::Ioctl,
1314 &source_context,
1315 &target_context_matched,
1316 class_id,
1317 0x7f,
1318 );
1319 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1320 let decision = policy.compute_xperms_access_decision(
1321 XpermsKind::Ioctl,
1322 &source_context,
1323 &target_context_matched,
1324 class_id,
1325 0x80,
1326 );
1327 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1328 let decision = policy.compute_xperms_access_decision(
1329 XpermsKind::Ioctl,
1330 &source_context,
1331 &target_context_matched,
1332 class_id,
1333 0x81,
1334 );
1335 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1336 }
1337
1338 #[test]
1339 fn compute_ioctl_later_redundant_prefixful_not_coalesced_into_prefixless() {
1340 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1341 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1342 let class_id = find_class_by_name(
1343 &unvalidated.0.classes(),
1344 "class_later_redundant_prefixful_not_coalesced_into_prefixless",
1345 )
1346 .expect("look up class_later_redundant_prefixful_not_coalesced_into_prefixless")
1347 .id();
1348 let policy = unvalidated.validate().expect("validate policy");
1349 let source_context: SecurityContext = policy
1350 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1351 .expect("create source security context");
1352 let target_context_matched: SecurityContext = source_context.clone();
1353
1354 let decision = policy.compute_xperms_access_decision(
1359 XpermsKind::Ioctl,
1360 &source_context,
1361 &target_context_matched,
1362 class_id,
1363 0x8f,
1364 );
1365 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1366 let decision = policy.compute_xperms_access_decision(
1367 XpermsKind::Ioctl,
1368 &source_context,
1369 &target_context_matched,
1370 class_id,
1371 0x90,
1372 );
1373 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1374 let decision = policy.compute_xperms_access_decision(
1375 XpermsKind::Ioctl,
1376 &source_context,
1377 &target_context_matched,
1378 class_id,
1379 0x91,
1380 );
1381 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1382 }
1383
1384 #[test]
1385 fn compute_ioctl_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless() {
1386 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1387 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1388 let class_id = find_class_by_name(
1389 &unvalidated.0.classes(),
1390 "class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless",
1391 )
1392 .expect("look up class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless")
1393 .id();
1394 let policy = unvalidated.validate().expect("validate policy");
1395 let source_context: SecurityContext = policy
1396 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1397 .expect("create source security context");
1398 let target_context_matched: SecurityContext = source_context.clone();
1399
1400 let decision = policy.compute_xperms_access_decision(
1406 XpermsKind::Ioctl,
1407 &source_context,
1408 &target_context_matched,
1409 class_id,
1410 0x9f,
1411 );
1412 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1413 let decision = policy.compute_xperms_access_decision(
1414 XpermsKind::Ioctl,
1415 &source_context,
1416 &target_context_matched,
1417 class_id,
1418 0xa0,
1419 );
1420 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1421 let decision = policy.compute_xperms_access_decision(
1422 XpermsKind::Ioctl,
1423 &source_context,
1424 &target_context_matched,
1425 class_id,
1426 0xa1,
1427 );
1428 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1429 }
1430
1431 #[test]
1432 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless() {
1433 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1434 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1435 let class_id = find_class_by_name(
1436 &unvalidated.0.classes(),
1437 "class_prefixfuls_that_coalesce_to_prefixless",
1438 )
1439 .expect("look up class_prefixfuls_that_coalesce_to_prefixless")
1440 .id();
1441 let policy = unvalidated.validate().expect("validate policy");
1442 let source_context: SecurityContext = policy
1443 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1444 .expect("create source security context");
1445 let target_context_matched: SecurityContext = source_context.clone();
1446
1447 let decision = policy.compute_xperms_access_decision(
1453 XpermsKind::Ioctl,
1454 &source_context,
1455 &target_context_matched,
1456 class_id,
1457 0xaf,
1458 );
1459 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1460 let decision = policy.compute_xperms_access_decision(
1461 XpermsKind::Ioctl,
1462 &source_context,
1463 &target_context_matched,
1464 class_id,
1465 0xb0,
1466 );
1467 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1468 let decision = policy.compute_xperms_access_decision(
1469 XpermsKind::Ioctl,
1470 &source_context,
1471 &target_context_matched,
1472 class_id,
1473 0xb1,
1474 );
1475 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1476 }
1477
1478 #[test]
1479 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless() {
1480 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1481 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1482 let class_id = find_class_by_name(
1483 &unvalidated.0.classes(),
1484 "class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless",
1485 )
1486 .expect("look up class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless")
1487 .id();
1488 let policy = unvalidated.validate().expect("validate policy");
1489 let source_context: SecurityContext = policy
1490 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1491 .expect("create source security context");
1492 let target_context_matched: SecurityContext = source_context.clone();
1493
1494 let decision = policy.compute_xperms_access_decision(
1501 XpermsKind::Ioctl,
1502 &source_context,
1503 &target_context_matched,
1504 class_id,
1505 0xbf,
1506 );
1507 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1508 let decision = policy.compute_xperms_access_decision(
1509 XpermsKind::Ioctl,
1510 &source_context,
1511 &target_context_matched,
1512 class_id,
1513 0xc0,
1514 );
1515 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1516 let decision = policy.compute_xperms_access_decision(
1517 XpermsKind::Ioctl,
1518 &source_context,
1519 &target_context_matched,
1520 class_id,
1521 0xc1,
1522 );
1523 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1524 let decision = policy.compute_xperms_access_decision(
1525 XpermsKind::Ioctl,
1526 &source_context,
1527 &target_context_matched,
1528 class_id,
1529 0xc2,
1530 );
1531 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1532 }
1533
1534 #[test]
1535 fn compute_ioctl_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless() {
1536 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1537 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1538 let class_id = find_class_by_name(
1539 &unvalidated.0.classes(),
1540 "class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless",
1541 )
1542 .expect("look up class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless")
1543 .id();
1544 let policy = unvalidated.validate().expect("validate policy");
1545 let source_context: SecurityContext = policy
1546 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1547 .expect("create source security context");
1548 let target_context_matched: SecurityContext = source_context.clone();
1549
1550 let decision = policy.compute_xperms_access_decision(
1557 XpermsKind::Ioctl,
1558 &source_context,
1559 &target_context_matched,
1560 class_id,
1561 0xd5,
1562 );
1563 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1564 let decision = policy.compute_xperms_access_decision(
1565 XpermsKind::Ioctl,
1566 &source_context,
1567 &target_context_matched,
1568 class_id,
1569 0xd6,
1570 );
1571 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1572 let decision = policy.compute_xperms_access_decision(
1573 XpermsKind::Ioctl,
1574 &source_context,
1575 &target_context_matched,
1576 class_id,
1577 0xd7,
1578 );
1579 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1580 let decision = policy.compute_xperms_access_decision(
1581 XpermsKind::Ioctl,
1582 &source_context,
1583 &target_context_matched,
1584 class_id,
1585 0xd8,
1586 );
1587 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1588 }
1589
1590 #[test]
1601 fn compute_ioctl_ridiculous_permission_ordering() {
1602 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1603 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1604 let class_id =
1605 find_class_by_name(&unvalidated.0.classes(), "class_ridiculous_permission_ordering")
1606 .expect("look up class_ridiculous_permission_ordering")
1607 .id();
1608 let policy = unvalidated.validate().expect("validate policy");
1609 let source_context: SecurityContext = policy
1610 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1611 .expect("create source security context");
1612 let target_context_matched: SecurityContext = source_context.clone();
1613
1614 let decision = policy.compute_xperms_access_decision(
1619 XpermsKind::Ioctl,
1620 &source_context,
1621 &target_context_matched,
1622 class_id,
1623 0x00,
1624 );
1625 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1626 let decision = policy.compute_xperms_access_decision(
1627 XpermsKind::Ioctl,
1628 &source_context,
1629 &target_context_matched,
1630 class_id,
1631 0x01,
1632 );
1633 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1634 let decision = policy.compute_xperms_access_decision(
1635 XpermsKind::Ioctl,
1636 &source_context,
1637 &target_context_matched,
1638 class_id,
1639 0xbf,
1640 );
1641 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1642 let decision = policy.compute_xperms_access_decision(
1643 XpermsKind::Ioctl,
1644 &source_context,
1645 &target_context_matched,
1646 class_id,
1647 0xc0,
1648 );
1649 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1650 let decision = policy.compute_xperms_access_decision(
1651 XpermsKind::Ioctl,
1652 &source_context,
1653 &target_context_matched,
1654 class_id,
1655 0xce,
1656 );
1657 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1658 let decision = policy.compute_xperms_access_decision(
1659 XpermsKind::Ioctl,
1660 &source_context,
1661 &target_context_matched,
1662 class_id,
1663 0xcf,
1664 );
1665 assert_eq!(
1666 decision,
1667 XpermsAccessDecision {
1668 allow: xperms_bitmap_from_elements((0x0..=0xf2).collect::<Vec<_>>().as_slice()),
1669 auditallow: XpermsBitmap::NONE,
1670 auditdeny: XpermsBitmap::ALL,
1671 }
1672 );
1673 let decision = policy.compute_xperms_access_decision(
1674 XpermsKind::Ioctl,
1675 &source_context,
1676 &target_context_matched,
1677 class_id,
1678 0xd0,
1679 );
1680 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1681 let decision = policy.compute_xperms_access_decision(
1682 XpermsKind::Ioctl,
1683 &source_context,
1684 &target_context_matched,
1685 class_id,
1686 0xe9,
1687 );
1688 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1689 let decision = policy.compute_xperms_access_decision(
1690 XpermsKind::Ioctl,
1691 &source_context,
1692 &target_context_matched,
1693 class_id,
1694 0xf0,
1695 );
1696 assert_eq!(
1697 decision,
1698 XpermsAccessDecision {
1699 allow: xperms_bitmap_from_elements(&[0x01]),
1700 auditallow: XpermsBitmap::NONE,
1701 auditdeny: XpermsBitmap::ALL,
1702 }
1703 );
1704 let decision = policy.compute_xperms_access_decision(
1705 XpermsKind::Ioctl,
1706 &source_context,
1707 &target_context_matched,
1708 class_id,
1709 0xf1,
1710 );
1711 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1712 let decision = policy.compute_xperms_access_decision(
1713 XpermsKind::Ioctl,
1714 &source_context,
1715 &target_context_matched,
1716 class_id,
1717 0xfc,
1718 );
1719 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1720 let decision = policy.compute_xperms_access_decision(
1721 XpermsKind::Ioctl,
1722 &source_context,
1723 &target_context_matched,
1724 class_id,
1725 0xfd,
1726 );
1727 assert_eq!(
1728 decision,
1729 XpermsAccessDecision {
1730 allow: xperms_bitmap_from_elements((0xfa..=0xfd).collect::<Vec<_>>().as_slice()),
1731 auditallow: XpermsBitmap::NONE,
1732 auditdeny: XpermsBitmap::ALL,
1733 }
1734 );
1735 let decision = policy.compute_xperms_access_decision(
1736 XpermsKind::Ioctl,
1737 &source_context,
1738 &target_context_matched,
1739 class_id,
1740 0xfe,
1741 );
1742 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1743 }
1744
1745 #[test]
1746 fn compute_nlmsg_access_decision_explicitly_allowed() {
1747 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1748 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1749 let policy = policy.validate().expect("validate policy");
1750
1751 let source_context: SecurityContext = policy
1752 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1753 .expect("create source security context");
1754 let target_context_matched: SecurityContext = source_context.clone();
1755
1756 let decision_single = policy.compute_xperms_access_decision(
1774 XpermsKind::Nlmsg,
1775 &source_context,
1776 &target_context_matched,
1777 KernelClass::NetlinkRouteSocket,
1778 0xab,
1779 );
1780
1781 let mut expected_auditdeny =
1782 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1783 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1784
1785 let expected_decision_single = XpermsAccessDecision {
1786 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1787 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1788 auditdeny: expected_auditdeny,
1789 };
1790 assert_eq!(decision_single, expected_decision_single);
1791
1792 let decision_range = policy.compute_xperms_access_decision(
1793 XpermsKind::Nlmsg,
1794 &source_context,
1795 &target_context_matched,
1796 KernelClass::NetlinkRouteSocket,
1797 0x10,
1798 );
1799 let expected_decision_range = XpermsAccessDecision {
1800 allow: XpermsBitmap::ALL,
1801 auditallow: XpermsBitmap::ALL,
1802 auditdeny: XpermsBitmap::NONE,
1803 };
1804 assert_eq!(decision_range, expected_decision_range);
1805 }
1806
1807 #[test]
1808 fn compute_nlmsg_access_decision_unmatched() {
1809 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1810 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1811 let policy = policy.validate().expect("validate policy");
1812
1813 let source_context: SecurityContext = policy
1814 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1815 .expect("create source security context");
1816
1817 let target_context_unmatched: SecurityContext = policy
1819 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1820 .expect("create source security context");
1821
1822 for prefix in 0x0..=0xff {
1823 let decision = policy.compute_xperms_access_decision(
1824 XpermsKind::Nlmsg,
1825 &source_context,
1826 &target_context_unmatched,
1827 KernelClass::NetlinkRouteSocket,
1828 prefix,
1829 );
1830 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1831 }
1832 }
1833
1834 #[test]
1835 fn compute_ioctl_grant_does_not_cause_nlmsg_deny() {
1836 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1837 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1838 let class_id = find_class_by_name(
1839 &unvalidated.0.classes(),
1840 "class_ioctl_grant_does_not_cause_nlmsg_deny",
1841 )
1842 .expect("look up class_ioctl_grant_does_not_cause_nlmsg_deny")
1843 .id();
1844 let policy = unvalidated.validate().expect("validate policy");
1845 let source_context: SecurityContext = policy
1846 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1847 .expect("create source security context");
1848 let target_context_matched: SecurityContext = source_context.clone();
1849
1850 let ioctl_decision = policy.compute_xperms_access_decision(
1854 XpermsKind::Ioctl,
1855 &source_context,
1856 &target_context_matched,
1857 class_id,
1858 0x00,
1859 );
1860 assert_eq!(
1861 ioctl_decision,
1862 XpermsAccessDecision {
1863 allow: xperms_bitmap_from_elements(&[0x0002]),
1864 auditallow: XpermsBitmap::NONE,
1865 auditdeny: XpermsBitmap::ALL,
1866 }
1867 );
1868 let nlmsg_decision = policy.compute_xperms_access_decision(
1869 XpermsKind::Nlmsg,
1870 &source_context,
1871 &target_context_matched,
1872 class_id,
1873 0x00,
1874 );
1875 assert_eq!(nlmsg_decision, XpermsAccessDecision::ALLOW_ALL);
1876 }
1877
1878 #[test]
1879 fn compute_nlmsg_grant_does_not_cause_ioctl_deny() {
1880 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1881 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1882 let class_id = find_class_by_name(
1883 &unvalidated.0.classes(),
1884 "class_nlmsg_grant_does_not_cause_ioctl_deny",
1885 )
1886 .expect("look up class_nlmsg_grant_does_not_cause_ioctl_deny")
1887 .id();
1888 let policy = unvalidated.validate().expect("validate policy");
1889 let source_context: SecurityContext = policy
1890 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1891 .expect("create source security context");
1892 let target_context_matched: SecurityContext = source_context.clone();
1893
1894 let nlmsg_decision = policy.compute_xperms_access_decision(
1898 XpermsKind::Nlmsg,
1899 &source_context,
1900 &target_context_matched,
1901 class_id,
1902 0x00,
1903 );
1904 assert_eq!(
1905 nlmsg_decision,
1906 XpermsAccessDecision {
1907 allow: xperms_bitmap_from_elements(&[0x0003]),
1908 auditallow: XpermsBitmap::NONE,
1909 auditdeny: XpermsBitmap::ALL,
1910 }
1911 );
1912 let ioctl_decision = policy.compute_xperms_access_decision(
1913 XpermsKind::Ioctl,
1914 &source_context,
1915 &target_context_matched,
1916 class_id,
1917 0x00,
1918 );
1919 assert_eq!(ioctl_decision, XpermsAccessDecision::ALLOW_ALL);
1920 }
1921
1922 #[test]
1923 fn compute_create_context_minimal() {
1924 let policy_bytes =
1925 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1926 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1927 let policy = policy.validate().expect("validate policy");
1928 let source = policy
1929 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1930 .expect("valid source security context");
1931 let target = policy
1932 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1933 .expect("valid target security context");
1934
1935 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1936 let expected: SecurityContext = policy
1937 .parse_security_context(b"source_u:object_r:target_t:s0:c0".into())
1938 .expect("valid expected security context");
1939
1940 assert_eq!(expected, actual);
1941 }
1942
1943 #[test]
1944 fn new_security_context_minimal() {
1945 let policy_bytes =
1946 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1947 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1948 let policy = policy.validate().expect("validate policy");
1949 let source = policy
1950 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1951 .expect("valid source security context");
1952 let target = policy
1953 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1954 .expect("valid target security context");
1955
1956 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1957
1958 assert_eq!(source, actual);
1959 }
1960
1961 #[test]
1962 fn compute_create_context_class_defaults() {
1963 let policy_bytes =
1964 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1965 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1966 let policy = policy.validate().expect("validate policy");
1967 let source = policy
1968 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1969 .expect("valid source security context");
1970 let target = policy
1971 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1972 .expect("valid target security context");
1973
1974 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1975 let expected: SecurityContext = policy
1976 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1977 .expect("valid expected security context");
1978
1979 assert_eq!(expected, actual);
1980 }
1981
1982 #[test]
1983 fn new_security_context_class_defaults() {
1984 let policy_bytes =
1985 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1986 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1987 let policy = policy.validate().expect("validate policy");
1988 let source = policy
1989 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1990 .expect("valid source security context");
1991 let target = policy
1992 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1993 .expect("valid target security context");
1994
1995 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1996 let expected: SecurityContext = policy
1997 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1998 .expect("valid expected security context");
1999
2000 assert_eq!(expected, actual);
2001 }
2002
2003 #[test]
2004 fn compute_create_context_role_transition() {
2005 let policy_bytes =
2006 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
2007 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2008 let policy = policy.validate().expect("validate policy");
2009 let source = policy
2010 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2011 .expect("valid source security context");
2012 let target = policy
2013 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2014 .expect("valid target security context");
2015
2016 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2017 let expected: SecurityContext = policy
2018 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
2019 .expect("valid expected security context");
2020
2021 assert_eq!(expected, actual);
2022 }
2023
2024 #[test]
2025 fn new_security_context_role_transition() {
2026 let policy_bytes =
2027 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
2028 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2029 let policy = policy.validate().expect("validate policy");
2030 let source = policy
2031 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2032 .expect("valid source security context");
2033 let target = policy
2034 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2035 .expect("valid target security context");
2036
2037 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2038 let expected: SecurityContext = policy
2039 .parse_security_context(b"source_u:transition_r:source_t:s0:c0-s2:c0.c1".into())
2040 .expect("valid expected security context");
2041
2042 assert_eq!(expected, actual);
2043 }
2044
2045 #[test]
2046 #[ignore]
2048 fn compute_create_context_role_transition_not_allowed() {
2049 let policy_bytes = include_bytes!(
2050 "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy.pp"
2051 );
2052 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2053 let policy = policy.validate().expect("validate policy");
2054 let source = policy
2055 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2056 .expect("valid source security context");
2057 let target = policy
2058 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2059 .expect("valid target security context");
2060
2061 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2062
2063 assert!(policy.validate_security_context(&actual).is_err());
2065 }
2066
2067 #[test]
2068 fn compute_create_context_type_transition() {
2069 let policy_bytes =
2070 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
2071 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2072 let policy = policy.validate().expect("validate policy");
2073 let source = policy
2074 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2075 .expect("valid source security context");
2076 let target = policy
2077 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2078 .expect("valid target security context");
2079
2080 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2081 let expected: SecurityContext = policy
2082 .parse_security_context(b"source_u:object_r:transition_t:s0:c0".into())
2083 .expect("valid expected security context");
2084
2085 assert_eq!(expected, actual);
2086 }
2087
2088 #[test]
2089 fn new_security_context_type_transition() {
2090 let policy_bytes =
2091 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
2092 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2093 let policy = policy.validate().expect("validate policy");
2094 let source = policy
2095 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2096 .expect("valid source security context");
2097 let target = policy
2098 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2099 .expect("valid target security context");
2100
2101 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2102 let expected: SecurityContext = policy
2103 .parse_security_context(b"source_u:source_r:transition_t:s0:c0-s2:c0.c1".into())
2104 .expect("valid expected security context");
2105
2106 assert_eq!(expected, actual);
2107 }
2108
2109 #[test]
2110 fn compute_create_context_range_transition() {
2111 let policy_bytes =
2112 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
2113 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2114 let policy = policy.validate().expect("validate policy");
2115 let source = policy
2116 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2117 .expect("valid source security context");
2118 let target = policy
2119 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2120 .expect("valid target security context");
2121
2122 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2123 let expected: SecurityContext = policy
2124 .parse_security_context(b"source_u:object_r:target_t:s1:c1-s2:c1.c2".into())
2125 .expect("valid expected security context");
2126
2127 assert_eq!(expected, actual);
2128 }
2129
2130 #[test]
2131 fn new_security_context_range_transition() {
2132 let policy_bytes =
2133 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
2134 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2135 let policy = policy.validate().expect("validate policy");
2136 let source = policy
2137 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2138 .expect("valid source security context");
2139 let target = policy
2140 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2141 .expect("valid target security context");
2142
2143 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2144 let expected: SecurityContext = policy
2145 .parse_security_context(b"source_u:source_r:source_t:s1:c1-s2:c1.c2".into())
2146 .expect("valid expected security context");
2147
2148 assert_eq!(expected, actual);
2149 }
2150
2151 #[test]
2152 fn access_vector_formats() {
2153 assert_eq!(format!("{:x}", AccessVector::NONE), "0");
2154 assert_eq!(format!("{:x}", AccessVector::ALL), "ffffffff");
2155 assert_eq!(format!("{:?}", AccessVector::NONE), "AccessVector(00000000)");
2156 assert_eq!(format!("{:?}", AccessVector::ALL), "AccessVector(ffffffff)");
2157 }
2158}