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::{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(NonZeroU32);
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_by_name(name).map(|x| x.id())
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 access_vector_from_permissions<
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_info) = self.0.permission(&permission.clone().into()) {
510 access_vector |= AccessVector::from_class_permission_id(permission_info.id());
512 } else {
513 if self.0.parsed_policy().handle_unknown() != HandleUnknown::Allow {
515 return None;
516 }
517 }
518 }
519 Some(access_vector)
520 }
521}
522
523pub struct Unvalidated(ParsedPolicy);
525
526impl Unvalidated {
527 pub fn validate(self) -> Result<Policy, anyhow::Error> {
528 self.0.validate().context("validating parsed policy")?;
529 let index = PolicyIndex::new(self.0).context("building index")?;
530 Ok(Policy(index))
531 }
532}
533
534pub trait AccessVectorComputer {
537 fn access_vector_from_permissions<
544 P: ClassPermission + Into<KernelPermission> + Clone + 'static,
545 >(
546 &self,
547 permissions: &[P],
548 ) -> Option<AccessVector>;
549}
550
551pub trait Parse: Sized {
553 type Error: Into<anyhow::Error>;
556
557 fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error>;
560}
561
562pub(super) trait ParseSlice: Sized {
564 type Error: Into<anyhow::Error>;
567
568 fn parse_slice(bytes: PolicyCursor, count: usize) -> Result<(Self, PolicyCursor), Self::Error>;
571}
572
573pub(super) struct PolicyValidationContext {
575 #[allow(unused)]
577 pub(super) data: PolicyData,
578}
579
580pub(super) trait Validate {
582 type Error: Into<anyhow::Error>;
585
586 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error>;
588}
589
590pub(super) trait ValidateArray<M, D> {
591 type Error: Into<anyhow::Error>;
594
595 fn validate_array(
597 context: &mut PolicyValidationContext,
598 metadata: &M,
599 items: &[D],
600 ) -> Result<(), Self::Error>;
601}
602
603pub(super) trait Counted {
605 fn count(&self) -> u32;
607}
608
609impl<T: Validate> Validate for Option<T> {
610 type Error = <T as Validate>::Error;
611
612 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
613 match self {
614 Some(value) => value.validate(context),
615 None => Ok(()),
616 }
617 }
618}
619
620impl Validate for le::U32 {
621 type Error = anyhow::Error;
622
623 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
626 Ok(())
627 }
628}
629
630impl Validate for u8 {
631 type Error = anyhow::Error;
632
633 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
636 Ok(())
637 }
638}
639
640impl Validate for [u8] {
641 type Error = anyhow::Error;
642
643 fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
646 Ok(())
647 }
648}
649
650impl<B: SplitByteSlice, T: Validate + FromBytes + KnownLayout + Immutable> Validate for Ref<B, T> {
651 type Error = <T as Validate>::Error;
652
653 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
654 self.deref().validate(context)
655 }
656}
657
658impl<B: SplitByteSlice, T: Counted + FromBytes + KnownLayout + Immutable> Counted for Ref<B, T> {
659 fn count(&self) -> u32 {
660 self.deref().count()
661 }
662}
663
664#[derive(Clone, Debug, PartialEq)]
667struct Array<M, D> {
668 metadata: M,
669 data: D,
670}
671
672impl<M: Counted + Parse, D: ParseSlice> Parse for Array<M, D> {
673 type Error = anyhow::Error;
676
677 fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
679 let tail = bytes;
680
681 let (metadata, tail) = M::parse(tail).map_err(Into::<anyhow::Error>::into)?;
682
683 let (data, tail) =
684 D::parse_slice(tail, metadata.count() as usize).map_err(Into::<anyhow::Error>::into)?;
685
686 let array = Self { metadata, data };
687
688 Ok((array, tail))
689 }
690}
691
692impl<T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned> Parse for T {
693 type Error = anyhow::Error;
694
695 fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
696 bytes.parse::<T>().map_err(anyhow::Error::from)
697 }
698}
699
700macro_rules! array_type {
704 ($type_name:ident, $metadata_type:ty, $data_type:ty, $metadata_type_name:expr, $data_type_name:expr) => {
705 #[doc = "An [`Array`] with [`"]
706 #[doc = $metadata_type_name]
707 #[doc = "`] metadata and [`"]
708 #[doc = $data_type_name]
709 #[doc = "`] data items."]
710 #[derive(Debug, PartialEq)]
711 pub(super) struct $type_name(super::Array<$metadata_type, $data_type>);
712
713 impl std::ops::Deref for $type_name {
714 type Target = super::Array<$metadata_type, $data_type>;
715
716 fn deref(&self) -> &Self::Target {
717 &self.0
718 }
719 }
720
721 impl super::Parse for $type_name
722 where
723 super::Array<$metadata_type, $data_type>: super::Parse,
724 {
725 type Error = <Array<$metadata_type, $data_type> as super::Parse>::Error;
726
727 fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
728 let (array, tail) = Array::<$metadata_type, $data_type>::parse(bytes)?;
729 Ok((Self(array), tail))
730 }
731 }
732 };
733
734 ($type_name:ident, $metadata_type:ty, $data_type:ty) => {
735 array_type!(
736 $type_name,
737 $metadata_type,
738 $data_type,
739 stringify!($metadata_type),
740 stringify!($data_type)
741 );
742 };
743}
744
745pub(super) use array_type;
746
747macro_rules! array_type_validate_deref_both {
748 ($type_name:ident) => {
749 impl Validate for $type_name {
750 type Error = anyhow::Error;
751
752 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
753 let metadata = &self.metadata;
754 metadata.validate(context)?;
755
756 let items = &self.data;
757 items.validate(context)?;
758
759 Self::validate_array(context, metadata, items).map_err(Into::<anyhow::Error>::into)
760 }
761 }
762 };
763}
764
765pub(super) use array_type_validate_deref_both;
766
767macro_rules! array_type_validate_deref_data {
768 ($type_name:ident) => {
769 impl Validate for $type_name {
770 type Error = anyhow::Error;
771
772 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
773 let metadata = &self.metadata;
774 metadata.validate(context)?;
775
776 let items = &self.data;
777 items.validate(context)?;
778
779 Self::validate_array(context, metadata, items)
780 }
781 }
782 };
783}
784
785pub(super) use array_type_validate_deref_data;
786
787macro_rules! array_type_validate_deref_metadata_data_vec {
788 ($type_name:ident) => {
789 impl Validate for $type_name {
790 type Error = anyhow::Error;
791
792 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
793 let metadata = &self.metadata;
794 metadata.validate(context)?;
795
796 let items = &self.data;
797 items.validate(context)?;
798
799 Self::validate_array(context, metadata, items.as_slice())
800 }
801 }
802 };
803}
804
805pub(super) use array_type_validate_deref_metadata_data_vec;
806
807macro_rules! array_type_validate_deref_none_data_vec {
808 ($type_name:ident) => {
809 impl Validate for $type_name {
810 type Error = anyhow::Error;
811
812 fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
813 let metadata = &self.metadata;
814 metadata.validate(context)?;
815
816 let items = &self.data;
817 items.validate(context)?;
818
819 Self::validate_array(context, metadata, items.as_slice())
820 }
821 }
822 };
823}
824
825pub(super) use array_type_validate_deref_none_data_vec;
826
827impl<T: Parse> ParseSlice for Vec<T> {
828 type Error = anyhow::Error;
831
832 fn parse_slice(bytes: PolicyCursor, count: usize) -> Result<(Self, PolicyCursor), Self::Error> {
834 let mut slice = Vec::with_capacity(count);
835 let mut tail = bytes;
836
837 for _ in 0..count {
838 let (item, next_tail) = T::parse(tail).map_err(Into::<anyhow::Error>::into)?;
839 slice.push(item);
840 tail = next_tail;
841 }
842
843 Ok((slice, tail))
844 }
845}
846
847#[cfg(test)]
848pub(super) mod testing {
849 use super::AccessVector;
850 use super::error::{ParseError, ValidateError};
851
852 pub const ACCESS_VECTOR_0001: AccessVector = AccessVector(0b0001u32);
853 pub const ACCESS_VECTOR_0010: AccessVector = AccessVector(0b0010u32);
854
855 pub(super) fn as_parse_error(error: anyhow::Error) -> ParseError {
857 error.downcast::<ParseError>().expect("parse error")
858 }
859
860 pub(super) fn as_validate_error(error: anyhow::Error) -> ValidateError {
862 error.downcast::<ValidateError>().expect("validate error")
863 }
864}
865
866#[cfg(test)]
867pub(super) mod tests {
868 use super::arrays::XpermsBitmap;
869 use super::metadata::HandleUnknown;
870 use super::security_context::SecurityContext;
871 use super::symbols::find_class_by_name;
872 use super::{
873 AccessVector, Policy, TypeId, XpermsAccessDecision, XpermsKind, parse_policy_by_value,
874 };
875 use crate::{FileClass, InitialSid, KernelClass};
876
877 use anyhow::Context as _;
878 use serde::Deserialize;
879 use std::ops::{Deref, Shl};
880 use zerocopy::little_endian as le;
881
882 fn is_explicitly_allowed(
890 policy: &Policy,
891 source_type: TypeId,
892 target_type: TypeId,
893 target_class: &str,
894 permission: &str,
895 ) -> bool {
896 let class = policy
897 .0
898 .parsed_policy()
899 .classes()
900 .iter()
901 .find(|class| class.name_bytes() == target_class.as_bytes())
902 .expect("class not found");
903 let class_permissions = policy
904 .find_class_permissions_by_name(target_class)
905 .expect("class permissions not found");
906 let (permission_id, _) = class_permissions
907 .iter()
908 .find(|(_, name)| permission.as_bytes() == name)
909 .expect("permission not found");
910 let permission_bit = AccessVector::from_class_permission_id(*permission_id);
911 let access_decision =
912 policy.0.parsed_policy().compute_explicitly_allowed(source_type, target_type, class);
913 permission_bit == access_decision.allow & permission_bit
914 }
915
916 #[derive(Debug, Deserialize)]
917 struct Expectations {
918 expected_policy_version: u32,
919 expected_handle_unknown: LocalHandleUnknown,
920 }
921
922 #[derive(Debug, Deserialize, PartialEq)]
923 #[serde(rename_all = "snake_case")]
924 enum LocalHandleUnknown {
925 Deny,
926 Reject,
927 Allow,
928 }
929
930 impl PartialEq<HandleUnknown> for LocalHandleUnknown {
931 fn eq(&self, other: &HandleUnknown) -> bool {
932 match self {
933 LocalHandleUnknown::Deny => *other == HandleUnknown::Deny,
934 LocalHandleUnknown::Reject => *other == HandleUnknown::Reject,
935 LocalHandleUnknown::Allow => *other == HandleUnknown::Allow,
936 }
937 }
938 }
939
940 fn xperms_bitmap_from_elements(elements: &[u8]) -> XpermsBitmap {
943 let mut bitmap = [le::U32::ZERO; 8];
944 for element in elements {
945 let block_index = (*element as usize) / 32;
946 let bit_index = ((*element as usize) % 32) as u32;
947 let bitmask = le::U32::new(1).shl(bit_index);
948 bitmap[block_index] = bitmap[block_index] | bitmask;
949 }
950 XpermsBitmap::new(bitmap)
951 }
952
953 #[test]
954 fn known_policies() {
955 let policies_and_expectations = [
956 [
957 b"testdata/policies/emulator".to_vec(),
958 include_bytes!("../../testdata/policies/emulator").to_vec(),
959 include_bytes!("../../testdata/expectations/emulator").to_vec(),
960 ],
961 [
962 b"testdata/policies/selinux_testsuite".to_vec(),
963 include_bytes!("../../testdata/policies/selinux_testsuite").to_vec(),
964 include_bytes!("../../testdata/expectations/selinux_testsuite").to_vec(),
965 ],
966 ];
967
968 for [policy_path, policy_bytes, expectations_bytes] in policies_and_expectations {
969 let expectations = serde_json5::from_reader::<_, Expectations>(
970 &mut std::io::Cursor::new(expectations_bytes),
971 )
972 .expect("deserialize expectations");
973
974 let unvalidated_policy =
977 parse_policy_by_value(policy_bytes.clone()).expect("parse policy");
978
979 let policy = unvalidated_policy
980 .validate()
981 .with_context(|| {
982 format!(
983 "policy path: {:?}",
984 std::str::from_utf8(policy_path.as_slice()).unwrap()
985 )
986 })
987 .expect("validate policy");
988
989 assert_eq!(expectations.expected_policy_version, policy.policy_version());
990 assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
991
992 let binary_policy = policy.binary().clone();
994 assert_eq!(&policy_bytes, binary_policy.deref());
995 }
996 }
997
998 #[test]
999 fn policy_lookup() {
1000 let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
1001 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1002 let policy = policy.validate().expect("validate selinux testsuite policy");
1003
1004 let unconfined_t = policy.type_id_by_name("unconfined_t").expect("look up type id");
1005
1006 assert!(is_explicitly_allowed(&policy, unconfined_t, unconfined_t, "process", "fork",));
1007 }
1008
1009 #[test]
1010 fn initial_contexts() {
1011 let policy_bytes = include_bytes!(
1012 "../../testdata/micro_policies/multiple_levels_and_categories_policy.pp"
1013 );
1014 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1015 let policy = policy.validate().expect("validate policy");
1016
1017 let kernel_context = policy.initial_context(InitialSid::Kernel);
1018 assert_eq!(
1019 policy.serialize_security_context(&kernel_context),
1020 b"user0:object_r:type0:s0:c0-s1:c0.c2,c4"
1021 )
1022 }
1023
1024 #[test]
1025 fn explicit_allow_type_type() {
1026 let policy_bytes =
1027 include_bytes!("../../testdata/micro_policies/allow_a_t_b_t_class0_perm0_policy.pp");
1028 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1029 let policy = policy.validate().expect("validate policy");
1030
1031 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1032 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1033
1034 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1035 }
1036
1037 #[test]
1038 fn no_explicit_allow_type_type() {
1039 let policy_bytes =
1040 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_t_class0_perm0_policy.pp");
1041 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1042 let policy = policy.validate().expect("validate policy");
1043
1044 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1045 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1046
1047 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1048 }
1049
1050 #[test]
1051 fn explicit_allow_type_attr() {
1052 let policy_bytes =
1053 include_bytes!("../../testdata/micro_policies/allow_a_t_b_attr_class0_perm0_policy.pp");
1054 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1055 let policy = policy.validate().expect("validate policy");
1056
1057 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1058 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1059
1060 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1061 }
1062
1063 #[test]
1064 fn no_explicit_allow_type_attr() {
1065 let policy_bytes = include_bytes!(
1066 "../../testdata/micro_policies/no_allow_a_t_b_attr_class0_perm0_policy.pp"
1067 );
1068 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1069 let policy = policy.validate().expect("validate policy");
1070
1071 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1072 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1073
1074 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1075 }
1076
1077 #[test]
1078 fn explicit_allow_attr_attr() {
1079 let policy_bytes = include_bytes!(
1080 "../../testdata/micro_policies/allow_a_attr_b_attr_class0_perm0_policy.pp"
1081 );
1082 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1083 let policy = policy.validate().expect("validate policy");
1084
1085 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1086 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1087
1088 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1089 }
1090
1091 #[test]
1092 fn no_explicit_allow_attr_attr() {
1093 let policy_bytes = include_bytes!(
1094 "../../testdata/micro_policies/no_allow_a_attr_b_attr_class0_perm0_policy.pp"
1095 );
1096 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1097 let policy = policy.validate().expect("validate policy");
1098
1099 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1100 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1101
1102 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1103 }
1104
1105 #[test]
1106 fn compute_explicitly_allowed_multiple_attributes() {
1107 let policy_bytes = include_bytes!(
1108 "../../testdata/micro_policies/allow_a_t_a1_attr_class0_perm0_a2_attr_class0_perm1_policy.pp"
1109 );
1110 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1111 let policy = policy.validate().expect("validate policy");
1112
1113 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1114
1115 let class = policy
1116 .0
1117 .parsed_policy()
1118 .classes()
1119 .iter()
1120 .find(|class| class.name_bytes() == b"class0")
1121 .expect("class not found");
1122 let raw_access_vector =
1123 policy.0.parsed_policy().compute_explicitly_allowed(a_t, a_t, class).allow.0;
1124
1125 assert_eq!(2, raw_access_vector.count_ones());
1130 }
1131
1132 #[test]
1133 fn compute_access_decision_with_constraints() {
1134 let policy_bytes =
1135 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1136 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1137 let policy = policy.validate().expect("validate policy");
1138
1139 let source_context: SecurityContext = policy
1140 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1141 .expect("create source security context");
1142
1143 let target_context_satisfied: SecurityContext = source_context.clone();
1144 let decision_satisfied = policy.compute_access_decision(
1145 &source_context,
1146 &target_context_satisfied,
1147 KernelClass::File,
1148 );
1149 assert_eq!(decision_satisfied.allow, AccessVector(7));
1153
1154 let target_context_unsatisfied: SecurityContext = policy
1155 .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1156 .expect("create target security context failing some constraints");
1157 let decision_unsatisfied = policy.compute_access_decision(
1158 &source_context,
1159 &target_context_unsatisfied,
1160 KernelClass::File,
1161 );
1162 assert_eq!(decision_unsatisfied.allow, AccessVector(4));
1165 }
1166
1167 #[test]
1168 fn compute_ioctl_access_decision_explicitly_allowed() {
1169 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1170 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1171 let policy = policy.validate().expect("validate policy");
1172
1173 let source_context: SecurityContext = policy
1174 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1175 .expect("create source security context");
1176 let target_context_matched: SecurityContext = source_context.clone();
1177
1178 let decision_single = policy.compute_xperms_access_decision(
1196 XpermsKind::Ioctl,
1197 &source_context,
1198 &target_context_matched,
1199 KernelClass::File,
1200 0xab,
1201 );
1202
1203 let mut expected_auditdeny =
1204 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1205 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1206
1207 let expected_decision_single = XpermsAccessDecision {
1208 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1209 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1210 auditdeny: expected_auditdeny,
1211 };
1212 assert_eq!(decision_single, expected_decision_single);
1213
1214 let decision_range = policy.compute_xperms_access_decision(
1215 XpermsKind::Ioctl,
1216 &source_context,
1217 &target_context_matched,
1218 KernelClass::File,
1219 0x10,
1220 );
1221 let expected_decision_range = XpermsAccessDecision {
1222 allow: XpermsBitmap::ALL,
1223 auditallow: XpermsBitmap::ALL,
1224 auditdeny: XpermsBitmap::NONE,
1225 };
1226 assert_eq!(decision_range, expected_decision_range);
1227 }
1228
1229 #[test]
1230 fn compute_ioctl_access_decision_denied() {
1231 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1232 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1233 let class_id = find_class_by_name(unvalidated.0.classes(), "class_one_ioctl")
1234 .expect("look up class_one_ioctl")
1235 .id();
1236 let policy = unvalidated.validate().expect("validate policy");
1237 let source_context: SecurityContext = policy
1238 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1239 .expect("create source security context");
1240 let target_context_matched: SecurityContext = source_context.clone();
1241
1242 let decision_single = policy.compute_xperms_access_decision(
1246 XpermsKind::Ioctl,
1247 &source_context,
1248 &target_context_matched,
1249 class_id,
1250 0xdb,
1251 );
1252
1253 let expected_decision = XpermsAccessDecision {
1254 allow: XpermsBitmap::NONE,
1255 auditallow: XpermsBitmap::NONE,
1256 auditdeny: XpermsBitmap::ALL,
1257 };
1258 assert_eq!(decision_single, expected_decision);
1259 }
1260
1261 #[test]
1262 fn compute_ioctl_access_decision_unmatched() {
1263 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1264 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1265 let policy = policy.validate().expect("validate policy");
1266
1267 let source_context: SecurityContext = policy
1268 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1269 .expect("create source security context");
1270
1271 let target_context_unmatched: SecurityContext = policy
1273 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1274 .expect("create source security context");
1275
1276 for prefix in 0x0..=0xff {
1277 let decision = policy.compute_xperms_access_decision(
1278 XpermsKind::Ioctl,
1279 &source_context,
1280 &target_context_unmatched,
1281 KernelClass::File,
1282 prefix,
1283 );
1284 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1285 }
1286 }
1287
1288 #[test]
1289 fn compute_ioctl_earlier_redundant_prefixful_not_coalesced_into_prefixless() {
1290 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1291 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1292 let class_id = find_class_by_name(
1293 unvalidated.0.classes(),
1294 "class_earlier_redundant_prefixful_not_coalesced_into_prefixless",
1295 )
1296 .expect("look up class_earlier_redundant_prefixful_not_coalesced_into_prefixless")
1297 .id();
1298 let policy = unvalidated.validate().expect("validate policy");
1299 let source_context: SecurityContext = policy
1300 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1301 .expect("create source security context");
1302 let target_context_matched: SecurityContext = source_context.clone();
1303
1304 let decision = policy.compute_xperms_access_decision(
1309 XpermsKind::Ioctl,
1310 &source_context,
1311 &target_context_matched,
1312 class_id,
1313 0x7f,
1314 );
1315 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1316 let decision = policy.compute_xperms_access_decision(
1317 XpermsKind::Ioctl,
1318 &source_context,
1319 &target_context_matched,
1320 class_id,
1321 0x80,
1322 );
1323 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1324 let decision = policy.compute_xperms_access_decision(
1325 XpermsKind::Ioctl,
1326 &source_context,
1327 &target_context_matched,
1328 class_id,
1329 0x81,
1330 );
1331 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1332 }
1333
1334 #[test]
1335 fn compute_ioctl_later_redundant_prefixful_not_coalesced_into_prefixless() {
1336 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1337 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1338 let class_id = find_class_by_name(
1339 unvalidated.0.classes(),
1340 "class_later_redundant_prefixful_not_coalesced_into_prefixless",
1341 )
1342 .expect("look up class_later_redundant_prefixful_not_coalesced_into_prefixless")
1343 .id();
1344 let policy = unvalidated.validate().expect("validate policy");
1345 let source_context: SecurityContext = policy
1346 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1347 .expect("create source security context");
1348 let target_context_matched: SecurityContext = source_context.clone();
1349
1350 let decision = policy.compute_xperms_access_decision(
1355 XpermsKind::Ioctl,
1356 &source_context,
1357 &target_context_matched,
1358 class_id,
1359 0x8f,
1360 );
1361 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1362 let decision = policy.compute_xperms_access_decision(
1363 XpermsKind::Ioctl,
1364 &source_context,
1365 &target_context_matched,
1366 class_id,
1367 0x90,
1368 );
1369 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1370 let decision = policy.compute_xperms_access_decision(
1371 XpermsKind::Ioctl,
1372 &source_context,
1373 &target_context_matched,
1374 class_id,
1375 0x91,
1376 );
1377 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1378 }
1379
1380 #[test]
1381 fn compute_ioctl_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless() {
1382 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1383 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1384 let class_id = find_class_by_name(
1385 unvalidated.0.classes(),
1386 "class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless",
1387 )
1388 .expect("look up class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless")
1389 .id();
1390 let policy = unvalidated.validate().expect("validate policy");
1391 let source_context: SecurityContext = policy
1392 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1393 .expect("create source security context");
1394 let target_context_matched: SecurityContext = source_context.clone();
1395
1396 let decision = policy.compute_xperms_access_decision(
1402 XpermsKind::Ioctl,
1403 &source_context,
1404 &target_context_matched,
1405 class_id,
1406 0x9f,
1407 );
1408 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1409 let decision = policy.compute_xperms_access_decision(
1410 XpermsKind::Ioctl,
1411 &source_context,
1412 &target_context_matched,
1413 class_id,
1414 0xa0,
1415 );
1416 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1417 let decision = policy.compute_xperms_access_decision(
1418 XpermsKind::Ioctl,
1419 &source_context,
1420 &target_context_matched,
1421 class_id,
1422 0xa1,
1423 );
1424 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1425 }
1426
1427 #[test]
1428 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless() {
1429 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1430 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1431 let class_id = find_class_by_name(
1432 unvalidated.0.classes(),
1433 "class_prefixfuls_that_coalesce_to_prefixless",
1434 )
1435 .expect("look up class_prefixfuls_that_coalesce_to_prefixless")
1436 .id();
1437 let policy = unvalidated.validate().expect("validate policy");
1438 let source_context: SecurityContext = policy
1439 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1440 .expect("create source security context");
1441 let target_context_matched: SecurityContext = source_context.clone();
1442
1443 let decision = policy.compute_xperms_access_decision(
1449 XpermsKind::Ioctl,
1450 &source_context,
1451 &target_context_matched,
1452 class_id,
1453 0xaf,
1454 );
1455 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1456 let decision = policy.compute_xperms_access_decision(
1457 XpermsKind::Ioctl,
1458 &source_context,
1459 &target_context_matched,
1460 class_id,
1461 0xb0,
1462 );
1463 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1464 let decision = policy.compute_xperms_access_decision(
1465 XpermsKind::Ioctl,
1466 &source_context,
1467 &target_context_matched,
1468 class_id,
1469 0xb1,
1470 );
1471 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1472 }
1473
1474 #[test]
1475 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless() {
1476 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1477 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1478 let class_id = find_class_by_name(
1479 unvalidated.0.classes(),
1480 "class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless",
1481 )
1482 .expect("look up class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless")
1483 .id();
1484 let policy = unvalidated.validate().expect("validate policy");
1485 let source_context: SecurityContext = policy
1486 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1487 .expect("create source security context");
1488 let target_context_matched: SecurityContext = source_context.clone();
1489
1490 let decision = policy.compute_xperms_access_decision(
1497 XpermsKind::Ioctl,
1498 &source_context,
1499 &target_context_matched,
1500 class_id,
1501 0xbf,
1502 );
1503 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1504 let decision = policy.compute_xperms_access_decision(
1505 XpermsKind::Ioctl,
1506 &source_context,
1507 &target_context_matched,
1508 class_id,
1509 0xc0,
1510 );
1511 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1512 let decision = policy.compute_xperms_access_decision(
1513 XpermsKind::Ioctl,
1514 &source_context,
1515 &target_context_matched,
1516 class_id,
1517 0xc1,
1518 );
1519 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1520 let decision = policy.compute_xperms_access_decision(
1521 XpermsKind::Ioctl,
1522 &source_context,
1523 &target_context_matched,
1524 class_id,
1525 0xc2,
1526 );
1527 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1528 }
1529
1530 #[test]
1531 fn compute_ioctl_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless() {
1532 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1533 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1534 let class_id = find_class_by_name(
1535 unvalidated.0.classes(),
1536 "class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless",
1537 )
1538 .expect("look up class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless")
1539 .id();
1540 let policy = unvalidated.validate().expect("validate policy");
1541 let source_context: SecurityContext = policy
1542 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1543 .expect("create source security context");
1544 let target_context_matched: SecurityContext = source_context.clone();
1545
1546 let decision = policy.compute_xperms_access_decision(
1553 XpermsKind::Ioctl,
1554 &source_context,
1555 &target_context_matched,
1556 class_id,
1557 0xd5,
1558 );
1559 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1560 let decision = policy.compute_xperms_access_decision(
1561 XpermsKind::Ioctl,
1562 &source_context,
1563 &target_context_matched,
1564 class_id,
1565 0xd6,
1566 );
1567 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1568 let decision = policy.compute_xperms_access_decision(
1569 XpermsKind::Ioctl,
1570 &source_context,
1571 &target_context_matched,
1572 class_id,
1573 0xd7,
1574 );
1575 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1576 let decision = policy.compute_xperms_access_decision(
1577 XpermsKind::Ioctl,
1578 &source_context,
1579 &target_context_matched,
1580 class_id,
1581 0xd8,
1582 );
1583 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1584 }
1585
1586 #[test]
1597 fn compute_ioctl_ridiculous_permission_ordering() {
1598 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1599 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1600 let class_id =
1601 find_class_by_name(unvalidated.0.classes(), "class_ridiculous_permission_ordering")
1602 .expect("look up class_ridiculous_permission_ordering")
1603 .id();
1604 let policy = unvalidated.validate().expect("validate policy");
1605 let source_context: SecurityContext = policy
1606 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1607 .expect("create source security context");
1608 let target_context_matched: SecurityContext = source_context.clone();
1609
1610 let decision = policy.compute_xperms_access_decision(
1615 XpermsKind::Ioctl,
1616 &source_context,
1617 &target_context_matched,
1618 class_id,
1619 0x00,
1620 );
1621 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1622 let decision = policy.compute_xperms_access_decision(
1623 XpermsKind::Ioctl,
1624 &source_context,
1625 &target_context_matched,
1626 class_id,
1627 0x01,
1628 );
1629 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1630 let decision = policy.compute_xperms_access_decision(
1631 XpermsKind::Ioctl,
1632 &source_context,
1633 &target_context_matched,
1634 class_id,
1635 0xbf,
1636 );
1637 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1638 let decision = policy.compute_xperms_access_decision(
1639 XpermsKind::Ioctl,
1640 &source_context,
1641 &target_context_matched,
1642 class_id,
1643 0xc0,
1644 );
1645 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1646 let decision = policy.compute_xperms_access_decision(
1647 XpermsKind::Ioctl,
1648 &source_context,
1649 &target_context_matched,
1650 class_id,
1651 0xce,
1652 );
1653 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1654 let decision = policy.compute_xperms_access_decision(
1655 XpermsKind::Ioctl,
1656 &source_context,
1657 &target_context_matched,
1658 class_id,
1659 0xcf,
1660 );
1661 assert_eq!(
1662 decision,
1663 XpermsAccessDecision {
1664 allow: xperms_bitmap_from_elements((0x0..=0xf2).collect::<Vec<_>>().as_slice()),
1665 auditallow: XpermsBitmap::NONE,
1666 auditdeny: XpermsBitmap::ALL,
1667 }
1668 );
1669 let decision = policy.compute_xperms_access_decision(
1670 XpermsKind::Ioctl,
1671 &source_context,
1672 &target_context_matched,
1673 class_id,
1674 0xd0,
1675 );
1676 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1677 let decision = policy.compute_xperms_access_decision(
1678 XpermsKind::Ioctl,
1679 &source_context,
1680 &target_context_matched,
1681 class_id,
1682 0xe9,
1683 );
1684 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1685 let decision = policy.compute_xperms_access_decision(
1686 XpermsKind::Ioctl,
1687 &source_context,
1688 &target_context_matched,
1689 class_id,
1690 0xf0,
1691 );
1692 assert_eq!(
1693 decision,
1694 XpermsAccessDecision {
1695 allow: xperms_bitmap_from_elements(&[0x01]),
1696 auditallow: XpermsBitmap::NONE,
1697 auditdeny: XpermsBitmap::ALL,
1698 }
1699 );
1700 let decision = policy.compute_xperms_access_decision(
1701 XpermsKind::Ioctl,
1702 &source_context,
1703 &target_context_matched,
1704 class_id,
1705 0xf1,
1706 );
1707 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1708 let decision = policy.compute_xperms_access_decision(
1709 XpermsKind::Ioctl,
1710 &source_context,
1711 &target_context_matched,
1712 class_id,
1713 0xfc,
1714 );
1715 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1716 let decision = policy.compute_xperms_access_decision(
1717 XpermsKind::Ioctl,
1718 &source_context,
1719 &target_context_matched,
1720 class_id,
1721 0xfd,
1722 );
1723 assert_eq!(
1724 decision,
1725 XpermsAccessDecision {
1726 allow: xperms_bitmap_from_elements((0xfa..=0xfd).collect::<Vec<_>>().as_slice()),
1727 auditallow: XpermsBitmap::NONE,
1728 auditdeny: XpermsBitmap::ALL,
1729 }
1730 );
1731 let decision = policy.compute_xperms_access_decision(
1732 XpermsKind::Ioctl,
1733 &source_context,
1734 &target_context_matched,
1735 class_id,
1736 0xfe,
1737 );
1738 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1739 }
1740
1741 #[test]
1742 fn compute_nlmsg_access_decision_explicitly_allowed() {
1743 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1744 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1745 let policy = policy.validate().expect("validate policy");
1746
1747 let source_context: SecurityContext = policy
1748 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1749 .expect("create source security context");
1750 let target_context_matched: SecurityContext = source_context.clone();
1751
1752 let decision_single = policy.compute_xperms_access_decision(
1770 XpermsKind::Nlmsg,
1771 &source_context,
1772 &target_context_matched,
1773 KernelClass::NetlinkRouteSocket,
1774 0xab,
1775 );
1776
1777 let mut expected_auditdeny =
1778 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1779 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1780
1781 let expected_decision_single = XpermsAccessDecision {
1782 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1783 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1784 auditdeny: expected_auditdeny,
1785 };
1786 assert_eq!(decision_single, expected_decision_single);
1787
1788 let decision_range = policy.compute_xperms_access_decision(
1789 XpermsKind::Nlmsg,
1790 &source_context,
1791 &target_context_matched,
1792 KernelClass::NetlinkRouteSocket,
1793 0x10,
1794 );
1795 let expected_decision_range = XpermsAccessDecision {
1796 allow: XpermsBitmap::ALL,
1797 auditallow: XpermsBitmap::ALL,
1798 auditdeny: XpermsBitmap::NONE,
1799 };
1800 assert_eq!(decision_range, expected_decision_range);
1801 }
1802
1803 #[test]
1804 fn compute_nlmsg_access_decision_unmatched() {
1805 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1806 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1807 let policy = policy.validate().expect("validate policy");
1808
1809 let source_context: SecurityContext = policy
1810 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1811 .expect("create source security context");
1812
1813 let target_context_unmatched: SecurityContext = policy
1815 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1816 .expect("create source security context");
1817
1818 for prefix in 0x0..=0xff {
1819 let decision = policy.compute_xperms_access_decision(
1820 XpermsKind::Nlmsg,
1821 &source_context,
1822 &target_context_unmatched,
1823 KernelClass::NetlinkRouteSocket,
1824 prefix,
1825 );
1826 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1827 }
1828 }
1829
1830 #[test]
1831 fn compute_ioctl_grant_does_not_cause_nlmsg_deny() {
1832 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1833 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1834 let class_id = find_class_by_name(
1835 unvalidated.0.classes(),
1836 "class_ioctl_grant_does_not_cause_nlmsg_deny",
1837 )
1838 .expect("look up class_ioctl_grant_does_not_cause_nlmsg_deny")
1839 .id();
1840 let policy = unvalidated.validate().expect("validate policy");
1841 let source_context: SecurityContext = policy
1842 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1843 .expect("create source security context");
1844 let target_context_matched: SecurityContext = source_context.clone();
1845
1846 let ioctl_decision = policy.compute_xperms_access_decision(
1850 XpermsKind::Ioctl,
1851 &source_context,
1852 &target_context_matched,
1853 class_id,
1854 0x00,
1855 );
1856 assert_eq!(
1857 ioctl_decision,
1858 XpermsAccessDecision {
1859 allow: xperms_bitmap_from_elements(&[0x0002]),
1860 auditallow: XpermsBitmap::NONE,
1861 auditdeny: XpermsBitmap::ALL,
1862 }
1863 );
1864 let nlmsg_decision = policy.compute_xperms_access_decision(
1865 XpermsKind::Nlmsg,
1866 &source_context,
1867 &target_context_matched,
1868 class_id,
1869 0x00,
1870 );
1871 assert_eq!(nlmsg_decision, XpermsAccessDecision::ALLOW_ALL);
1872 }
1873
1874 #[test]
1875 fn compute_nlmsg_grant_does_not_cause_ioctl_deny() {
1876 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1877 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1878 let class_id = find_class_by_name(
1879 unvalidated.0.classes(),
1880 "class_nlmsg_grant_does_not_cause_ioctl_deny",
1881 )
1882 .expect("look up class_nlmsg_grant_does_not_cause_ioctl_deny")
1883 .id();
1884 let policy = unvalidated.validate().expect("validate policy");
1885 let source_context: SecurityContext = policy
1886 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1887 .expect("create source security context");
1888 let target_context_matched: SecurityContext = source_context.clone();
1889
1890 let nlmsg_decision = policy.compute_xperms_access_decision(
1894 XpermsKind::Nlmsg,
1895 &source_context,
1896 &target_context_matched,
1897 class_id,
1898 0x00,
1899 );
1900 assert_eq!(
1901 nlmsg_decision,
1902 XpermsAccessDecision {
1903 allow: xperms_bitmap_from_elements(&[0x0003]),
1904 auditallow: XpermsBitmap::NONE,
1905 auditdeny: XpermsBitmap::ALL,
1906 }
1907 );
1908 let ioctl_decision = policy.compute_xperms_access_decision(
1909 XpermsKind::Ioctl,
1910 &source_context,
1911 &target_context_matched,
1912 class_id,
1913 0x00,
1914 );
1915 assert_eq!(ioctl_decision, XpermsAccessDecision::ALLOW_ALL);
1916 }
1917
1918 #[test]
1919 fn compute_create_context_minimal() {
1920 let policy_bytes =
1921 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1922 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1923 let policy = policy.validate().expect("validate policy");
1924 let source = policy
1925 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1926 .expect("valid source security context");
1927 let target = policy
1928 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1929 .expect("valid target security context");
1930
1931 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1932 let expected: SecurityContext = policy
1933 .parse_security_context(b"source_u:object_r:target_t:s0:c0".into())
1934 .expect("valid expected security context");
1935
1936 assert_eq!(expected, actual);
1937 }
1938
1939 #[test]
1940 fn new_security_context_minimal() {
1941 let policy_bytes =
1942 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1943 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1944 let policy = policy.validate().expect("validate policy");
1945 let source = policy
1946 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1947 .expect("valid source security context");
1948 let target = policy
1949 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1950 .expect("valid target security context");
1951
1952 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1953
1954 assert_eq!(source, actual);
1955 }
1956
1957 #[test]
1958 fn compute_create_context_class_defaults() {
1959 let policy_bytes =
1960 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1961 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1962 let policy = policy.validate().expect("validate policy");
1963 let source = policy
1964 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1965 .expect("valid source security context");
1966 let target = policy
1967 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1968 .expect("valid target security context");
1969
1970 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1971 let expected: SecurityContext = policy
1972 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1973 .expect("valid expected security context");
1974
1975 assert_eq!(expected, actual);
1976 }
1977
1978 #[test]
1979 fn new_security_context_class_defaults() {
1980 let policy_bytes =
1981 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1982 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1983 let policy = policy.validate().expect("validate policy");
1984 let source = policy
1985 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1986 .expect("valid source security context");
1987 let target = policy
1988 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1989 .expect("valid target security context");
1990
1991 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1992 let expected: SecurityContext = policy
1993 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1994 .expect("valid expected security context");
1995
1996 assert_eq!(expected, actual);
1997 }
1998
1999 #[test]
2000 fn compute_create_context_role_transition() {
2001 let policy_bytes =
2002 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
2003 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2004 let policy = policy.validate().expect("validate policy");
2005 let source = policy
2006 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2007 .expect("valid source security context");
2008 let target = policy
2009 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2010 .expect("valid target security context");
2011
2012 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2013 let expected: SecurityContext = policy
2014 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
2015 .expect("valid expected security context");
2016
2017 assert_eq!(expected, actual);
2018 }
2019
2020 #[test]
2021 fn new_security_context_role_transition() {
2022 let policy_bytes =
2023 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
2024 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2025 let policy = policy.validate().expect("validate policy");
2026 let source = policy
2027 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2028 .expect("valid source security context");
2029 let target = policy
2030 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2031 .expect("valid target security context");
2032
2033 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2034 let expected: SecurityContext = policy
2035 .parse_security_context(b"source_u:transition_r:source_t:s0:c0-s2:c0.c1".into())
2036 .expect("valid expected security context");
2037
2038 assert_eq!(expected, actual);
2039 }
2040
2041 #[test]
2042 #[ignore]
2044 fn compute_create_context_role_transition_not_allowed() {
2045 let policy_bytes = include_bytes!(
2046 "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy.pp"
2047 );
2048 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2049 let policy = policy.validate().expect("validate policy");
2050 let source = policy
2051 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2052 .expect("valid source security context");
2053 let target = policy
2054 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2055 .expect("valid target security context");
2056
2057 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2058
2059 assert!(policy.validate_security_context(&actual).is_err());
2061 }
2062
2063 #[test]
2064 fn compute_create_context_type_transition() {
2065 let policy_bytes =
2066 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
2067 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2068 let policy = policy.validate().expect("validate policy");
2069 let source = policy
2070 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2071 .expect("valid source security context");
2072 let target = policy
2073 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2074 .expect("valid target security context");
2075
2076 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2077 let expected: SecurityContext = policy
2078 .parse_security_context(b"source_u:object_r:transition_t:s0:c0".into())
2079 .expect("valid expected security context");
2080
2081 assert_eq!(expected, actual);
2082 }
2083
2084 #[test]
2085 fn new_security_context_type_transition() {
2086 let policy_bytes =
2087 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
2088 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2089 let policy = policy.validate().expect("validate policy");
2090 let source = policy
2091 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2092 .expect("valid source security context");
2093 let target = policy
2094 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2095 .expect("valid target security context");
2096
2097 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2098 let expected: SecurityContext = policy
2099 .parse_security_context(b"source_u:source_r:transition_t:s0:c0-s2:c0.c1".into())
2100 .expect("valid expected security context");
2101
2102 assert_eq!(expected, actual);
2103 }
2104
2105 #[test]
2106 fn compute_create_context_range_transition() {
2107 let policy_bytes =
2108 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
2109 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2110 let policy = policy.validate().expect("validate policy");
2111 let source = policy
2112 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2113 .expect("valid source security context");
2114 let target = policy
2115 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2116 .expect("valid target security context");
2117
2118 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2119 let expected: SecurityContext = policy
2120 .parse_security_context(b"source_u:object_r:target_t:s1:c1-s2:c1.c2".into())
2121 .expect("valid expected security context");
2122
2123 assert_eq!(expected, actual);
2124 }
2125
2126 #[test]
2127 fn new_security_context_range_transition() {
2128 let policy_bytes =
2129 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
2130 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2131 let policy = policy.validate().expect("validate policy");
2132 let source = policy
2133 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2134 .expect("valid source security context");
2135 let target = policy
2136 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2137 .expect("valid target security context");
2138
2139 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2140 let expected: SecurityContext = policy
2141 .parse_security_context(b"source_u:source_r:source_t:s1:c1-s2:c1.c2".into())
2142 .expect("valid expected security context");
2143
2144 assert_eq!(expected, actual);
2145 }
2146
2147 #[test]
2148 fn access_vector_formats() {
2149 assert_eq!(format!("{:x}", AccessVector::NONE), "0");
2150 assert_eq!(format!("{:x}", AccessVector::ALL), "ffffffff");
2151 assert_eq!(format!("{:?}", AccessVector::NONE), "AccessVector(00000000)");
2152 assert_eq!(format!("{:?}", AccessVector::ALL), "AccessVector(ffffffff)");
2153 }
2154}