1pub mod arrays;
6pub mod error;
7pub mod index;
8pub mod metadata;
9pub mod parsed_policy;
10pub mod parser;
11pub mod view;
12
13mod constraints;
14mod extensible_bitmap;
15mod security_context;
16mod symbols;
17
18pub use arrays::{FsUseType, XpermsBitmap};
19pub use index::FsUseLabelAndType;
20pub use parser::PolicyCursor;
21pub use security_context::{SecurityContext, SecurityContextError};
22
23use crate::{self as sc, PolicyCap};
24use anyhow::Context as _;
25use index::PolicyIndex;
26use metadata::HandleUnknown;
27use parsed_policy::ParsedPolicy;
28use parser::PolicyData;
29use std::fmt::{Debug, Display, LowerHex};
30use std::sync::Arc;
31
32use std::num::{NonZeroU32, NonZeroU64};
33use std::ops::Deref;
34use std::str::FromStr;
35use symbols::{find_class_by_name, find_common_symbol_by_name_bytes};
36use zerocopy::{
37 FromBytes, Immutable, KnownLayout, Ref, SplitByteSlice, Unaligned, little_endian as le,
38};
39
40#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
42pub struct UserId(NonZeroU32);
43
44#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
46pub struct RoleId(NonZeroU32);
47
48#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
50pub struct TypeId(NonZeroU32);
51
52#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
54pub struct SensitivityId(NonZeroU32);
55
56#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
58pub struct CategoryId(NonZeroU32);
59
60#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
63pub struct ClassId(NonZeroU32);
64
65impl ClassId {
66 pub fn new(id: NonZeroU32) -> Self {
68 Self(id)
69 }
70}
71
72impl Into<u32> for ClassId {
73 fn into(self) -> u32 {
74 self.0.into()
75 }
76}
77
78#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
80pub struct ClassPermissionId(NonZeroU32);
81
82impl Display for ClassPermissionId {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 write!(f, "{}", self.0)
85 }
86}
87
88#[derive(Debug, Clone, PartialEq)]
93pub struct AccessDecision {
94 pub allow: AccessVector,
95 pub auditallow: AccessVector,
96 pub auditdeny: AccessVector,
97 pub flags: u32,
98
99 pub todo_bug: Option<NonZeroU64>,
102}
103
104impl Default for AccessDecision {
105 fn default() -> Self {
106 Self::allow(AccessVector::NONE)
107 }
108}
109
110impl AccessDecision {
111 pub(super) const fn allow(allow: AccessVector) -> Self {
114 Self {
115 allow,
116 auditallow: AccessVector::NONE,
117 auditdeny: AccessVector::ALL,
118 flags: 0,
119 todo_bug: None,
120 }
121 }
122}
123
124pub(super) const SELINUX_AVD_FLAGS_PERMISSIVE: u32 = 1;
126
127#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
130pub struct AccessVector(u32);
131
132impl AccessVector {
133 pub const NONE: AccessVector = AccessVector(0);
134 pub const ALL: AccessVector = AccessVector(std::u32::MAX);
135
136 pub(super) fn from_class_permission_id(id: ClassPermissionId) -> Self {
137 Self((1 as u32) << (id.0.get() - 1))
138 }
139}
140
141impl Debug for AccessVector {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 write!(f, "AccessVector({:0>8x})", self)
144 }
145}
146
147impl FromStr for AccessVector {
148 type Err = <u32 as FromStr>::Err;
149
150 fn from_str(value: &str) -> Result<Self, Self::Err> {
151 Ok(AccessVector(u32::from_str_radix(value, 16)?))
153 }
154}
155
156impl LowerHex for AccessVector {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 LowerHex::fmt(&self.0, f)
159 }
160}
161
162impl std::ops::BitAnd for AccessVector {
163 type Output = Self;
164
165 fn bitand(self, rhs: Self) -> Self::Output {
166 AccessVector(self.0 & rhs.0)
167 }
168}
169
170impl std::ops::BitOr for AccessVector {
171 type Output = Self;
172
173 fn bitor(self, rhs: Self) -> Self::Output {
174 AccessVector(self.0 | rhs.0)
175 }
176}
177
178impl std::ops::BitAndAssign for AccessVector {
179 fn bitand_assign(&mut self, rhs: Self) {
180 self.0 &= rhs.0
181 }
182}
183
184impl std::ops::BitOrAssign for AccessVector {
185 fn bitor_assign(&mut self, rhs: Self) {
186 self.0 |= rhs.0
187 }
188}
189
190impl std::ops::SubAssign for AccessVector {
191 fn sub_assign(&mut self, rhs: Self) {
192 self.0 = self.0 ^ (self.0 & rhs.0);
193 }
194}
195
196impl std::ops::Sub for AccessVector {
197 type Output = Self;
198
199 fn sub(self, rhs: Self) -> Self::Output {
200 AccessVector(self.0 ^ (self.0 & rhs.0))
201 }
202}
203
204#[derive(Clone, Debug, Eq, Hash, PartialEq)]
207pub enum XpermsKind {
208 Ioctl,
209 Nlmsg,
210}
211
212#[derive(Debug, Clone, PartialEq)]
217pub struct XpermsAccessDecision {
218 pub allow: XpermsBitmap,
219 pub auditallow: XpermsBitmap,
220 pub auditdeny: XpermsBitmap,
221}
222
223impl XpermsAccessDecision {
224 pub const DENY_ALL: Self = Self {
225 allow: XpermsBitmap::NONE,
226 auditallow: XpermsBitmap::NONE,
227 auditdeny: XpermsBitmap::ALL,
228 };
229 pub const ALLOW_ALL: Self = Self {
230 allow: XpermsBitmap::ALL,
231 auditallow: XpermsBitmap::NONE,
232 auditdeny: XpermsBitmap::ALL,
233 };
234}
235
236pub fn parse_policy_by_value(binary_policy: Vec<u8>) -> Result<Unvalidated, anyhow::Error> {
245 let policy_data = Arc::new(binary_policy);
246 let policy = ParsedPolicy::parse(policy_data).context("parsing policy")?;
247 Ok(Unvalidated(policy))
248}
249
250pub struct ClassInfo<'a> {
252 pub class_name: &'a [u8],
254 pub class_id: ClassId,
256}
257
258#[derive(Debug)]
259pub struct Policy(PolicyIndex);
260
261impl Policy {
262 pub fn policy_version(&self) -> u32 {
264 self.0.parsed_policy().policy_version()
265 }
266
267 pub fn binary(&self) -> &PolicyData {
268 &self.0.parsed_policy().data
269 }
270
271 pub fn handle_unknown(&self) -> HandleUnknown {
274 self.0.parsed_policy().handle_unknown()
275 }
276
277 pub fn conditional_booleans<'a>(&'a self) -> Vec<(&'a [u8], bool)> {
278 self.0
279 .parsed_policy()
280 .conditional_booleans()
281 .iter()
282 .map(|boolean| (boolean.data.as_slice(), boolean.metadata.active()))
283 .collect()
284 }
285
286 pub fn classes<'a>(&'a self) -> Vec<ClassInfo<'a>> {
288 self.0
289 .parsed_policy()
290 .classes()
291 .iter()
292 .map(|class| ClassInfo { class_name: class.name_bytes(), class_id: class.id() })
293 .collect()
294 }
295
296 pub(super) fn type_id_by_name(&self, name: &str) -> Option<TypeId> {
298 self.0.parsed_policy().type_by_name(name).map(|x| x.id())
299 }
300
301 pub fn find_class_permissions_by_name(
306 &self,
307 class_name: &str,
308 ) -> Result<Vec<(ClassPermissionId, Vec<u8>)>, ()> {
309 let class = find_class_by_name(self.0.parsed_policy().classes(), class_name).ok_or(())?;
310 let owned_permissions = class.permissions();
311
312 let mut result: Vec<_> = owned_permissions
313 .iter()
314 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
315 .collect();
316
317 if class.common_name_bytes().is_empty() {
319 return Ok(result);
320 }
321
322 let common_symbol_permissions = find_common_symbol_by_name_bytes(
323 self.0.parsed_policy().common_symbols(),
324 class.common_name_bytes(),
325 )
326 .ok_or(())?
327 .permissions();
328
329 result.append(
330 &mut common_symbol_permissions
331 .iter()
332 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
333 .collect(),
334 );
335
336 Ok(result)
337 }
338
339 pub fn fs_use_label_and_type(
342 &self,
343 fs_type: sc::NullessByteStr<'_>,
344 ) -> Option<FsUseLabelAndType> {
345 self.0.fs_use_label_and_type(fs_type)
346 }
347
348 pub fn genfscon_label_for_fs_and_path(
351 &self,
352 fs_type: sc::NullessByteStr<'_>,
353 node_path: sc::NullessByteStr<'_>,
354 class_id: Option<sc::KernelClass>,
355 ) -> Option<SecurityContext> {
356 self.0.genfscon_label_for_fs_and_path(fs_type, node_path, class_id)
357 }
358
359 pub fn initial_context(&self, id: sc::InitialSid) -> security_context::SecurityContext {
362 self.0.initial_context(id)
363 }
364
365 pub fn parse_security_context(
367 &self,
368 security_context: sc::NullessByteStr<'_>,
369 ) -> Result<security_context::SecurityContext, security_context::SecurityContextError> {
370 security_context::SecurityContext::parse(&self.0, security_context)
371 }
372
373 pub fn validate_security_context(
375 &self,
376 security_context: &SecurityContext,
377 ) -> Result<(), SecurityContextError> {
378 security_context.validate(&self.0)
379 }
380
381 pub fn serialize_security_context(&self, security_context: &SecurityContext) -> Vec<u8> {
383 security_context.serialize(&self.0)
384 }
385
386 pub fn compute_create_context_with_name(
394 &self,
395 source: &SecurityContext,
396 target: &SecurityContext,
397 class: impl Into<sc::ObjectClass>,
398 name: sc::NullessByteStr<'_>,
399 ) -> Option<SecurityContext> {
400 self.0.compute_create_context_with_name(source, target, class.into(), name)
401 }
402
403 pub fn compute_create_context(
421 &self,
422 source: &SecurityContext,
423 target: &SecurityContext,
424 class: impl Into<sc::ObjectClass>,
425 ) -> SecurityContext {
426 self.0.compute_create_context(source, target, class.into())
427 }
428
429 pub fn compute_access_decision(
445 &self,
446 source_context: &SecurityContext,
447 target_context: &SecurityContext,
448 object_class: impl Into<sc::ObjectClass>,
449 ) -> AccessDecision {
450 if let Some(target_class) = self.0.class(object_class.into()) {
451 self.0.parsed_policy().compute_access_decision(
452 source_context,
453 target_context,
454 target_class,
455 )
456 } else {
457 AccessDecision::allow(AccessVector::NONE)
458 }
459 }
460
461 pub fn compute_xperms_access_decision(
465 &self,
466 xperms_kind: XpermsKind,
467 source_context: &SecurityContext,
468 target_context: &SecurityContext,
469 object_class: impl Into<sc::ObjectClass>,
470 xperms_prefix: u8,
471 ) -> XpermsAccessDecision {
472 if let Some(target_class) = self.0.class(object_class.into()) {
473 self.0.parsed_policy().compute_xperms_access_decision(
474 xperms_kind,
475 source_context,
476 target_context,
477 target_class,
478 xperms_prefix,
479 )
480 } else {
481 XpermsAccessDecision::DENY_ALL
482 }
483 }
484
485 pub fn is_bounded_by(&self, bounded_type: TypeId, parent_type: TypeId) -> bool {
486 let type_ = self.0.parsed_policy().type_(bounded_type);
487 type_.bounded_by() == Some(parent_type)
488 }
489
490 pub fn is_permissive(&self, type_: TypeId) -> bool {
492 self.0.parsed_policy().permissive_types().is_set(type_.0.get())
493 }
494
495 pub fn has_policycap(&self, policy_cap: PolicyCap) -> bool {
497 self.0.parsed_policy().has_policycap(policy_cap)
498 }
499}
500
501impl AccessVectorComputer for Policy {
502 fn access_vector_from_permissions<
503 P: sc::ClassPermission + Into<sc::KernelPermission> + Clone + 'static,
504 >(
505 &self,
506 permissions: &[P],
507 ) -> Option<AccessVector> {
508 let mut access_vector = AccessVector::NONE;
509 for permission in permissions {
510 if let Some(permission_info) = self.0.permission(&permission.clone().into()) {
511 access_vector |= AccessVector::from_class_permission_id(permission_info.id());
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 access_vector_from_permissions<
545 P: sc::ClassPermission + Into<sc::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(crate::policy::Array<$metadata_type, $data_type>);
713
714 impl std::ops::Deref for $type_name {
715 type Target = crate::policy::Array<$metadata_type, $data_type>;
716
717 fn deref(&self) -> &Self::Target {
718 &self.0
719 }
720 }
721
722 impl crate::policy::Parse for $type_name
723 where
724 crate::policy::Array<$metadata_type, $data_type>: crate::policy::Parse,
725 {
726 type Error = <Array<$metadata_type, $data_type> as crate::policy::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::*;
870
871 use crate::policy::metadata::HandleUnknown;
872 use crate::policy::{SecurityContext, parse_policy_by_value};
873 use crate::{FileClass, InitialSid, KernelClass};
874
875 use serde::Deserialize;
876 use std::ops::Shl;
877
878 fn is_explicitly_allowed(
886 policy: &Policy,
887 source_type: TypeId,
888 target_type: TypeId,
889 target_class: &str,
890 permission: &str,
891 ) -> bool {
892 let class = policy
893 .0
894 .parsed_policy()
895 .classes()
896 .iter()
897 .find(|class| class.name_bytes() == target_class.as_bytes())
898 .expect("class not found");
899 let class_permissions = policy
900 .find_class_permissions_by_name(target_class)
901 .expect("class permissions not found");
902 let (permission_id, _) = class_permissions
903 .iter()
904 .find(|(_, name)| permission.as_bytes() == name)
905 .expect("permission not found");
906 let permission_bit = AccessVector::from_class_permission_id(*permission_id);
907 let access_decision =
908 policy.0.parsed_policy().compute_explicitly_allowed(source_type, target_type, class);
909 permission_bit == access_decision.allow & permission_bit
910 }
911
912 #[derive(Debug, Deserialize)]
913 struct Expectations {
914 expected_policy_version: u32,
915 expected_handle_unknown: LocalHandleUnknown,
916 }
917
918 #[derive(Debug, Deserialize, PartialEq)]
919 #[serde(rename_all = "snake_case")]
920 enum LocalHandleUnknown {
921 Deny,
922 Reject,
923 Allow,
924 }
925
926 impl PartialEq<HandleUnknown> for LocalHandleUnknown {
927 fn eq(&self, other: &HandleUnknown) -> bool {
928 match self {
929 LocalHandleUnknown::Deny => *other == HandleUnknown::Deny,
930 LocalHandleUnknown::Reject => *other == HandleUnknown::Reject,
931 LocalHandleUnknown::Allow => *other == HandleUnknown::Allow,
932 }
933 }
934 }
935
936 fn xperms_bitmap_from_elements(elements: &[u8]) -> XpermsBitmap {
939 let mut bitmap = [le::U32::ZERO; 8];
940 for element in elements.iter() {
941 let block_index = (*element as usize) / 32;
942 let bit_index = ((*element as usize) % 32) as u32;
943 let bitmask = le::U32::new(1).shl(bit_index);
944 bitmap[block_index] = bitmap[block_index] | bitmask;
945 }
946 XpermsBitmap::new(bitmap)
947 }
948
949 #[test]
950 fn known_policies() {
951 let policies_and_expectations = [
952 [
953 b"testdata/policies/emulator".to_vec(),
954 include_bytes!("../../testdata/policies/emulator").to_vec(),
955 include_bytes!("../../testdata/expectations/emulator").to_vec(),
956 ],
957 [
958 b"testdata/policies/selinux_testsuite".to_vec(),
959 include_bytes!("../../testdata/policies/selinux_testsuite").to_vec(),
960 include_bytes!("../../testdata/expectations/selinux_testsuite").to_vec(),
961 ],
962 ];
963
964 for [policy_path, policy_bytes, expectations_bytes] in policies_and_expectations {
965 let expectations = serde_json5::from_reader::<_, Expectations>(
966 &mut std::io::Cursor::new(expectations_bytes),
967 )
968 .expect("deserialize expectations");
969
970 let unvalidated_policy =
973 parse_policy_by_value(policy_bytes.clone()).expect("parse policy");
974
975 let policy = unvalidated_policy
976 .validate()
977 .with_context(|| {
978 format!(
979 "policy path: {:?}",
980 std::str::from_utf8(policy_path.as_slice()).unwrap()
981 )
982 })
983 .expect("validate policy");
984
985 assert_eq!(expectations.expected_policy_version, policy.policy_version());
986 assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
987
988 let binary_policy = policy.binary().clone();
990 assert_eq!(&policy_bytes, binary_policy.deref());
991 }
992 }
993
994 #[test]
995 fn policy_lookup() {
996 let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
997 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
998 let policy = policy.validate().expect("validate selinux testsuite policy");
999
1000 let unconfined_t = policy.type_id_by_name("unconfined_t").expect("look up type id");
1001
1002 assert!(is_explicitly_allowed(&policy, unconfined_t, unconfined_t, "process", "fork",));
1003 }
1004
1005 #[test]
1006 fn initial_contexts() {
1007 let policy_bytes = include_bytes!(
1008 "../../testdata/micro_policies/multiple_levels_and_categories_policy.pp"
1009 );
1010 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1011 let policy = policy.validate().expect("validate policy");
1012
1013 let kernel_context = policy.initial_context(InitialSid::Kernel);
1014 assert_eq!(
1015 policy.serialize_security_context(&kernel_context),
1016 b"user0:object_r:type0:s0:c0-s1:c0.c2,c4"
1017 )
1018 }
1019
1020 #[test]
1021 fn explicit_allow_type_type() {
1022 let policy_bytes =
1023 include_bytes!("../../testdata/micro_policies/allow_a_t_b_t_class0_perm0_policy.pp");
1024 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1025 let policy = policy.validate().expect("validate policy");
1026
1027 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1028 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1029
1030 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1031 }
1032
1033 #[test]
1034 fn no_explicit_allow_type_type() {
1035 let policy_bytes =
1036 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_t_class0_perm0_policy.pp");
1037 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1038 let policy = policy.validate().expect("validate policy");
1039
1040 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1041 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1042
1043 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1044 }
1045
1046 #[test]
1047 fn explicit_allow_type_attr() {
1048 let policy_bytes =
1049 include_bytes!("../../testdata/micro_policies/allow_a_t_b_attr_class0_perm0_policy.pp");
1050 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1051 let policy = policy.validate().expect("validate policy");
1052
1053 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1054 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1055
1056 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1057 }
1058
1059 #[test]
1060 fn no_explicit_allow_type_attr() {
1061 let policy_bytes = include_bytes!(
1062 "../../testdata/micro_policies/no_allow_a_t_b_attr_class0_perm0_policy.pp"
1063 );
1064 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1065 let policy = policy.validate().expect("validate policy");
1066
1067 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1068 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1069
1070 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1071 }
1072
1073 #[test]
1074 fn explicit_allow_attr_attr() {
1075 let policy_bytes = include_bytes!(
1076 "../../testdata/micro_policies/allow_a_attr_b_attr_class0_perm0_policy.pp"
1077 );
1078 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1079 let policy = policy.validate().expect("validate policy");
1080
1081 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1082 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1083
1084 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1085 }
1086
1087 #[test]
1088 fn no_explicit_allow_attr_attr() {
1089 let policy_bytes = include_bytes!(
1090 "../../testdata/micro_policies/no_allow_a_attr_b_attr_class0_perm0_policy.pp"
1091 );
1092 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1093 let policy = policy.validate().expect("validate policy");
1094
1095 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1096 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1097
1098 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1099 }
1100
1101 #[test]
1102 fn compute_explicitly_allowed_multiple_attributes() {
1103 let policy_bytes = include_bytes!(
1104 "../../testdata/micro_policies/allow_a_t_a1_attr_class0_perm0_a2_attr_class0_perm1_policy.pp"
1105 );
1106 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1107 let policy = policy.validate().expect("validate policy");
1108
1109 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1110
1111 let class = policy
1112 .0
1113 .parsed_policy()
1114 .classes()
1115 .iter()
1116 .find(|class| class.name_bytes() == b"class0")
1117 .expect("class not found");
1118 let raw_access_vector =
1119 policy.0.parsed_policy().compute_explicitly_allowed(a_t, a_t, class).allow.0;
1120
1121 assert_eq!(2, raw_access_vector.count_ones());
1126 }
1127
1128 #[test]
1129 fn compute_access_decision_with_constraints() {
1130 let policy_bytes =
1131 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1132 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1133 let policy = policy.validate().expect("validate policy");
1134
1135 let source_context: SecurityContext = policy
1136 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1137 .expect("create source security context");
1138
1139 let target_context_satisfied: SecurityContext = source_context.clone();
1140 let decision_satisfied = policy.compute_access_decision(
1141 &source_context,
1142 &target_context_satisfied,
1143 KernelClass::File,
1144 );
1145 assert_eq!(decision_satisfied.allow, AccessVector(7));
1149
1150 let target_context_unsatisfied: SecurityContext = policy
1151 .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1152 .expect("create target security context failing some constraints");
1153 let decision_unsatisfied = policy.compute_access_decision(
1154 &source_context,
1155 &target_context_unsatisfied,
1156 KernelClass::File,
1157 );
1158 assert_eq!(decision_unsatisfied.allow, AccessVector(4));
1161 }
1162
1163 #[test]
1164 fn compute_ioctl_access_decision_explicitly_allowed() {
1165 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1166 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1167 let policy = policy.validate().expect("validate policy");
1168
1169 let source_context: SecurityContext = policy
1170 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1171 .expect("create source security context");
1172 let target_context_matched: SecurityContext = source_context.clone();
1173
1174 let decision_single = policy.compute_xperms_access_decision(
1192 XpermsKind::Ioctl,
1193 &source_context,
1194 &target_context_matched,
1195 KernelClass::File,
1196 0xab,
1197 );
1198
1199 let mut expected_auditdeny =
1200 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1201 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1202
1203 let expected_decision_single = XpermsAccessDecision {
1204 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1205 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1206 auditdeny: expected_auditdeny,
1207 };
1208 assert_eq!(decision_single, expected_decision_single);
1209
1210 let decision_range = policy.compute_xperms_access_decision(
1211 XpermsKind::Ioctl,
1212 &source_context,
1213 &target_context_matched,
1214 KernelClass::File,
1215 0x10,
1216 );
1217 let expected_decision_range = XpermsAccessDecision {
1218 allow: XpermsBitmap::ALL,
1219 auditallow: XpermsBitmap::ALL,
1220 auditdeny: XpermsBitmap::NONE,
1221 };
1222 assert_eq!(decision_range, expected_decision_range);
1223 }
1224
1225 #[test]
1226 fn compute_ioctl_access_decision_denied() {
1227 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1228 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1229 let class_id = find_class_by_name(unvalidated.0.classes(), "class_one_ioctl")
1230 .expect("look up class_one_ioctl")
1231 .id();
1232 let policy = unvalidated.validate().expect("validate policy");
1233 let source_context: SecurityContext = policy
1234 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1235 .expect("create source security context");
1236 let target_context_matched: SecurityContext = source_context.clone();
1237
1238 let decision_single = policy.compute_xperms_access_decision(
1242 XpermsKind::Ioctl,
1243 &source_context,
1244 &target_context_matched,
1245 class_id,
1246 0xdb,
1247 );
1248
1249 let expected_decision = XpermsAccessDecision {
1250 allow: XpermsBitmap::NONE,
1251 auditallow: XpermsBitmap::NONE,
1252 auditdeny: XpermsBitmap::ALL,
1253 };
1254 assert_eq!(decision_single, expected_decision);
1255 }
1256
1257 #[test]
1258 fn compute_ioctl_access_decision_unmatched() {
1259 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1260 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1261 let policy = policy.validate().expect("validate policy");
1262
1263 let source_context: SecurityContext = policy
1264 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1265 .expect("create source security context");
1266
1267 let target_context_unmatched: SecurityContext = policy
1269 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1270 .expect("create source security context");
1271
1272 for prefix in 0x0..=0xff {
1273 let decision = policy.compute_xperms_access_decision(
1274 XpermsKind::Ioctl,
1275 &source_context,
1276 &target_context_unmatched,
1277 KernelClass::File,
1278 prefix,
1279 );
1280 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1281 }
1282 }
1283
1284 #[test]
1285 fn compute_ioctl_earlier_redundant_prefixful_not_coalesced_into_prefixless() {
1286 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1287 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1288 let class_id = find_class_by_name(
1289 unvalidated.0.classes(),
1290 "class_earlier_redundant_prefixful_not_coalesced_into_prefixless",
1291 )
1292 .expect("look up class_earlier_redundant_prefixful_not_coalesced_into_prefixless")
1293 .id();
1294 let policy = unvalidated.validate().expect("validate policy");
1295 let source_context: SecurityContext = policy
1296 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1297 .expect("create source security context");
1298 let target_context_matched: SecurityContext = source_context.clone();
1299
1300 let decision = policy.compute_xperms_access_decision(
1305 XpermsKind::Ioctl,
1306 &source_context,
1307 &target_context_matched,
1308 class_id,
1309 0x7f,
1310 );
1311 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1312 let decision = policy.compute_xperms_access_decision(
1313 XpermsKind::Ioctl,
1314 &source_context,
1315 &target_context_matched,
1316 class_id,
1317 0x80,
1318 );
1319 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1320 let decision = policy.compute_xperms_access_decision(
1321 XpermsKind::Ioctl,
1322 &source_context,
1323 &target_context_matched,
1324 class_id,
1325 0x81,
1326 );
1327 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1328 }
1329
1330 #[test]
1331 fn compute_ioctl_later_redundant_prefixful_not_coalesced_into_prefixless() {
1332 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1333 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1334 let class_id = find_class_by_name(
1335 unvalidated.0.classes(),
1336 "class_later_redundant_prefixful_not_coalesced_into_prefixless",
1337 )
1338 .expect("look up class_later_redundant_prefixful_not_coalesced_into_prefixless")
1339 .id();
1340 let policy = unvalidated.validate().expect("validate policy");
1341 let source_context: SecurityContext = policy
1342 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1343 .expect("create source security context");
1344 let target_context_matched: SecurityContext = source_context.clone();
1345
1346 let decision = policy.compute_xperms_access_decision(
1351 XpermsKind::Ioctl,
1352 &source_context,
1353 &target_context_matched,
1354 class_id,
1355 0x8f,
1356 );
1357 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1358 let decision = policy.compute_xperms_access_decision(
1359 XpermsKind::Ioctl,
1360 &source_context,
1361 &target_context_matched,
1362 class_id,
1363 0x90,
1364 );
1365 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1366 let decision = policy.compute_xperms_access_decision(
1367 XpermsKind::Ioctl,
1368 &source_context,
1369 &target_context_matched,
1370 class_id,
1371 0x91,
1372 );
1373 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1374 }
1375
1376 #[test]
1377 fn compute_ioctl_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless() {
1378 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1379 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1380 let class_id = find_class_by_name(
1381 unvalidated.0.classes(),
1382 "class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless",
1383 )
1384 .expect("look up class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless")
1385 .id();
1386 let policy = unvalidated.validate().expect("validate policy");
1387 let source_context: SecurityContext = policy
1388 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1389 .expect("create source security context");
1390 let target_context_matched: SecurityContext = source_context.clone();
1391
1392 let decision = policy.compute_xperms_access_decision(
1398 XpermsKind::Ioctl,
1399 &source_context,
1400 &target_context_matched,
1401 class_id,
1402 0x9f,
1403 );
1404 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1405 let decision = policy.compute_xperms_access_decision(
1406 XpermsKind::Ioctl,
1407 &source_context,
1408 &target_context_matched,
1409 class_id,
1410 0xa0,
1411 );
1412 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1413 let decision = policy.compute_xperms_access_decision(
1414 XpermsKind::Ioctl,
1415 &source_context,
1416 &target_context_matched,
1417 class_id,
1418 0xa1,
1419 );
1420 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1421 }
1422
1423 #[test]
1424 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless() {
1425 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1426 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1427 let class_id = find_class_by_name(
1428 unvalidated.0.classes(),
1429 "class_prefixfuls_that_coalesce_to_prefixless",
1430 )
1431 .expect("look up class_prefixfuls_that_coalesce_to_prefixless")
1432 .id();
1433 let policy = unvalidated.validate().expect("validate policy");
1434 let source_context: SecurityContext = policy
1435 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1436 .expect("create source security context");
1437 let target_context_matched: SecurityContext = source_context.clone();
1438
1439 let decision = policy.compute_xperms_access_decision(
1445 XpermsKind::Ioctl,
1446 &source_context,
1447 &target_context_matched,
1448 class_id,
1449 0xaf,
1450 );
1451 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1452 let decision = policy.compute_xperms_access_decision(
1453 XpermsKind::Ioctl,
1454 &source_context,
1455 &target_context_matched,
1456 class_id,
1457 0xb0,
1458 );
1459 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1460 let decision = policy.compute_xperms_access_decision(
1461 XpermsKind::Ioctl,
1462 &source_context,
1463 &target_context_matched,
1464 class_id,
1465 0xb1,
1466 );
1467 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1468 }
1469
1470 #[test]
1471 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless() {
1472 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1473 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1474 let class_id = find_class_by_name(
1475 unvalidated.0.classes(),
1476 "class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless",
1477 )
1478 .expect("look up class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless")
1479 .id();
1480 let policy = unvalidated.validate().expect("validate policy");
1481 let source_context: SecurityContext = policy
1482 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1483 .expect("create source security context");
1484 let target_context_matched: SecurityContext = source_context.clone();
1485
1486 let decision = policy.compute_xperms_access_decision(
1493 XpermsKind::Ioctl,
1494 &source_context,
1495 &target_context_matched,
1496 class_id,
1497 0xbf,
1498 );
1499 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1500 let decision = policy.compute_xperms_access_decision(
1501 XpermsKind::Ioctl,
1502 &source_context,
1503 &target_context_matched,
1504 class_id,
1505 0xc0,
1506 );
1507 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1508 let decision = policy.compute_xperms_access_decision(
1509 XpermsKind::Ioctl,
1510 &source_context,
1511 &target_context_matched,
1512 class_id,
1513 0xc1,
1514 );
1515 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1516 let decision = policy.compute_xperms_access_decision(
1517 XpermsKind::Ioctl,
1518 &source_context,
1519 &target_context_matched,
1520 class_id,
1521 0xc2,
1522 );
1523 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1524 }
1525
1526 #[test]
1527 fn compute_ioctl_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless() {
1528 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1529 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1530 let class_id = find_class_by_name(
1531 unvalidated.0.classes(),
1532 "class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless",
1533 )
1534 .expect("look up class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless")
1535 .id();
1536 let policy = unvalidated.validate().expect("validate policy");
1537 let source_context: SecurityContext = policy
1538 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1539 .expect("create source security context");
1540 let target_context_matched: SecurityContext = source_context.clone();
1541
1542 let decision = policy.compute_xperms_access_decision(
1549 XpermsKind::Ioctl,
1550 &source_context,
1551 &target_context_matched,
1552 class_id,
1553 0xd5,
1554 );
1555 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1556 let decision = policy.compute_xperms_access_decision(
1557 XpermsKind::Ioctl,
1558 &source_context,
1559 &target_context_matched,
1560 class_id,
1561 0xd6,
1562 );
1563 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1564 let decision = policy.compute_xperms_access_decision(
1565 XpermsKind::Ioctl,
1566 &source_context,
1567 &target_context_matched,
1568 class_id,
1569 0xd7,
1570 );
1571 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1572 let decision = policy.compute_xperms_access_decision(
1573 XpermsKind::Ioctl,
1574 &source_context,
1575 &target_context_matched,
1576 class_id,
1577 0xd8,
1578 );
1579 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1580 }
1581
1582 #[test]
1593 fn compute_ioctl_ridiculous_permission_ordering() {
1594 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1595 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1596 let class_id =
1597 find_class_by_name(unvalidated.0.classes(), "class_ridiculous_permission_ordering")
1598 .expect("look up class_ridiculous_permission_ordering")
1599 .id();
1600 let policy = unvalidated.validate().expect("validate policy");
1601 let source_context: SecurityContext = policy
1602 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1603 .expect("create source security context");
1604 let target_context_matched: SecurityContext = source_context.clone();
1605
1606 let decision = policy.compute_xperms_access_decision(
1611 XpermsKind::Ioctl,
1612 &source_context,
1613 &target_context_matched,
1614 class_id,
1615 0x00,
1616 );
1617 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1618 let decision = policy.compute_xperms_access_decision(
1619 XpermsKind::Ioctl,
1620 &source_context,
1621 &target_context_matched,
1622 class_id,
1623 0x01,
1624 );
1625 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1626 let decision = policy.compute_xperms_access_decision(
1627 XpermsKind::Ioctl,
1628 &source_context,
1629 &target_context_matched,
1630 class_id,
1631 0xbf,
1632 );
1633 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1634 let decision = policy.compute_xperms_access_decision(
1635 XpermsKind::Ioctl,
1636 &source_context,
1637 &target_context_matched,
1638 class_id,
1639 0xc0,
1640 );
1641 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1642 let decision = policy.compute_xperms_access_decision(
1643 XpermsKind::Ioctl,
1644 &source_context,
1645 &target_context_matched,
1646 class_id,
1647 0xce,
1648 );
1649 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1650 let decision = policy.compute_xperms_access_decision(
1651 XpermsKind::Ioctl,
1652 &source_context,
1653 &target_context_matched,
1654 class_id,
1655 0xcf,
1656 );
1657 assert_eq!(
1658 decision,
1659 XpermsAccessDecision {
1660 allow: xperms_bitmap_from_elements((0x0..=0xf2).collect::<Vec<_>>().as_slice()),
1661 auditallow: XpermsBitmap::NONE,
1662 auditdeny: XpermsBitmap::ALL,
1663 }
1664 );
1665 let decision = policy.compute_xperms_access_decision(
1666 XpermsKind::Ioctl,
1667 &source_context,
1668 &target_context_matched,
1669 class_id,
1670 0xd0,
1671 );
1672 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1673 let decision = policy.compute_xperms_access_decision(
1674 XpermsKind::Ioctl,
1675 &source_context,
1676 &target_context_matched,
1677 class_id,
1678 0xe9,
1679 );
1680 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1681 let decision = policy.compute_xperms_access_decision(
1682 XpermsKind::Ioctl,
1683 &source_context,
1684 &target_context_matched,
1685 class_id,
1686 0xf0,
1687 );
1688 assert_eq!(
1689 decision,
1690 XpermsAccessDecision {
1691 allow: xperms_bitmap_from_elements(&[0x01]),
1692 auditallow: XpermsBitmap::NONE,
1693 auditdeny: XpermsBitmap::ALL,
1694 }
1695 );
1696 let decision = policy.compute_xperms_access_decision(
1697 XpermsKind::Ioctl,
1698 &source_context,
1699 &target_context_matched,
1700 class_id,
1701 0xf1,
1702 );
1703 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1704 let decision = policy.compute_xperms_access_decision(
1705 XpermsKind::Ioctl,
1706 &source_context,
1707 &target_context_matched,
1708 class_id,
1709 0xfc,
1710 );
1711 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1712 let decision = policy.compute_xperms_access_decision(
1713 XpermsKind::Ioctl,
1714 &source_context,
1715 &target_context_matched,
1716 class_id,
1717 0xfd,
1718 );
1719 assert_eq!(
1720 decision,
1721 XpermsAccessDecision {
1722 allow: xperms_bitmap_from_elements((0xfa..=0xfd).collect::<Vec<_>>().as_slice()),
1723 auditallow: XpermsBitmap::NONE,
1724 auditdeny: XpermsBitmap::ALL,
1725 }
1726 );
1727 let decision = policy.compute_xperms_access_decision(
1728 XpermsKind::Ioctl,
1729 &source_context,
1730 &target_context_matched,
1731 class_id,
1732 0xfe,
1733 );
1734 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1735 }
1736
1737 #[test]
1738 fn compute_nlmsg_access_decision_explicitly_allowed() {
1739 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1740 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1741 let policy = policy.validate().expect("validate policy");
1742
1743 let source_context: SecurityContext = policy
1744 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1745 .expect("create source security context");
1746 let target_context_matched: SecurityContext = source_context.clone();
1747
1748 let decision_single = policy.compute_xperms_access_decision(
1766 XpermsKind::Nlmsg,
1767 &source_context,
1768 &target_context_matched,
1769 KernelClass::NetlinkRouteSocket,
1770 0xab,
1771 );
1772
1773 let mut expected_auditdeny =
1774 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1775 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1776
1777 let expected_decision_single = XpermsAccessDecision {
1778 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1779 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1780 auditdeny: expected_auditdeny,
1781 };
1782 assert_eq!(decision_single, expected_decision_single);
1783
1784 let decision_range = policy.compute_xperms_access_decision(
1785 XpermsKind::Nlmsg,
1786 &source_context,
1787 &target_context_matched,
1788 KernelClass::NetlinkRouteSocket,
1789 0x10,
1790 );
1791 let expected_decision_range = XpermsAccessDecision {
1792 allow: XpermsBitmap::ALL,
1793 auditallow: XpermsBitmap::ALL,
1794 auditdeny: XpermsBitmap::NONE,
1795 };
1796 assert_eq!(decision_range, expected_decision_range);
1797 }
1798
1799 #[test]
1800 fn compute_nlmsg_access_decision_unmatched() {
1801 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1802 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1803 let policy = policy.validate().expect("validate policy");
1804
1805 let source_context: SecurityContext = policy
1806 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1807 .expect("create source security context");
1808
1809 let target_context_unmatched: SecurityContext = policy
1811 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1812 .expect("create source security context");
1813
1814 for prefix in 0x0..=0xff {
1815 let decision = policy.compute_xperms_access_decision(
1816 XpermsKind::Nlmsg,
1817 &source_context,
1818 &target_context_unmatched,
1819 KernelClass::NetlinkRouteSocket,
1820 prefix,
1821 );
1822 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1823 }
1824 }
1825
1826 #[test]
1827 fn compute_ioctl_grant_does_not_cause_nlmsg_deny() {
1828 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1829 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1830 let class_id = find_class_by_name(
1831 unvalidated.0.classes(),
1832 "class_ioctl_grant_does_not_cause_nlmsg_deny",
1833 )
1834 .expect("look up class_ioctl_grant_does_not_cause_nlmsg_deny")
1835 .id();
1836 let policy = unvalidated.validate().expect("validate policy");
1837 let source_context: SecurityContext = policy
1838 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1839 .expect("create source security context");
1840 let target_context_matched: SecurityContext = source_context.clone();
1841
1842 let ioctl_decision = policy.compute_xperms_access_decision(
1846 XpermsKind::Ioctl,
1847 &source_context,
1848 &target_context_matched,
1849 class_id,
1850 0x00,
1851 );
1852 assert_eq!(
1853 ioctl_decision,
1854 XpermsAccessDecision {
1855 allow: xperms_bitmap_from_elements(&[0x0002]),
1856 auditallow: XpermsBitmap::NONE,
1857 auditdeny: XpermsBitmap::ALL,
1858 }
1859 );
1860 let nlmsg_decision = policy.compute_xperms_access_decision(
1861 XpermsKind::Nlmsg,
1862 &source_context,
1863 &target_context_matched,
1864 class_id,
1865 0x00,
1866 );
1867 assert_eq!(nlmsg_decision, XpermsAccessDecision::ALLOW_ALL);
1868 }
1869
1870 #[test]
1871 fn compute_nlmsg_grant_does_not_cause_ioctl_deny() {
1872 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1873 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1874 let class_id = find_class_by_name(
1875 unvalidated.0.classes(),
1876 "class_nlmsg_grant_does_not_cause_ioctl_deny",
1877 )
1878 .expect("look up class_nlmsg_grant_does_not_cause_ioctl_deny")
1879 .id();
1880 let policy = unvalidated.validate().expect("validate policy");
1881 let source_context: SecurityContext = policy
1882 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1883 .expect("create source security context");
1884 let target_context_matched: SecurityContext = source_context.clone();
1885
1886 let nlmsg_decision = policy.compute_xperms_access_decision(
1890 XpermsKind::Nlmsg,
1891 &source_context,
1892 &target_context_matched,
1893 class_id,
1894 0x00,
1895 );
1896 assert_eq!(
1897 nlmsg_decision,
1898 XpermsAccessDecision {
1899 allow: xperms_bitmap_from_elements(&[0x0003]),
1900 auditallow: XpermsBitmap::NONE,
1901 auditdeny: XpermsBitmap::ALL,
1902 }
1903 );
1904 let ioctl_decision = policy.compute_xperms_access_decision(
1905 XpermsKind::Ioctl,
1906 &source_context,
1907 &target_context_matched,
1908 class_id,
1909 0x00,
1910 );
1911 assert_eq!(ioctl_decision, XpermsAccessDecision::ALLOW_ALL);
1912 }
1913
1914 #[test]
1915 fn compute_create_context_minimal() {
1916 let policy_bytes =
1917 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1918 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1919 let policy = policy.validate().expect("validate policy");
1920 let source = policy
1921 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1922 .expect("valid source security context");
1923 let target = policy
1924 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1925 .expect("valid target security context");
1926
1927 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1928 let expected: SecurityContext = policy
1929 .parse_security_context(b"source_u:object_r:target_t:s0:c0".into())
1930 .expect("valid expected security context");
1931
1932 assert_eq!(expected, actual);
1933 }
1934
1935 #[test]
1936 fn new_security_context_minimal() {
1937 let policy_bytes =
1938 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1939 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1940 let policy = policy.validate().expect("validate policy");
1941 let source = policy
1942 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1943 .expect("valid source security context");
1944 let target = policy
1945 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1946 .expect("valid target security context");
1947
1948 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1949
1950 assert_eq!(source, actual);
1951 }
1952
1953 #[test]
1954 fn compute_create_context_class_defaults() {
1955 let policy_bytes =
1956 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1957 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1958 let policy = policy.validate().expect("validate policy");
1959 let source = policy
1960 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1961 .expect("valid source security context");
1962 let target = policy
1963 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1964 .expect("valid target security context");
1965
1966 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1967 let expected: SecurityContext = policy
1968 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1969 .expect("valid expected security context");
1970
1971 assert_eq!(expected, actual);
1972 }
1973
1974 #[test]
1975 fn new_security_context_class_defaults() {
1976 let policy_bytes =
1977 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1978 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1979 let policy = policy.validate().expect("validate policy");
1980 let source = policy
1981 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1982 .expect("valid source security context");
1983 let target = policy
1984 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1985 .expect("valid target security context");
1986
1987 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1988 let expected: SecurityContext = policy
1989 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1990 .expect("valid expected security context");
1991
1992 assert_eq!(expected, actual);
1993 }
1994
1995 #[test]
1996 fn compute_create_context_role_transition() {
1997 let policy_bytes =
1998 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
1999 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2000 let policy = policy.validate().expect("validate policy");
2001 let source = policy
2002 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2003 .expect("valid source security context");
2004 let target = policy
2005 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2006 .expect("valid target security context");
2007
2008 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2009 let expected: SecurityContext = policy
2010 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
2011 .expect("valid expected security context");
2012
2013 assert_eq!(expected, actual);
2014 }
2015
2016 #[test]
2017 fn new_security_context_role_transition() {
2018 let policy_bytes =
2019 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
2020 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2021 let policy = policy.validate().expect("validate policy");
2022 let source = policy
2023 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2024 .expect("valid source security context");
2025 let target = policy
2026 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2027 .expect("valid target security context");
2028
2029 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2030 let expected: SecurityContext = policy
2031 .parse_security_context(b"source_u:transition_r:source_t:s0:c0-s2:c0.c1".into())
2032 .expect("valid expected security context");
2033
2034 assert_eq!(expected, actual);
2035 }
2036
2037 #[test]
2038 #[ignore]
2040 fn compute_create_context_role_transition_not_allowed() {
2041 let policy_bytes = include_bytes!(
2042 "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy.pp"
2043 );
2044 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2045 let policy = policy.validate().expect("validate policy");
2046 let source = policy
2047 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2048 .expect("valid source security context");
2049 let target = policy
2050 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2051 .expect("valid target security context");
2052
2053 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2054
2055 assert!(policy.validate_security_context(&actual).is_err());
2057 }
2058
2059 #[test]
2060 fn compute_create_context_type_transition() {
2061 let policy_bytes =
2062 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
2063 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2064 let policy = policy.validate().expect("validate policy");
2065 let source = policy
2066 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2067 .expect("valid source security context");
2068 let target = policy
2069 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2070 .expect("valid target security context");
2071
2072 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2073 let expected: SecurityContext = policy
2074 .parse_security_context(b"source_u:object_r:transition_t:s0:c0".into())
2075 .expect("valid expected security context");
2076
2077 assert_eq!(expected, actual);
2078 }
2079
2080 #[test]
2081 fn new_security_context_type_transition() {
2082 let policy_bytes =
2083 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
2084 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2085 let policy = policy.validate().expect("validate policy");
2086 let source = policy
2087 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2088 .expect("valid source security context");
2089 let target = policy
2090 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2091 .expect("valid target security context");
2092
2093 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2094 let expected: SecurityContext = policy
2095 .parse_security_context(b"source_u:source_r:transition_t:s0:c0-s2:c0.c1".into())
2096 .expect("valid expected security context");
2097
2098 assert_eq!(expected, actual);
2099 }
2100
2101 #[test]
2102 fn compute_create_context_range_transition() {
2103 let policy_bytes =
2104 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
2105 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2106 let policy = policy.validate().expect("validate policy");
2107 let source = policy
2108 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2109 .expect("valid source security context");
2110 let target = policy
2111 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2112 .expect("valid target security context");
2113
2114 let actual = policy.compute_create_context(&source, &target, FileClass::File);
2115 let expected: SecurityContext = policy
2116 .parse_security_context(b"source_u:object_r:target_t:s1:c1-s2:c1.c2".into())
2117 .expect("valid expected security context");
2118
2119 assert_eq!(expected, actual);
2120 }
2121
2122 #[test]
2123 fn new_security_context_range_transition() {
2124 let policy_bytes =
2125 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
2126 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2127 let policy = policy.validate().expect("validate policy");
2128 let source = policy
2129 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
2130 .expect("valid source security context");
2131 let target = policy
2132 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
2133 .expect("valid target security context");
2134
2135 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
2136 let expected: SecurityContext = policy
2137 .parse_security_context(b"source_u:source_r:source_t:s1:c1-s2:c1.c2".into())
2138 .expect("valid expected security context");
2139
2140 assert_eq!(expected, actual);
2141 }
2142
2143 #[test]
2144 fn access_vector_formats() {
2145 assert_eq!(format!("{:x}", AccessVector::NONE), "0");
2146 assert_eq!(format!("{:x}", AccessVector::ALL), "ffffffff");
2147 assert_eq!(format!("{:?}", AccessVector::NONE), "AccessVector(00000000)");
2148 assert_eq!(format!("{:?}", AccessVector::ALL), "AccessVector(ffffffff)");
2149 }
2150}