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<'a> {
254 pub class_name: &'a [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<'a>(&'a self) -> Vec<ClassInfo<'a>> {
290 self.0
291 .parsed_policy()
292 .classes()
293 .iter()
294 .map(|class| ClassInfo { class_name: class.name_bytes(), class_id: class.id() })
295 .collect()
296 }
297
298 pub(super) fn type_id_by_name(&self, name: &str) -> Option<TypeId> {
300 self.0.parsed_policy().type_id_by_name(name)
301 }
302
303 pub fn find_class_permissions_by_name(
308 &self,
309 class_name: &str,
310 ) -> Result<Vec<(ClassPermissionId, Vec<u8>)>, ()> {
311 let class = find_class_by_name(self.0.parsed_policy().classes(), class_name).ok_or(())?;
312 let owned_permissions = class.permissions();
313
314 let mut result: Vec<_> = owned_permissions
315 .iter()
316 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
317 .collect();
318
319 if class.common_name_bytes().is_empty() {
321 return Ok(result);
322 }
323
324 let common_symbol_permissions = find_common_symbol_by_name_bytes(
325 self.0.parsed_policy().common_symbols(),
326 class.common_name_bytes(),
327 )
328 .ok_or(())?
329 .permissions();
330
331 result.append(
332 &mut common_symbol_permissions
333 .iter()
334 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
335 .collect(),
336 );
337
338 Ok(result)
339 }
340
341 pub fn fs_use_label_and_type(&self, fs_type: NullessByteStr<'_>) -> Option<FsUseLabelAndType> {
344 self.0.fs_use_label_and_type(fs_type)
345 }
346
347 pub fn genfscon_label_for_fs_and_path(
350 &self,
351 fs_type: NullessByteStr<'_>,
352 node_path: NullessByteStr<'_>,
353 class_id: Option<KernelClass>,
354 ) -> Option<SecurityContext> {
355 self.0.genfscon_label_for_fs_and_path(fs_type, node_path, class_id)
356 }
357
358 pub fn initial_context(&self, id: crate::InitialSid) -> security_context::SecurityContext {
361 self.0.initial_context(id)
362 }
363
364 pub fn parse_security_context(
366 &self,
367 security_context: NullessByteStr<'_>,
368 ) -> Result<security_context::SecurityContext, security_context::SecurityContextError> {
369 security_context::SecurityContext::parse(&self.0, security_context)
370 }
371
372 pub fn validate_security_context(
374 &self,
375 security_context: &SecurityContext,
376 ) -> Result<(), SecurityContextError> {
377 security_context.validate(&self.0)
378 }
379
380 pub fn serialize_security_context(&self, security_context: &SecurityContext) -> Vec<u8> {
382 security_context.serialize(&self.0)
383 }
384
385 pub fn compute_create_context_with_name(
393 &self,
394 source: &SecurityContext,
395 target: &SecurityContext,
396 class: impl Into<ObjectClass>,
397 name: NullessByteStr<'_>,
398 ) -> Option<SecurityContext> {
399 self.0.compute_create_context_with_name(source, target, class.into(), name)
400 }
401
402 pub fn compute_create_context(
420 &self,
421 source: &SecurityContext,
422 target: &SecurityContext,
423 class: impl Into<ObjectClass>,
424 ) -> SecurityContext {
425 self.0.compute_create_context(source, target, class.into())
426 }
427
428 pub fn compute_access_decision(
444 &self,
445 source_context: &SecurityContext,
446 target_context: &SecurityContext,
447 object_class: impl Into<ObjectClass>,
448 ) -> AccessDecision {
449 if let Some(target_class) = self.0.class(object_class.into()) {
450 self.0.parsed_policy().compute_access_decision(
451 source_context,
452 target_context,
453 target_class,
454 )
455 } else {
456 AccessDecision::allow(AccessVector::NONE)
457 }
458 }
459
460 pub fn compute_xperms_access_decision(
464 &self,
465 xperms_kind: XpermsKind,
466 source_context: &SecurityContext,
467 target_context: &SecurityContext,
468 object_class: impl Into<ObjectClass>,
469 xperms_prefix: u8,
470 ) -> XpermsAccessDecision {
471 if let Some(target_class) = self.0.class(object_class.into()) {
472 self.0.parsed_policy().compute_xperms_access_decision(
473 xperms_kind,
474 source_context,
475 target_context,
476 target_class,
477 xperms_prefix,
478 )
479 } else {
480 XpermsAccessDecision::DENY_ALL
481 }
482 }
483
484 pub fn is_bounded_by(&self, bounded_type: TypeId, parent_type: TypeId) -> bool {
485 let type_ = self.0.parsed_policy().type_(bounded_type);
486 type_.bounded_by() == Some(parent_type)
487 }
488
489 pub fn is_permissive(&self, type_: TypeId) -> bool {
491 self.0.parsed_policy().permissive_types().is_set(type_.0.get())
492 }
493
494 pub fn has_policycap(&self, policy_cap: PolicyCap) -> bool {
496 self.0.parsed_policy().has_policycap(policy_cap)
497 }
498}
499
500impl AccessVectorComputer for Policy {
501 fn kernel_permissions_to_access_vector<
502 P: ClassPermission + Into<KernelPermission> + Clone + 'static,
503 >(
504 &self,
505 permissions: &[P],
506 ) -> Option<AccessVector> {
507 let mut access_vector = AccessVector::NONE;
508 for permission in permissions {
509 if let Some(permission_access_vector) =
510 self.0.kernel_permission_to_access_vector(permission.clone())
511 {
512 access_vector |= permission_access_vector;
513 } else {
514 if self.0.parsed_policy().handle_unknown() != HandleUnknown::Allow {
516 return None;
517 }
518 }
519 }
520 Some(access_vector)
521 }
522}
523
524pub struct Unvalidated(ParsedPolicy);
526
527impl Unvalidated {
528 pub fn validate(self) -> Result<Policy, anyhow::Error> {
529 self.0.validate().context("validating parsed policy")?;
530 let index = PolicyIndex::new(self.0).context("building index")?;
531 Ok(Policy(index))
532 }
533}
534
535pub trait AccessVectorComputer {
538 fn kernel_permissions_to_access_vector<
545 P: ClassPermission + Into<KernelPermission> + Clone + 'static,
546 >(
547 &self,
548 permissions: &[P],
549 ) -> Option<AccessVector>;
550}
551
552pub trait Parse: Sized {
554 type Error: Into<anyhow::Error>;
557
558 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error>;
561}
562
563pub(super) trait ParseSlice: Sized {
565 type Error: Into<anyhow::Error>;
568
569 fn parse_slice<'a>(
572 bytes: PolicyCursor<'a>,
573 count: usize,
574 ) -> Result<(Self, PolicyCursor<'a>), Self::Error>;
575}
576
577pub(super) struct PolicyValidationContext {
579 #[allow(unused)]
581 pub(super) data: PolicyData,
582}
583
584pub(super) trait Validate {
586 type Error: Into<anyhow::Error>;
589
590 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error>;
592}
593
594pub(super) trait ValidateArray<M, D> {
595 type Error: Into<anyhow::Error>;
598
599 fn validate_array(
601 context: &mut PolicyValidationContext,
602 metadata: &M,
603 items: &[D],
604 ) -> Result<(), Self::Error>;
605}
606
607pub(super) trait Counted {
609 fn count(&self) -> u32;
611}
612
613impl<T: Validate> Validate for Option<T> {
614 type Error = <T as Validate>::Error;
615
616 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
617 match self {
618 Some(value) => value.validate(context),
619 None => Ok(()),
620 }
621 }
622}
623
624impl Validate for le::U32 {
625 type Error = anyhow::Error;
626
627 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
630 Ok(())
631 }
632}
633
634impl Validate for u8 {
635 type Error = anyhow::Error;
636
637 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
640 Ok(())
641 }
642}
643
644impl Validate for [u8] {
645 type Error = anyhow::Error;
646
647 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
650 Ok(())
651 }
652}
653
654impl<B: SplitByteSlice, T: Validate + FromBytes + KnownLayout + Immutable> Validate for Ref<B, T> {
655 type Error = <T as Validate>::Error;
656
657 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
658 self.deref().validate(context)
659 }
660}
661
662impl<B: SplitByteSlice, T: Counted + FromBytes + KnownLayout + Immutable> Counted for Ref<B, T> {
663 fn count(&self) -> u32 {
664 self.deref().count()
665 }
666}
667
668#[derive(Clone, Debug, PartialEq)]
671struct Array<M, D> {
672 metadata: M,
673 data: D,
674}
675
676impl<M: Counted + Parse, D: ParseSlice> Parse for Array<M, D> {
677 type Error = anyhow::Error;
680
681 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
683 let tail = bytes;
684
685 let (metadata, tail) = M::parse(tail).map_err(Into::<anyhow::Error>::into)?;
686
687 let (data, tail) =
688 D::parse_slice(tail, metadata.count() as usize).map_err(Into::<anyhow::Error>::into)?;
689
690 let array = Self { metadata, data };
691
692 Ok((array, tail))
693 }
694}
695
696impl<T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned> Parse for T {
697 type Error = anyhow::Error;
698
699 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
700 bytes.parse::<T>().map_err(anyhow::Error::from)
701 }
702}
703
704macro_rules! array_type {
708 ($type_name:ident, $metadata_type:ty, $data_type:ty, $metadata_type_name:expr, $data_type_name:expr) => {
709 #[doc = "An [`Array`] with [`"]
710 #[doc = $metadata_type_name]
711 #[doc = "`] metadata and [`"]
712 #[doc = $data_type_name]
713 #[doc = "`] data items."]
714 #[derive(Debug, PartialEq)]
715 pub(super) struct $type_name(super::Array<$metadata_type, $data_type>);
716
717 impl std::ops::Deref for $type_name {
718 type Target = super::Array<$metadata_type, $data_type>;
719
720 fn deref(&self) -> &Self::Target {
721 &self.0
722 }
723 }
724
725 impl super::Parse for $type_name
726 where
727 super::Array<$metadata_type, $data_type>: super::Parse,
728 {
729 type Error = <Array<$metadata_type, $data_type> as super::Parse>::Error;
730
731 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
732 let (array, tail) = Array::<$metadata_type, $data_type>::parse(bytes)?;
733 Ok((Self(array), tail))
734 }
735 }
736 };
737
738 ($type_name:ident, $metadata_type:ty, $data_type:ty) => {
739 array_type!(
740 $type_name,
741 $metadata_type,
742 $data_type,
743 stringify!($metadata_type),
744 stringify!($data_type)
745 );
746 };
747}
748
749pub(super) use array_type;
750
751macro_rules! array_type_validate_deref_both {
752 ($type_name:ident) => {
753 impl Validate for $type_name {
754 type Error = anyhow::Error;
755
756 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
757 let metadata = &self.metadata;
758 metadata.validate(context)?;
759
760 let items = &self.data;
761 items.validate(context)?;
762
763 Self::validate_array(context, metadata, items).map_err(Into::<anyhow::Error>::into)
764 }
765 }
766 };
767}
768
769pub(super) use array_type_validate_deref_both;
770
771macro_rules! array_type_validate_deref_data {
772 ($type_name:ident) => {
773 impl Validate for $type_name {
774 type Error = anyhow::Error;
775
776 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
777 let metadata = &self.metadata;
778 metadata.validate(context)?;
779
780 let items = &self.data;
781 items.validate(context)?;
782
783 Self::validate_array(context, metadata, items)
784 }
785 }
786 };
787}
788
789pub(super) use array_type_validate_deref_data;
790
791macro_rules! array_type_validate_deref_metadata_data_vec {
792 ($type_name:ident) => {
793 impl Validate for $type_name {
794 type Error = anyhow::Error;
795
796 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
797 let metadata = &self.metadata;
798 metadata.validate(context)?;
799
800 let items = &self.data;
801 items.validate(context)?;
802
803 Self::validate_array(context, metadata, items.as_slice())
804 }
805 }
806 };
807}
808
809pub(super) use array_type_validate_deref_metadata_data_vec;
810
811macro_rules! array_type_validate_deref_none_data_vec {
812 ($type_name:ident) => {
813 impl Validate for $type_name {
814 type Error = anyhow::Error;
815
816 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
817 let metadata = &self.metadata;
818 metadata.validate(context)?;
819
820 let items = &self.data;
821 items.validate(context)?;
822
823 Self::validate_array(context, metadata, items.as_slice())
824 }
825 }
826 };
827}
828
829pub(super) use array_type_validate_deref_none_data_vec;
830
831impl<T: Parse> ParseSlice for Vec<T> {
832 type Error = anyhow::Error;
835
836 fn parse_slice<'a>(
838 bytes: PolicyCursor<'a>,
839 count: usize,
840 ) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
841 let mut slice = Vec::with_capacity(count);
842 let mut tail = bytes;
843
844 for _ in 0..count {
845 let (item, next_tail) = T::parse(tail).map_err(Into::<anyhow::Error>::into)?;
846 slice.push(item);
847 tail = next_tail;
848 }
849
850 Ok((slice, tail))
851 }
852}
853
854#[cfg(test)]
855pub(super) mod testing {
856 use super::AccessVector;
857 use super::error::{ParseError, ValidateError};
858
859 pub const ACCESS_VECTOR_0001: AccessVector = AccessVector(0b0001u32);
860 pub const ACCESS_VECTOR_0010: AccessVector = AccessVector(0b0010u32);
861
862 pub(super) fn as_parse_error(error: anyhow::Error) -> ParseError {
864 error.downcast::<ParseError>().expect("parse error")
865 }
866
867 pub(super) fn as_validate_error(error: anyhow::Error) -> ValidateError {
869 error.downcast::<ValidateError>().expect("validate error")
870 }
871}
872
873#[cfg(test)]
874pub(super) mod tests {
875 use super::arrays::XpermsBitmap;
876 use super::metadata::HandleUnknown;
877 use super::security_context::SecurityContext;
878 use super::symbols::find_class_by_name;
879 use super::{
880 AccessVector, Policy, TypeId, XpermsAccessDecision, XpermsKind, parse_policy_by_value,
881 };
882 use crate::{FileClass, InitialSid, KernelClass};
883
884 use anyhow::Context as _;
885 use serde::Deserialize;
886 use std::ops::{Deref, Shl};
887 use zerocopy::little_endian as le;
888
889 fn is_explicitly_allowed(
897 policy: &Policy,
898 source_type: TypeId,
899 target_type: TypeId,
900 target_class: &str,
901 permission: &str,
902 ) -> bool {
903 let class = policy
904 .0
905 .parsed_policy()
906 .classes()
907 .iter()
908 .find(|class| class.name_bytes() == target_class.as_bytes())
909 .expect("class not found");
910 let class_permissions = policy
911 .find_class_permissions_by_name(target_class)
912 .expect("class permissions not found");
913 let (permission_id, _) = class_permissions
914 .iter()
915 .find(|(_, name)| permission.as_bytes() == name)
916 .expect("permission not found");
917 let permission_bit = AccessVector::from_class_permission_id(*permission_id);
918 let access_decision =
919 policy.0.parsed_policy().compute_explicitly_allowed(source_type, target_type, class);
920 permission_bit == access_decision.allow & permission_bit
921 }
922
923 #[derive(Debug, Deserialize)]
924 struct Expectations {
925 expected_policy_version: u32,
926 expected_handle_unknown: LocalHandleUnknown,
927 }
928
929 #[derive(Debug, Deserialize, PartialEq)]
930 #[serde(rename_all = "snake_case")]
931 enum LocalHandleUnknown {
932 Deny,
933 Reject,
934 Allow,
935 }
936
937 impl PartialEq<HandleUnknown> for LocalHandleUnknown {
938 fn eq(&self, other: &HandleUnknown) -> bool {
939 match self {
940 LocalHandleUnknown::Deny => *other == HandleUnknown::Deny,
941 LocalHandleUnknown::Reject => *other == HandleUnknown::Reject,
942 LocalHandleUnknown::Allow => *other == HandleUnknown::Allow,
943 }
944 }
945 }
946
947 fn xperms_bitmap_from_elements(elements: &[u8]) -> XpermsBitmap {
950 let mut bitmap = [le::U32::ZERO; 8];
951 for element in elements {
952 let block_index = (*element as usize) / 32;
953 let bit_index = ((*element as usize) % 32) as u32;
954 let bitmask = le::U32::new(1).shl(bit_index);
955 bitmap[block_index] = bitmap[block_index] | bitmask;
956 }
957 XpermsBitmap::new(bitmap)
958 }
959
960 #[test]
961 fn known_policies() {
962 let policies_and_expectations = [
963 [
964 b"testdata/policies/emulator".to_vec(),
965 include_bytes!("../../testdata/policies/emulator").to_vec(),
966 include_bytes!("../../testdata/expectations/emulator").to_vec(),
967 ],
968 [
969 b"testdata/policies/selinux_testsuite".to_vec(),
970 include_bytes!("../../testdata/policies/selinux_testsuite").to_vec(),
971 include_bytes!("../../testdata/expectations/selinux_testsuite").to_vec(),
972 ],
973 ];
974
975 for [policy_path, policy_bytes, expectations_bytes] in policies_and_expectations {
976 let expectations = serde_json5::from_reader::<_, Expectations>(
977 &mut std::io::Cursor::new(expectations_bytes),
978 )
979 .expect("deserialize expectations");
980
981 let unvalidated_policy =
984 parse_policy_by_value(policy_bytes.clone()).expect("parse policy");
985
986 let policy = unvalidated_policy
987 .validate()
988 .with_context(|| {
989 format!(
990 "policy path: {:?}",
991 std::str::from_utf8(policy_path.as_slice()).unwrap()
992 )
993 })
994 .expect("validate policy");
995
996 assert_eq!(expectations.expected_policy_version, policy.policy_version());
997 assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
998
999 let binary_policy = policy.binary().clone();
1001 assert_eq!(&policy_bytes, binary_policy.deref());
1002 }
1003 }
1004
1005 #[test]
1006 fn policy_lookup() {
1007 let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
1008 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1009 let policy = policy.validate().expect("validate selinux testsuite policy");
1010
1011 let unconfined_t = policy.type_id_by_name("unconfined_t").expect("look up type id");
1012
1013 assert!(is_explicitly_allowed(&policy, unconfined_t, unconfined_t, "process", "fork",));
1014 }
1015
1016 #[test]
1017 fn initial_contexts() {
1018 let policy_bytes = include_bytes!(
1019 "../../testdata/micro_policies/multiple_levels_and_categories_policy.pp"
1020 );
1021 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1022 let policy = policy.validate().expect("validate policy");
1023
1024 let kernel_context = policy.initial_context(InitialSid::Kernel);
1025 assert_eq!(
1026 policy.serialize_security_context(&kernel_context),
1027 b"user0:object_r:type0:s0:c0-s1:c0.c2,c4"
1028 )
1029 }
1030
1031 #[test]
1032 fn explicit_allow_type_type() {
1033 let policy_bytes =
1034 include_bytes!("../../testdata/micro_policies/allow_a_t_b_t_class0_perm0_policy.pp");
1035 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1036 let policy = policy.validate().expect("validate policy");
1037
1038 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1039 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1040
1041 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1042 }
1043
1044 #[test]
1045 fn no_explicit_allow_type_type() {
1046 let policy_bytes =
1047 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_t_class0_perm0_policy.pp");
1048 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1049 let policy = policy.validate().expect("validate policy");
1050
1051 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1052 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1053
1054 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1055 }
1056
1057 #[test]
1058 fn explicit_allow_type_attr() {
1059 let policy_bytes =
1060 include_bytes!("../../testdata/micro_policies/allow_a_t_b_attr_class0_perm0_policy.pp");
1061 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1062 let policy = policy.validate().expect("validate policy");
1063
1064 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1065 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1066
1067 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1068 }
1069
1070 #[test]
1071 fn no_explicit_allow_type_attr() {
1072 let policy_bytes = include_bytes!(
1073 "../../testdata/micro_policies/no_allow_a_t_b_attr_class0_perm0_policy.pp"
1074 );
1075 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1076 let policy = policy.validate().expect("validate policy");
1077
1078 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1079 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1080
1081 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1082 }
1083
1084 #[test]
1085 fn explicit_allow_attr_attr() {
1086 let policy_bytes = include_bytes!(
1087 "../../testdata/micro_policies/allow_a_attr_b_attr_class0_perm0_policy.pp"
1088 );
1089 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1090 let policy = policy.validate().expect("validate policy");
1091
1092 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1093 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1094
1095 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1096 }
1097
1098 #[test]
1099 fn no_explicit_allow_attr_attr() {
1100 let policy_bytes = include_bytes!(
1101 "../../testdata/micro_policies/no_allow_a_attr_b_attr_class0_perm0_policy.pp"
1102 );
1103 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1104 let policy = policy.validate().expect("validate policy");
1105
1106 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1107 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1108
1109 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1110 }
1111
1112 #[test]
1113 fn compute_explicitly_allowed_multiple_attributes() {
1114 let policy_bytes = include_bytes!(
1115 "../../testdata/micro_policies/allow_a_t_a1_attr_class0_perm0_a2_attr_class0_perm1_policy.pp"
1116 );
1117 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1118 let policy = policy.validate().expect("validate policy");
1119
1120 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1121
1122 let class = policy
1123 .0
1124 .parsed_policy()
1125 .classes()
1126 .iter()
1127 .find(|class| class.name_bytes() == b"class0")
1128 .expect("class not found");
1129 let raw_access_vector =
1130 policy.0.parsed_policy().compute_explicitly_allowed(a_t, a_t, class).allow.0;
1131
1132 assert_eq!(2, raw_access_vector.count_ones());
1137 }
1138
1139 #[test]
1140 fn compute_access_decision_with_constraints() {
1141 let policy_bytes =
1142 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1143 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1144 let policy = policy.validate().expect("validate policy");
1145
1146 let source_context: SecurityContext = policy
1147 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1148 .expect("create source security context");
1149
1150 let target_context_satisfied: SecurityContext = source_context.clone();
1151 let decision_satisfied = policy.compute_access_decision(
1152 &source_context,
1153 &target_context_satisfied,
1154 KernelClass::File,
1155 );
1156 assert_eq!(decision_satisfied.allow, AccessVector(7));
1160
1161 let target_context_unsatisfied: SecurityContext = policy
1162 .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1163 .expect("create target security context failing some constraints");
1164 let decision_unsatisfied = policy.compute_access_decision(
1165 &source_context,
1166 &target_context_unsatisfied,
1167 KernelClass::File,
1168 );
1169 assert_eq!(decision_unsatisfied.allow, AccessVector(4));
1172 }
1173
1174 #[test]
1175 fn compute_ioctl_access_decision_explicitly_allowed() {
1176 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1177 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1178 let policy = policy.validate().expect("validate policy");
1179
1180 let source_context: SecurityContext = policy
1181 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1182 .expect("create source security context");
1183 let target_context_matched: SecurityContext = source_context.clone();
1184
1185 let decision_single = policy.compute_xperms_access_decision(
1203 XpermsKind::Ioctl,
1204 &source_context,
1205 &target_context_matched,
1206 KernelClass::File,
1207 0xab,
1208 );
1209
1210 let mut expected_auditdeny =
1211 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1212 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1213
1214 let expected_decision_single = XpermsAccessDecision {
1215 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1216 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1217 auditdeny: expected_auditdeny,
1218 };
1219 assert_eq!(decision_single, expected_decision_single);
1220
1221 let decision_range = policy.compute_xperms_access_decision(
1222 XpermsKind::Ioctl,
1223 &source_context,
1224 &target_context_matched,
1225 KernelClass::File,
1226 0x10,
1227 );
1228 let expected_decision_range = XpermsAccessDecision {
1229 allow: XpermsBitmap::ALL,
1230 auditallow: XpermsBitmap::ALL,
1231 auditdeny: XpermsBitmap::NONE,
1232 };
1233 assert_eq!(decision_range, expected_decision_range);
1234 }
1235
1236 #[test]
1237 fn compute_ioctl_access_decision_denied() {
1238 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1239 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1240 let class_id = find_class_by_name(unvalidated.0.classes(), "class_one_ioctl")
1241 .expect("look up class_one_ioctl")
1242 .id();
1243 let policy = unvalidated.validate().expect("validate policy");
1244 let source_context: SecurityContext = policy
1245 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1246 .expect("create source security context");
1247 let target_context_matched: SecurityContext = source_context.clone();
1248
1249 let decision_single = policy.compute_xperms_access_decision(
1253 XpermsKind::Ioctl,
1254 &source_context,
1255 &target_context_matched,
1256 class_id,
1257 0xdb,
1258 );
1259
1260 let expected_decision = XpermsAccessDecision {
1261 allow: XpermsBitmap::NONE,
1262 auditallow: XpermsBitmap::NONE,
1263 auditdeny: XpermsBitmap::ALL,
1264 };
1265 assert_eq!(decision_single, expected_decision);
1266 }
1267
1268 #[test]
1269 fn compute_ioctl_access_decision_unmatched() {
1270 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1271 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1272 let policy = policy.validate().expect("validate policy");
1273
1274 let source_context: SecurityContext = policy
1275 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1276 .expect("create source security context");
1277
1278 let target_context_unmatched: SecurityContext = policy
1280 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1281 .expect("create source security context");
1282
1283 for prefix in 0x0..=0xff {
1284 let decision = policy.compute_xperms_access_decision(
1285 XpermsKind::Ioctl,
1286 &source_context,
1287 &target_context_unmatched,
1288 KernelClass::File,
1289 prefix,
1290 );
1291 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1292 }
1293 }
1294
1295 #[test]
1296 fn compute_ioctl_earlier_redundant_prefixful_not_coalesced_into_prefixless() {
1297 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1298 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1299 let class_id = find_class_by_name(
1300 unvalidated.0.classes(),
1301 "class_earlier_redundant_prefixful_not_coalesced_into_prefixless",
1302 )
1303 .expect("look up class_earlier_redundant_prefixful_not_coalesced_into_prefixless")
1304 .id();
1305 let policy = unvalidated.validate().expect("validate policy");
1306 let source_context: SecurityContext = policy
1307 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1308 .expect("create source security context");
1309 let target_context_matched: SecurityContext = source_context.clone();
1310
1311 let decision = policy.compute_xperms_access_decision(
1316 XpermsKind::Ioctl,
1317 &source_context,
1318 &target_context_matched,
1319 class_id,
1320 0x7f,
1321 );
1322 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1323 let decision = policy.compute_xperms_access_decision(
1324 XpermsKind::Ioctl,
1325 &source_context,
1326 &target_context_matched,
1327 class_id,
1328 0x80,
1329 );
1330 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1331 let decision = policy.compute_xperms_access_decision(
1332 XpermsKind::Ioctl,
1333 &source_context,
1334 &target_context_matched,
1335 class_id,
1336 0x81,
1337 );
1338 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1339 }
1340
1341 #[test]
1342 fn compute_ioctl_later_redundant_prefixful_not_coalesced_into_prefixless() {
1343 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1344 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1345 let class_id = find_class_by_name(
1346 unvalidated.0.classes(),
1347 "class_later_redundant_prefixful_not_coalesced_into_prefixless",
1348 )
1349 .expect("look up class_later_redundant_prefixful_not_coalesced_into_prefixless")
1350 .id();
1351 let policy = unvalidated.validate().expect("validate policy");
1352 let source_context: SecurityContext = policy
1353 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1354 .expect("create source security context");
1355 let target_context_matched: SecurityContext = source_context.clone();
1356
1357 let decision = policy.compute_xperms_access_decision(
1362 XpermsKind::Ioctl,
1363 &source_context,
1364 &target_context_matched,
1365 class_id,
1366 0x8f,
1367 );
1368 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1369 let decision = policy.compute_xperms_access_decision(
1370 XpermsKind::Ioctl,
1371 &source_context,
1372 &target_context_matched,
1373 class_id,
1374 0x90,
1375 );
1376 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1377 let decision = policy.compute_xperms_access_decision(
1378 XpermsKind::Ioctl,
1379 &source_context,
1380 &target_context_matched,
1381 class_id,
1382 0x91,
1383 );
1384 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1385 }
1386
1387 #[test]
1388 fn compute_ioctl_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless() {
1389 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1390 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1391 let class_id = find_class_by_name(
1392 unvalidated.0.classes(),
1393 "class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless",
1394 )
1395 .expect("look up class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless")
1396 .id();
1397 let policy = unvalidated.validate().expect("validate policy");
1398 let source_context: SecurityContext = policy
1399 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1400 .expect("create source security context");
1401 let target_context_matched: SecurityContext = source_context.clone();
1402
1403 let decision = policy.compute_xperms_access_decision(
1409 XpermsKind::Ioctl,
1410 &source_context,
1411 &target_context_matched,
1412 class_id,
1413 0x9f,
1414 );
1415 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1416 let decision = policy.compute_xperms_access_decision(
1417 XpermsKind::Ioctl,
1418 &source_context,
1419 &target_context_matched,
1420 class_id,
1421 0xa0,
1422 );
1423 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1424 let decision = policy.compute_xperms_access_decision(
1425 XpermsKind::Ioctl,
1426 &source_context,
1427 &target_context_matched,
1428 class_id,
1429 0xa1,
1430 );
1431 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1432 }
1433
1434 #[test]
1435 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless() {
1436 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1437 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1438 let class_id = find_class_by_name(
1439 unvalidated.0.classes(),
1440 "class_prefixfuls_that_coalesce_to_prefixless",
1441 )
1442 .expect("look up class_prefixfuls_that_coalesce_to_prefixless")
1443 .id();
1444 let policy = unvalidated.validate().expect("validate policy");
1445 let source_context: SecurityContext = policy
1446 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1447 .expect("create source security context");
1448 let target_context_matched: SecurityContext = source_context.clone();
1449
1450 let decision = policy.compute_xperms_access_decision(
1456 XpermsKind::Ioctl,
1457 &source_context,
1458 &target_context_matched,
1459 class_id,
1460 0xaf,
1461 );
1462 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1463 let decision = policy.compute_xperms_access_decision(
1464 XpermsKind::Ioctl,
1465 &source_context,
1466 &target_context_matched,
1467 class_id,
1468 0xb0,
1469 );
1470 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1471 let decision = policy.compute_xperms_access_decision(
1472 XpermsKind::Ioctl,
1473 &source_context,
1474 &target_context_matched,
1475 class_id,
1476 0xb1,
1477 );
1478 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1479 }
1480
1481 #[test]
1482 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless() {
1483 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1484 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1485 let class_id = find_class_by_name(
1486 unvalidated.0.classes(),
1487 "class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless",
1488 )
1489 .expect("look up class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless")
1490 .id();
1491 let policy = unvalidated.validate().expect("validate policy");
1492 let source_context: SecurityContext = policy
1493 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1494 .expect("create source security context");
1495 let target_context_matched: SecurityContext = source_context.clone();
1496
1497 let decision = policy.compute_xperms_access_decision(
1504 XpermsKind::Ioctl,
1505 &source_context,
1506 &target_context_matched,
1507 class_id,
1508 0xbf,
1509 );
1510 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1511 let decision = policy.compute_xperms_access_decision(
1512 XpermsKind::Ioctl,
1513 &source_context,
1514 &target_context_matched,
1515 class_id,
1516 0xc0,
1517 );
1518 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1519 let decision = policy.compute_xperms_access_decision(
1520 XpermsKind::Ioctl,
1521 &source_context,
1522 &target_context_matched,
1523 class_id,
1524 0xc1,
1525 );
1526 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1527 let decision = policy.compute_xperms_access_decision(
1528 XpermsKind::Ioctl,
1529 &source_context,
1530 &target_context_matched,
1531 class_id,
1532 0xc2,
1533 );
1534 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1535 }
1536
1537 #[test]
1538 fn compute_ioctl_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless() {
1539 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1540 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1541 let class_id = find_class_by_name(
1542 unvalidated.0.classes(),
1543 "class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless",
1544 )
1545 .expect("look up class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless")
1546 .id();
1547 let policy = unvalidated.validate().expect("validate policy");
1548 let source_context: SecurityContext = policy
1549 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1550 .expect("create source security context");
1551 let target_context_matched: SecurityContext = source_context.clone();
1552
1553 let decision = policy.compute_xperms_access_decision(
1560 XpermsKind::Ioctl,
1561 &source_context,
1562 &target_context_matched,
1563 class_id,
1564 0xd5,
1565 );
1566 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1567 let decision = policy.compute_xperms_access_decision(
1568 XpermsKind::Ioctl,
1569 &source_context,
1570 &target_context_matched,
1571 class_id,
1572 0xd6,
1573 );
1574 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1575 let decision = policy.compute_xperms_access_decision(
1576 XpermsKind::Ioctl,
1577 &source_context,
1578 &target_context_matched,
1579 class_id,
1580 0xd7,
1581 );
1582 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1583 let decision = policy.compute_xperms_access_decision(
1584 XpermsKind::Ioctl,
1585 &source_context,
1586 &target_context_matched,
1587 class_id,
1588 0xd8,
1589 );
1590 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1591 }
1592
1593 #[test]
1604 fn compute_ioctl_ridiculous_permission_ordering() {
1605 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1606 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1607 let class_id =
1608 find_class_by_name(unvalidated.0.classes(), "class_ridiculous_permission_ordering")
1609 .expect("look up class_ridiculous_permission_ordering")
1610 .id();
1611 let policy = unvalidated.validate().expect("validate policy");
1612 let source_context: SecurityContext = policy
1613 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1614 .expect("create source security context");
1615 let target_context_matched: SecurityContext = source_context.clone();
1616
1617 let decision = policy.compute_xperms_access_decision(
1622 XpermsKind::Ioctl,
1623 &source_context,
1624 &target_context_matched,
1625 class_id,
1626 0x00,
1627 );
1628 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1629 let decision = policy.compute_xperms_access_decision(
1630 XpermsKind::Ioctl,
1631 &source_context,
1632 &target_context_matched,
1633 class_id,
1634 0x01,
1635 );
1636 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1637 let decision = policy.compute_xperms_access_decision(
1638 XpermsKind::Ioctl,
1639 &source_context,
1640 &target_context_matched,
1641 class_id,
1642 0xbf,
1643 );
1644 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1645 let decision = policy.compute_xperms_access_decision(
1646 XpermsKind::Ioctl,
1647 &source_context,
1648 &target_context_matched,
1649 class_id,
1650 0xc0,
1651 );
1652 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1653 let decision = policy.compute_xperms_access_decision(
1654 XpermsKind::Ioctl,
1655 &source_context,
1656 &target_context_matched,
1657 class_id,
1658 0xce,
1659 );
1660 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1661 let decision = policy.compute_xperms_access_decision(
1662 XpermsKind::Ioctl,
1663 &source_context,
1664 &target_context_matched,
1665 class_id,
1666 0xcf,
1667 );
1668 assert_eq!(
1669 decision,
1670 XpermsAccessDecision {
1671 allow: xperms_bitmap_from_elements((0x0..=0xf2).collect::<Vec<_>>().as_slice()),
1672 auditallow: XpermsBitmap::NONE,
1673 auditdeny: XpermsBitmap::ALL,
1674 }
1675 );
1676 let decision = policy.compute_xperms_access_decision(
1677 XpermsKind::Ioctl,
1678 &source_context,
1679 &target_context_matched,
1680 class_id,
1681 0xd0,
1682 );
1683 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1684 let decision = policy.compute_xperms_access_decision(
1685 XpermsKind::Ioctl,
1686 &source_context,
1687 &target_context_matched,
1688 class_id,
1689 0xe9,
1690 );
1691 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1692 let decision = policy.compute_xperms_access_decision(
1693 XpermsKind::Ioctl,
1694 &source_context,
1695 &target_context_matched,
1696 class_id,
1697 0xf0,
1698 );
1699 assert_eq!(
1700 decision,
1701 XpermsAccessDecision {
1702 allow: xperms_bitmap_from_elements(&[0x01]),
1703 auditallow: XpermsBitmap::NONE,
1704 auditdeny: XpermsBitmap::ALL,
1705 }
1706 );
1707 let decision = policy.compute_xperms_access_decision(
1708 XpermsKind::Ioctl,
1709 &source_context,
1710 &target_context_matched,
1711 class_id,
1712 0xf1,
1713 );
1714 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1715 let decision = policy.compute_xperms_access_decision(
1716 XpermsKind::Ioctl,
1717 &source_context,
1718 &target_context_matched,
1719 class_id,
1720 0xfc,
1721 );
1722 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1723 let decision = policy.compute_xperms_access_decision(
1724 XpermsKind::Ioctl,
1725 &source_context,
1726 &target_context_matched,
1727 class_id,
1728 0xfd,
1729 );
1730 assert_eq!(
1731 decision,
1732 XpermsAccessDecision {
1733 allow: xperms_bitmap_from_elements((0xfa..=0xfd).collect::<Vec<_>>().as_slice()),
1734 auditallow: XpermsBitmap::NONE,
1735 auditdeny: XpermsBitmap::ALL,
1736 }
1737 );
1738 let decision = policy.compute_xperms_access_decision(
1739 XpermsKind::Ioctl,
1740 &source_context,
1741 &target_context_matched,
1742 class_id,
1743 0xfe,
1744 );
1745 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1746 }
1747
1748 #[test]
1749 fn compute_nlmsg_access_decision_explicitly_allowed() {
1750 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1751 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1752 let policy = policy.validate().expect("validate policy");
1753
1754 let source_context: SecurityContext = policy
1755 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1756 .expect("create source security context");
1757 let target_context_matched: SecurityContext = source_context.clone();
1758
1759 let decision_single = policy.compute_xperms_access_decision(
1777 XpermsKind::Nlmsg,
1778 &source_context,
1779 &target_context_matched,
1780 KernelClass::NetlinkRouteSocket,
1781 0xab,
1782 );
1783
1784 let mut expected_auditdeny =
1785 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1786 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1787
1788 let expected_decision_single = XpermsAccessDecision {
1789 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1790 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1791 auditdeny: expected_auditdeny,
1792 };
1793 assert_eq!(decision_single, expected_decision_single);
1794
1795 let decision_range = policy.compute_xperms_access_decision(
1796 XpermsKind::Nlmsg,
1797 &source_context,
1798 &target_context_matched,
1799 KernelClass::NetlinkRouteSocket,
1800 0x10,
1801 );
1802 let expected_decision_range = XpermsAccessDecision {
1803 allow: XpermsBitmap::ALL,
1804 auditallow: XpermsBitmap::ALL,
1805 auditdeny: XpermsBitmap::NONE,
1806 };
1807 assert_eq!(decision_range, expected_decision_range);
1808 }
1809
1810 #[test]
1811 fn compute_nlmsg_access_decision_unmatched() {
1812 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1813 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1814 let policy = policy.validate().expect("validate policy");
1815
1816 let source_context: SecurityContext = policy
1817 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1818 .expect("create source security context");
1819
1820 let target_context_unmatched: SecurityContext = policy
1822 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1823 .expect("create source security context");
1824
1825 for prefix in 0x0..=0xff {
1826 let decision = policy.compute_xperms_access_decision(
1827 XpermsKind::Nlmsg,
1828 &source_context,
1829 &target_context_unmatched,
1830 KernelClass::NetlinkRouteSocket,
1831 prefix,
1832 );
1833 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1834 }
1835 }
1836
1837 #[test]
1838 fn compute_ioctl_grant_does_not_cause_nlmsg_deny() {
1839 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1840 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1841 let class_id = find_class_by_name(
1842 unvalidated.0.classes(),
1843 "class_ioctl_grant_does_not_cause_nlmsg_deny",
1844 )
1845 .expect("look up class_ioctl_grant_does_not_cause_nlmsg_deny")
1846 .id();
1847 let policy = unvalidated.validate().expect("validate policy");
1848 let source_context: SecurityContext = policy
1849 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1850 .expect("create source security context");
1851 let target_context_matched: SecurityContext = source_context.clone();
1852
1853 let ioctl_decision = policy.compute_xperms_access_decision(
1857 XpermsKind::Ioctl,
1858 &source_context,
1859 &target_context_matched,
1860 class_id,
1861 0x00,
1862 );
1863 assert_eq!(
1864 ioctl_decision,
1865 XpermsAccessDecision {
1866 allow: xperms_bitmap_from_elements(&[0x0002]),
1867 auditallow: XpermsBitmap::NONE,
1868 auditdeny: XpermsBitmap::ALL,
1869 }
1870 );
1871 let nlmsg_decision = policy.compute_xperms_access_decision(
1872 XpermsKind::Nlmsg,
1873 &source_context,
1874 &target_context_matched,
1875 class_id,
1876 0x00,
1877 );
1878 assert_eq!(nlmsg_decision, XpermsAccessDecision::ALLOW_ALL);
1879 }
1880
1881 #[test]
1882 fn compute_nlmsg_grant_does_not_cause_ioctl_deny() {
1883 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1884 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1885 let class_id = find_class_by_name(
1886 unvalidated.0.classes(),
1887 "class_nlmsg_grant_does_not_cause_ioctl_deny",
1888 )
1889 .expect("look up class_nlmsg_grant_does_not_cause_ioctl_deny")
1890 .id();
1891 let policy = unvalidated.validate().expect("validate policy");
1892 let source_context: SecurityContext = policy
1893 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1894 .expect("create source security context");
1895 let target_context_matched: SecurityContext = source_context.clone();
1896
1897 let nlmsg_decision = policy.compute_xperms_access_decision(
1901 XpermsKind::Nlmsg,
1902 &source_context,
1903 &target_context_matched,
1904 class_id,
1905 0x00,
1906 );
1907 assert_eq!(
1908 nlmsg_decision,
1909 XpermsAccessDecision {
1910 allow: xperms_bitmap_from_elements(&[0x0003]),
1911 auditallow: XpermsBitmap::NONE,
1912 auditdeny: XpermsBitmap::ALL,
1913 }
1914 );
1915 let ioctl_decision = policy.compute_xperms_access_decision(
1916 XpermsKind::Ioctl,
1917 &source_context,
1918 &target_context_matched,
1919 class_id,
1920 0x00,
1921 );
1922 assert_eq!(ioctl_decision, XpermsAccessDecision::ALLOW_ALL);
1923 }
1924
1925 #[test]
1926 fn compute_create_context_minimal() {
1927 let policy_bytes =
1928 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1929 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1930 let policy = policy.validate().expect("validate policy");
1931 let source = policy
1932 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1933 .expect("valid source security context");
1934 let target = policy
1935 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1936 .expect("valid target security context");
1937
1938 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1939 let expected: SecurityContext = policy
1940 .parse_security_context(b"source_u:object_r:target_t:s0:c0".into())
1941 .expect("valid expected security context");
1942
1943 assert_eq!(expected, actual);
1944 }
1945
1946 #[test]
1947 fn new_security_context_minimal() {
1948 let policy_bytes =
1949 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1950 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1951 let policy = policy.validate().expect("validate policy");
1952 let source = policy
1953 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1954 .expect("valid source security context");
1955 let target = policy
1956 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1957 .expect("valid target security context");
1958
1959 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1960
1961 assert_eq!(source, actual);
1962 }
1963
1964 #[test]
1965 fn compute_create_context_class_defaults() {
1966 let policy_bytes =
1967 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1968 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1969 let policy = policy.validate().expect("validate policy");
1970 let source = policy
1971 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1972 .expect("valid source security context");
1973 let target = policy
1974 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1975 .expect("valid target security context");
1976
1977 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1978 let expected: SecurityContext = policy
1979 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1980 .expect("valid expected security context");
1981
1982 assert_eq!(expected, actual);
1983 }
1984
1985 #[test]
1986 fn new_security_context_class_defaults() {
1987 let policy_bytes =
1988 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1989 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1990 let policy = policy.validate().expect("validate policy");
1991 let source = policy
1992 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1993 .expect("valid source security context");
1994 let target = policy
1995 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1996 .expect("valid target security context");
1997
1998 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1999 let expected: SecurityContext = policy
2000 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
2001 .expect("valid expected security context");
2002
2003 assert_eq!(expected, actual);
2004 }
2005
2006 #[test]
2007 fn compute_create_context_role_transition() {
2008 let policy_bytes =
2009 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
2010 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2011 let policy = policy.validate().expect("validate policy");
2012 let source = policy
2013 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2014 .expect("valid source security context");
2015 let target = policy
2016 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2017 .expect("valid target security context");
2018
2019 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2020 let expected: SecurityContext = policy
2021 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
2022 .expect("valid expected security context");
2023
2024 assert_eq!(expected, actual);
2025 }
2026
2027 #[test]
2028 fn new_security_context_role_transition() {
2029 let policy_bytes =
2030 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
2031 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2032 let policy = policy.validate().expect("validate policy");
2033 let source = policy
2034 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2035 .expect("valid source security context");
2036 let target = policy
2037 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2038 .expect("valid target security context");
2039
2040 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2041 let expected: SecurityContext = policy
2042 .parse_security_context(b"source_u:transition_r:source_t:s0:c0-s2:c0.c1".into())
2043 .expect("valid expected security context");
2044
2045 assert_eq!(expected, actual);
2046 }
2047
2048 #[test]
2049 #[ignore]
2051 fn compute_create_context_role_transition_not_allowed() {
2052 let policy_bytes = include_bytes!(
2053 "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy.pp"
2054 );
2055 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2056 let policy = policy.validate().expect("validate policy");
2057 let source = policy
2058 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2059 .expect("valid source security context");
2060 let target = policy
2061 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2062 .expect("valid target security context");
2063
2064 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2065
2066 assert!(policy.validate_security_context(&actual).is_err());
2068 }
2069
2070 #[test]
2071 fn compute_create_context_type_transition() {
2072 let policy_bytes =
2073 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
2074 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2075 let policy = policy.validate().expect("validate policy");
2076 let source = policy
2077 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2078 .expect("valid source security context");
2079 let target = policy
2080 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2081 .expect("valid target security context");
2082
2083 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2084 let expected: SecurityContext = policy
2085 .parse_security_context(b"source_u:object_r:transition_t:s0:c0".into())
2086 .expect("valid expected security context");
2087
2088 assert_eq!(expected, actual);
2089 }
2090
2091 #[test]
2092 fn new_security_context_type_transition() {
2093 let policy_bytes =
2094 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
2095 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2096 let policy = policy.validate().expect("validate policy");
2097 let source = policy
2098 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2099 .expect("valid source security context");
2100 let target = policy
2101 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2102 .expect("valid target security context");
2103
2104 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2105 let expected: SecurityContext = policy
2106 .parse_security_context(b"source_u:source_r:transition_t:s0:c0-s2:c0.c1".into())
2107 .expect("valid expected security context");
2108
2109 assert_eq!(expected, actual);
2110 }
2111
2112 #[test]
2113 fn compute_create_context_range_transition() {
2114 let policy_bytes =
2115 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
2116 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2117 let policy = policy.validate().expect("validate policy");
2118 let source = policy
2119 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2120 .expect("valid source security context");
2121 let target = policy
2122 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2123 .expect("valid target security context");
2124
2125 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2126 let expected: SecurityContext = policy
2127 .parse_security_context(b"source_u:object_r:target_t:s1:c1-s2:c1.c2".into())
2128 .expect("valid expected security context");
2129
2130 assert_eq!(expected, actual);
2131 }
2132
2133 #[test]
2134 fn new_security_context_range_transition() {
2135 let policy_bytes =
2136 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
2137 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2138 let policy = policy.validate().expect("validate policy");
2139 let source = policy
2140 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2141 .expect("valid source security context");
2142 let target = policy
2143 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2144 .expect("valid target security context");
2145
2146 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2147 let expected: SecurityContext = policy
2148 .parse_security_context(b"source_u:source_r:source_t:s1:c1-s2:c1.c2".into())
2149 .expect("valid expected security context");
2150
2151 assert_eq!(expected, actual);
2152 }
2153
2154 #[test]
2155 fn access_vector_formats() {
2156 assert_eq!(format!("{:x}", AccessVector::NONE), "0");
2157 assert_eq!(format!("{:x}", AccessVector::ALL), "ffffffff");
2158 assert_eq!(format!("{:?}", AccessVector::NONE), "AccessVector(00000000)");
2159 assert_eq!(format!("{:?}", AccessVector::ALL), "AccessVector(ffffffff)");
2160 }
2161}