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