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
23pub use crate::new_policy::traits::PolicyId;
24use crate::new_policy::traits::Serialize as _;
25pub use crate::new_policy::{
26 AccessVector, CategoryId, ClassId, HandleUnknown, MlsLevel, MlsRange, POLICYDB_VERSION_MAX,
27 PermissionId, RoleId, SensitivityId, TypeId, UserId,
28};
29use crate::{ClassPermission, KernelClass, NullessByteStr, ObjectClass, new_policy as new};
30use index::PolicyIndex;
31use parsed_policy::ParsedPolicy;
32use parser::PolicyData;
33
34use anyhow::Context as _;
35use std::fmt::Debug;
36use std::num::NonZeroU32;
37use std::ops::Deref;
38
39use std::sync::Arc;
40use zerocopy::{
41 FromBytes, Immutable, KnownLayout, Ref, SplitByteSlice, Unaligned, little_endian as le,
42};
43
44impl<T, Tag> Parse for crate::new_policy::IdType<T, Tag>
45where
46 crate::new_policy::IdType<T, Tag>: crate::new_policy::traits::PolicyId,
47{
48 type Error = error::ParseError;
49
50 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
51 let (id_val, tail) = PolicyCursor::parse::<le::U32>(bytes)?;
52 let id = Self::try_from(id_val.get())
53 .map_err(|_| error::ParseError::InvalidId { value: id_val.get() })?;
54 Ok((id, tail))
55 }
56}
57
58impl<T, Tag> Validate for crate::new_policy::IdType<T, Tag>
59where
60 crate::new_policy::IdType<T, Tag>: crate::new_policy::traits::PolicyId,
61{
62 type Error = anyhow::Error;
63
64 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
65 Ok(())
66 }
67}
68
69#[derive(Debug, Clone, PartialEq)]
74pub struct AccessDecision {
75 pub allow: AccessVector,
76 pub auditallow: AccessVector,
77 pub auditdeny: AccessVector,
78 pub flags: u32,
79
80 pub todo_bug: Option<NonZeroU32>,
83}
84
85impl Default for AccessDecision {
86 fn default() -> Self {
87 Self::allow(AccessVector::NONE)
88 }
89}
90
91impl AccessDecision {
92 pub(super) const fn allow(allow: AccessVector) -> Self {
95 Self {
96 allow,
97 auditallow: AccessVector::NONE,
98 auditdeny: AccessVector::ALL,
99 flags: 0,
100 todo_bug: None,
101 }
102 }
103}
104
105pub(super) const SELINUX_AVD_FLAGS_PERMISSIVE: u32 = 1;
107
108#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
111pub enum XpermsKind {
112 Ioctl,
113 Nlmsg,
114}
115
116#[derive(Debug, Clone, PartialEq)]
121pub struct XpermsAccessDecision {
122 pub allow: XpermsBitmap,
123 pub auditallow: XpermsBitmap,
124 pub auditdeny: XpermsBitmap,
125}
126
127impl XpermsAccessDecision {
128 pub const DENY_ALL: Self = Self {
129 allow: XpermsBitmap::NONE,
130 auditallow: XpermsBitmap::NONE,
131 auditdeny: XpermsBitmap::ALL,
132 };
133 pub const ALLOW_ALL: Self = Self {
134 allow: XpermsBitmap::ALL,
135 auditallow: XpermsBitmap::NONE,
136 auditdeny: XpermsBitmap::ALL,
137 };
138}
139
140pub fn parse_policy_by_value(binary_policy: Vec<u8>) -> Result<Unvalidated, anyhow::Error> {
149 let policy_data: PolicyData = Arc::from(binary_policy);
150 let policy = ParsedPolicy::parse(policy_data).context("parsing policy")?;
151 Ok(Unvalidated(policy))
152}
153
154#[derive(Debug)]
155pub struct Policy(PolicyIndex);
156
157impl Deref for Policy {
158 type Target = PolicyIndex;
159
160 fn deref(&self) -> &Self::Target {
161 &self.0
162 }
163}
164
165impl Policy {
166 pub fn serialize(&self) -> PolicyData {
168 let mut bytes = Vec::new();
169 self.0.serialize(&mut bytes).expect("serialization of new_policy should succeed");
170 std::sync::Arc::from(bytes)
171 }
172
173 pub fn conditional_booleans<'a>(&'a self) -> Vec<(&'a [u8], bool)> {
174 self.0
175 .conditional_booleans()
176 .iter()
177 .map(|boolean| (boolean.data.as_slice(), boolean.metadata.active()))
178 .collect()
179 }
180
181 pub fn find_class_permissions_by_name(
186 &self,
187 class_name: &str,
188 ) -> Result<Vec<(PermissionId, Vec<u8>)>, ()> {
189 let classes = self.classes();
190 let class = classes.get_by_name(class_name.as_bytes()).ok_or(())?;
191 let owned_permissions = class.permissions();
192
193 let mut result: Vec<_> = owned_permissions
194 .iter()
195 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
196 .collect();
197
198 if class.common_name().is_empty() {
200 return Ok(result);
201 }
202
203 let common_symbol_permissions =
204 self.common_symbols().get_by_name(class.common_name()).ok_or(())?.permissions();
205
206 result.append(
207 &mut common_symbol_permissions
208 .iter()
209 .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
210 .collect(),
211 );
212
213 Ok(result)
214 }
215
216 pub fn fs_use_label_and_type(&self, fs_type: NullessByteStr<'_>) -> Option<FsUseLabelAndType> {
219 self.0.fs_use_label_and_type(fs_type)
220 }
221
222 pub fn genfscon_label_for_fs_and_path(
225 &self,
226 fs_type: NullessByteStr<'_>,
227 node_path: NullessByteStr<'_>,
228 class_id: Option<KernelClass>,
229 ) -> Option<SecurityContext> {
230 self.0.genfscon_label_for_fs_and_path(fs_type, node_path, class_id)
231 }
232
233 pub fn initial_context(&self, id: crate::InitialSid) -> security_context::SecurityContext {
236 self.0.initial_context(id)
237 }
238
239 pub fn parse_security_context(
241 &self,
242 security_context: NullessByteStr<'_>,
243 ) -> Result<security_context::SecurityContext, security_context::SecurityContextError> {
244 security_context::SecurityContext::from_string(&self.0, security_context)
245 }
246
247 pub fn validate_security_context(
249 &self,
250 security_context: &SecurityContext,
251 ) -> Result<(), SecurityContextError> {
252 security_context.validate(&self.0)
253 }
254
255 pub fn serialize_security_context(&self, security_context: &SecurityContext) -> Vec<u8> {
257 security_context.to_string(&self.0)
258 }
259
260 pub fn compute_create_context_with_name(
268 &self,
269 source: &SecurityContext,
270 target: &SecurityContext,
271 class: impl Into<ObjectClass>,
272 name: NullessByteStr<'_>,
273 ) -> Option<SecurityContext> {
274 self.0.compute_create_context_with_name(source, target, class.into(), name)
275 }
276
277 pub fn compute_create_context(
295 &self,
296 source: &SecurityContext,
297 target: &SecurityContext,
298 class: impl Into<ObjectClass>,
299 ) -> SecurityContext {
300 self.0.compute_create_context(source, target, class.into())
301 }
302
303 pub fn compute_access_decision(
313 &self,
314 source_context: &SecurityContext,
315 target_context: &SecurityContext,
316 object_class: impl Into<ObjectClass>,
317 ) -> AccessDecision {
318 if let Some(target_class) = self.0.class(object_class.into()) {
319 self.0.compute_access_decision(source_context, target_context, &target_class)
320 } else {
321 let mut decision = AccessDecision::allow(AccessVector::NONE);
322 if self.is_permissive(source_context.type_()) {
323 decision.flags |= SELINUX_AVD_FLAGS_PERMISSIVE;
324 }
325 decision
326 }
327 }
328
329 pub fn compute_xperms_access_decision(
333 &self,
334 xperms_kind: XpermsKind,
335 source_context: &SecurityContext,
336 target_context: &SecurityContext,
337 object_class: impl Into<ObjectClass>,
338 xperms_prefix: u8,
339 ) -> XpermsAccessDecision {
340 if let Some(target_class) = self.0.class(object_class.into()) {
341 self.0.compute_xperms_access_decision(
342 xperms_kind,
343 source_context,
344 target_context,
345 &target_class,
346 xperms_prefix,
347 )
348 } else {
349 XpermsAccessDecision::DENY_ALL
350 }
351 }
352
353 pub fn is_bounded_by(&self, bounded_type: TypeId, parent_type: TypeId) -> bool {
354 self.0.type_(bounded_type).bounded_by() == Some(parent_type)
355 }
356
357 pub fn is_permissive(&self, type_: TypeId) -> bool {
359 self.0.permissive_map().contains(type_)
360 }
361}
362
363impl AccessVectorComputer for Policy {
364 fn access_decision_to_kernel_access_decision(
365 &self,
366 class: KernelClass,
367 av: AccessDecision,
368 ) -> KernelAccessDecision {
369 let mut kernel_allow;
370 let mut kernel_audit;
371 if self.0.handle_unknown() == HandleUnknown::Allow {
374 kernel_allow = 0xffffffffu32;
376 kernel_audit = 0u32;
377 } else {
378 kernel_allow = 0u32;
380 kernel_audit = 0xffffffffu32;
381 }
382
383 let decision_allow = av.allow;
384 let decision_audit = (av.allow & av.auditallow) | (!av.allow & av.auditdeny);
385 for permission in class.permissions() {
386 if let Some(permission_access_vector) =
387 self.0.kernel_permission_to_access_vector(permission.clone())
388 {
389 let bit = 1 << permission.id();
392 let allow = decision_allow & permission_access_vector == permission_access_vector;
393 let audit = decision_audit & permission_access_vector == permission_access_vector;
394 kernel_allow = (kernel_allow & !bit) | ((allow as u32) << permission.id());
395 kernel_audit = (kernel_audit & !bit) | ((audit as u32) << permission.id());
396 }
397 }
398 KernelAccessDecision {
399 allow: AccessVector::from(kernel_allow),
400 audit: AccessVector::from(kernel_audit),
401 flags: av.flags,
402 todo_bug: av.todo_bug,
403 }
404 }
405}
406
407pub struct Unvalidated(ParsedPolicy);
409
410impl Unvalidated {
411 pub fn validate(self) -> Result<Policy, anyhow::Error> {
412 self.0.validate().context("validating parsed policy")?;
413 let index = PolicyIndex::new(self.0).context("building index")?;
414 Ok(Policy(index))
415 }
416}
417
418#[derive(Clone, Copy, Debug, PartialEq, Eq)]
419pub struct KernelAccessDecision {
420 pub allow: AccessVector,
421 pub audit: AccessVector,
422 pub flags: u32,
423 pub todo_bug: Option<NonZeroU32>,
424}
425
426pub trait AccessVectorComputer {
429 fn access_decision_to_kernel_access_decision(
436 &self,
437 class: KernelClass,
438 av: AccessDecision,
439 ) -> KernelAccessDecision;
440}
441
442pub trait Parse: Sized {
444 type Error: Into<anyhow::Error>;
447
448 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error>;
451}
452
453pub(super) struct PolicyValidationContext {
455 pub(super) data: PolicyData,
457
458 pub(super) need_init_sid: bool,
460
461 pub(super) new_policy: Arc<new::NewPolicy>,
463}
464
465pub(super) trait Validate {
467 type Error: Into<anyhow::Error>;
470
471 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error>;
473}
474
475pub(super) trait ValidateArray<M, D> {
476 type Error: Into<anyhow::Error>;
479
480 fn validate_array(
482 context: &PolicyValidationContext,
483 metadata: &M,
484 items: &[D],
485 ) -> Result<(), Self::Error>;
486}
487
488pub(super) trait Counted {
490 fn count(&self) -> u32;
492}
493
494impl<T: Validate> Validate for Option<T> {
495 type Error = <T as Validate>::Error;
496
497 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
498 match self {
499 Some(value) => value.validate(context),
500 None => Ok(()),
501 }
502 }
503}
504
505impl<T: Validate> Validate for Vec<T> {
506 type Error = <T as Validate>::Error;
507
508 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
509 for item in self {
510 item.validate(context)?;
511 }
512 Ok(())
513 }
514}
515
516impl Validate for le::U32 {
517 type Error = anyhow::Error;
518
519 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
522 Ok(())
523 }
524}
525
526impl Validate for u8 {
527 type Error = anyhow::Error;
528
529 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
532 Ok(())
533 }
534}
535
536impl<B: SplitByteSlice, T: Validate + FromBytes + KnownLayout + Immutable> Validate for Ref<B, T> {
537 type Error = <T as Validate>::Error;
538
539 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
540 self.deref().validate(context)
541 }
542}
543
544impl<B: SplitByteSlice, T: Counted + FromBytes + KnownLayout + Immutable> Counted for Ref<B, T> {
545 fn count(&self) -> u32 {
546 self.deref().count()
547 }
548}
549
550#[derive(Clone, Debug, PartialEq)]
552struct Array<M, T> {
553 metadata: M,
554 data: Vec<T>,
555}
556
557impl<M: Counted + Parse, T: Parse> Parse for Array<M, T> {
558 type Error = anyhow::Error;
561
562 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
564 let tail = bytes;
565
566 let (metadata, tail) = M::parse(tail).map_err(Into::<anyhow::Error>::into)?;
567
568 let count = metadata.count() as usize;
569 let mut data = Vec::with_capacity(count);
570 let mut cur_tail = tail;
571 for _ in 0..count {
572 let (item, next_tail) = T::parse(cur_tail).map_err(Into::<anyhow::Error>::into)?;
573 data.push(item);
574 cur_tail = next_tail;
575 }
576 let tail = cur_tail;
577
578 let array = Self { metadata, data };
579
580 Ok((array, tail))
581 }
582}
583
584impl<T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned> Parse for T {
585 type Error = anyhow::Error;
586
587 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
588 bytes.parse::<T>().map_err(anyhow::Error::from)
589 }
590}
591
592macro_rules! array_type {
596 ($type_name:ident, $metadata_type:ty, $data_type:ty, $metadata_type_name:expr, $data_type_name:expr) => {
597 #[doc = "An [`Array`] with [`"]
598 #[doc = $metadata_type_name]
599 #[doc = "`] metadata and [`"]
600 #[doc = $data_type_name]
601 #[doc = "`] data items."]
602 #[derive(Debug, PartialEq)]
603 pub(super) struct $type_name(super::Array<$metadata_type, $data_type>);
604
605 impl std::ops::Deref for $type_name {
606 type Target = super::Array<$metadata_type, $data_type>;
607
608 fn deref(&self) -> &Self::Target {
609 &self.0
610 }
611 }
612
613 impl super::Parse for $type_name
614 where
615 super::Array<$metadata_type, $data_type>: super::Parse,
616 {
617 type Error = <Array<$metadata_type, $data_type> as super::Parse>::Error;
618
619 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
620 let (array, tail) = Array::<$metadata_type, $data_type>::parse(bytes)?;
621 Ok((Self(array), tail))
622 }
623 }
624 };
625
626 ($type_name:ident, $metadata_type:ty, $data_type:ty) => {
627 array_type!(
628 $type_name,
629 $metadata_type,
630 $data_type,
631 stringify!($metadata_type),
632 stringify!($data_type)
633 );
634 };
635}
636
637pub(super) use array_type;
638
639macro_rules! array_type_validate_deref_both {
640 ($type_name:ident) => {
641 impl Validate for $type_name {
642 type Error = anyhow::Error;
643
644 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
645 let metadata = &self.metadata;
646 metadata.validate(context)?;
647
648 self.data.validate(context).map_err(Into::<anyhow::Error>::into)?;
649
650 Self::validate_array(context, metadata, &self.data)
651 .map_err(Into::<anyhow::Error>::into)
652 }
653 }
654 };
655}
656
657pub(super) use array_type_validate_deref_both;
658
659#[cfg(test)]
660pub(super) mod testing {
661 use super::error::ParseError;
662
663 pub(super) fn as_parse_error(error: anyhow::Error) -> ParseError {
665 error.downcast::<ParseError>().expect("parse error")
666 }
667}
668
669#[cfg(test)]
670pub(super) mod tests {
671 use super::arrays::XpermsBitmap;
672 use super::security_context::SecurityContext;
673 use super::{
674 AccessVector, ClassId, HandleUnknown, Policy, TypeId, XpermsAccessDecision, XpermsKind,
675 parse_policy_by_value,
676 };
677 use crate::new_policy::traits::HasPolicyId;
678 use crate::{FileClass, InitialSid, KernelClass};
679
680 use anyhow::Context as _;
681 use serde::Deserialize;
682 use std::ops::{Deref, Shl};
683 use zerocopy::little_endian as le;
684
685 fn is_explicitly_allowed(
693 policy: &Policy,
694 source_type: TypeId,
695 target_type: TypeId,
696 target_class: &str,
697 permission: &str,
698 ) -> bool {
699 let classes = policy.classes();
700 let class = classes.get_by_name(target_class.as_bytes()).expect("class not found");
701 let class_permissions = policy
702 .find_class_permissions_by_name(target_class)
703 .expect("class permissions not found");
704 let (permission_id, _) = class_permissions
705 .iter()
706 .find(|(_, name)| permission.as_bytes() == name)
707 .expect("permission not found");
708 let permission_bit = AccessVector::from(*permission_id);
709 let access_decision = policy.0.compute_explicitly_allowed(source_type, target_type, class);
710 permission_bit == access_decision.allow & permission_bit
711 }
712
713 #[derive(Debug, Deserialize)]
714 struct Expectations {
715 expected_policy_version: u32,
716 expected_handle_unknown: LocalHandleUnknown,
717 }
718
719 #[derive(Debug, Deserialize, PartialEq)]
720 #[serde(rename_all = "snake_case")]
721 enum LocalHandleUnknown {
722 Deny,
723 Reject,
724 Allow,
725 }
726
727 impl PartialEq<HandleUnknown> for LocalHandleUnknown {
728 fn eq(&self, other: &HandleUnknown) -> bool {
729 match self {
730 LocalHandleUnknown::Deny => *other == HandleUnknown::Deny,
731 LocalHandleUnknown::Reject => *other == HandleUnknown::Reject,
732 LocalHandleUnknown::Allow => *other == HandleUnknown::Allow,
733 }
734 }
735 }
736
737 fn xperms_bitmap_from_elements(elements: &[u8]) -> XpermsBitmap {
740 let mut bitmap = [le::U32::ZERO; 8];
741 for element in elements {
742 let block_index = (*element as usize) / 32;
743 let bit_index = ((*element as usize) % 32) as u32;
744 let bitmask = le::U32::new(1).shl(bit_index);
745 bitmap[block_index] = bitmap[block_index] | bitmask;
746 }
747 XpermsBitmap::new(bitmap)
748 }
749
750 #[test]
751 fn known_policies() {
752 let policies_and_expectations = [
753 [
754 b"testdata/policies/emulator".to_vec(),
755 include_bytes!("../../testdata/policies/emulator").to_vec(),
756 include_bytes!("../../testdata/expectations/emulator").to_vec(),
757 ],
758 [
759 b"testdata/policies/selinux_testsuite".to_vec(),
760 include_bytes!("../../testdata/policies/selinux_testsuite").to_vec(),
761 include_bytes!("../../testdata/expectations/selinux_testsuite").to_vec(),
762 ],
763 ];
764
765 for [policy_path, policy_bytes, expectations_bytes] in policies_and_expectations {
766 let expectations = serde_json5::from_reader::<_, Expectations>(
767 &mut std::io::Cursor::new(expectations_bytes),
768 )
769 .expect("deserialize expectations");
770
771 let unvalidated_policy =
774 parse_policy_by_value(policy_bytes.clone()).expect("parse policy");
775
776 let policy = unvalidated_policy
777 .validate()
778 .with_context(|| {
779 format!(
780 "policy path: {:?}",
781 std::str::from_utf8(policy_path.as_slice()).unwrap()
782 )
783 })
784 .expect("validate policy");
785
786 assert_eq!(expectations.expected_policy_version, policy.policy_version());
787 assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
788
789 let binary_policy = policy.serialize();
791 assert_eq!(&policy_bytes, binary_policy.deref());
792 }
793 }
794
795 #[test]
796 fn policy_lookup() {
797 let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
798 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
799 let policy = policy.validate().expect("validate selinux testsuite policy");
800
801 let unconfined_t = policy.type_id_by_name("unconfined_t").expect("look up type id");
802
803 assert!(is_explicitly_allowed(&policy, unconfined_t, unconfined_t, "process", "fork",));
804 }
805
806 #[test]
807 fn initial_contexts() {
808 let policy_bytes =
809 include_bytes!("../../testdata/micro_policies/multiple_levels_and_categories_policy");
810 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
811 let policy = policy.validate().expect("validate policy");
812
813 let kernel_context = policy.initial_context(InitialSid::Kernel);
814 assert_eq!(
815 policy.serialize_security_context(&kernel_context),
816 b"user0:object_r:type0:s0:c0-s1:c0.c2,c4"
817 )
818 }
819
820 #[test]
821 fn explicit_allow_type_type() {
822 let policy_bytes =
823 include_bytes!("../../testdata/micro_policies/allow_a_t_b_t_class0_perm0_policy");
824 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
825 let policy = policy.validate().expect("validate policy");
826
827 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
828 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
829
830 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
831 }
832
833 #[test]
834 fn no_explicit_allow_type_type() {
835 let policy_bytes =
836 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_t_class0_perm0_policy");
837 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
838 let policy = policy.validate().expect("validate policy");
839
840 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
841 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
842
843 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
844 }
845
846 #[test]
847 fn explicit_allow_type_attr() {
848 let policy_bytes =
849 include_bytes!("../../testdata/micro_policies/allow_a_t_b_attr_class0_perm0_policy");
850 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
851 let policy = policy.validate().expect("validate policy");
852
853 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
854 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
855
856 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
857 }
858
859 #[test]
860 fn no_explicit_allow_type_attr() {
861 let policy_bytes =
862 include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_attr_class0_perm0_policy");
863 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
864 let policy = policy.validate().expect("validate policy");
865
866 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
867 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
868
869 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
870 }
871
872 #[test]
873 fn explicit_allow_attr_attr() {
874 let policy_bytes =
875 include_bytes!("../../testdata/micro_policies/allow_a_attr_b_attr_class0_perm0_policy");
876 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
877 let policy = policy.validate().expect("validate policy");
878
879 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
880 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
881
882 assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
883 }
884
885 #[test]
886 fn no_explicit_allow_attr_attr() {
887 let policy_bytes = include_bytes!(
888 "../../testdata/micro_policies/no_allow_a_attr_b_attr_class0_perm0_policy"
889 );
890 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
891 let policy = policy.validate().expect("validate policy");
892
893 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
894 let b_t = policy.type_id_by_name("b_t").expect("look up type id");
895
896 assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
897 }
898
899 #[test]
900 fn compute_explicitly_allowed_multiple_attributes() {
901 let policy_bytes = include_bytes!(
902 "../../testdata/micro_policies/allow_a_t_a1_attr_class0_perm0_a2_attr_class0_perm1_policy"
903 );
904 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
905 let policy = policy.validate().expect("validate policy");
906
907 let a_t = policy.type_id_by_name("a_t").expect("look up type id");
908
909 let classes = policy.classes();
910 let class = classes.get_by_name(b"class0").expect("class not found");
911 let raw_access_vector = policy.0.compute_explicitly_allowed(a_t, a_t, class).allow.value();
912
913 assert_eq!(2, raw_access_vector.count_ones());
918 }
919
920 #[test]
921 fn compute_access_decision_with_constraints() {
922 let policy_bytes =
923 include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy");
924 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
925 let policy = policy.validate().expect("validate policy");
926
927 let source_context: SecurityContext = policy
928 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
929 .expect("create source security context");
930
931 let target_context_satisfied: SecurityContext = source_context.clone();
932 let decision_satisfied = policy.compute_access_decision(
933 &source_context,
934 &target_context_satisfied,
935 KernelClass::File,
936 );
937 assert_eq!(decision_satisfied.allow, AccessVector::from(7));
941
942 let target_context_unsatisfied: SecurityContext = policy
943 .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
944 .expect("create target security context failing some constraints");
945 let decision_unsatisfied = policy.compute_access_decision(
946 &source_context,
947 &target_context_unsatisfied,
948 KernelClass::File,
949 );
950 assert_eq!(decision_unsatisfied.allow, AccessVector::from(4));
953 }
954
955 #[test]
956 fn compute_ioctl_access_decision_explicitly_allowed() {
957 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
958 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
959 let policy = policy.validate().expect("validate policy");
960
961 let source_context: SecurityContext = policy
962 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
963 .expect("create source security context");
964 let target_context_matched: SecurityContext = source_context.clone();
965
966 let decision_single = policy.compute_xperms_access_decision(
984 XpermsKind::Ioctl,
985 &source_context,
986 &target_context_matched,
987 KernelClass::File,
988 0xab,
989 );
990
991 let mut expected_auditdeny =
992 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
993 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
994
995 let expected_decision_single = XpermsAccessDecision {
996 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
997 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
998 auditdeny: expected_auditdeny,
999 };
1000 assert_eq!(decision_single, expected_decision_single);
1001
1002 let decision_range = policy.compute_xperms_access_decision(
1003 XpermsKind::Ioctl,
1004 &source_context,
1005 &target_context_matched,
1006 KernelClass::File,
1007 0x10,
1008 );
1009 let expected_decision_range = XpermsAccessDecision {
1010 allow: XpermsBitmap::ALL,
1011 auditallow: XpermsBitmap::ALL,
1012 auditdeny: XpermsBitmap::NONE,
1013 };
1014 assert_eq!(decision_range, expected_decision_range);
1015 }
1016
1017 #[test]
1018 fn compute_ioctl_access_decision_denied() {
1019 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1020 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1021 let class_id = unvalidated
1022 .0
1023 .classes()
1024 .get_by_name(b"class_one_ioctl")
1025 .expect("look up class_one_ioctl")
1026 .id();
1027 let policy = unvalidated.validate().expect("validate policy");
1028 let source_context: SecurityContext = policy
1029 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1030 .expect("create source security context");
1031 let target_context_matched: SecurityContext = source_context.clone();
1032
1033 let decision_single = policy.compute_xperms_access_decision(
1037 XpermsKind::Ioctl,
1038 &source_context,
1039 &target_context_matched,
1040 class_id,
1041 0xdb,
1042 );
1043
1044 let expected_decision = XpermsAccessDecision {
1045 allow: XpermsBitmap::NONE,
1046 auditallow: XpermsBitmap::NONE,
1047 auditdeny: XpermsBitmap::ALL,
1048 };
1049 assert_eq!(decision_single, expected_decision);
1050 }
1051
1052 #[test]
1053 fn compute_ioctl_access_decision_unmatched() {
1054 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
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 source_context: SecurityContext = policy
1059 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1060 .expect("create source security context");
1061
1062 let target_context_unmatched: SecurityContext = policy
1064 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1065 .expect("create source security context");
1066
1067 for prefix in 0x0..=0xff {
1068 let decision = policy.compute_xperms_access_decision(
1069 XpermsKind::Ioctl,
1070 &source_context,
1071 &target_context_unmatched,
1072 KernelClass::File,
1073 prefix,
1074 );
1075 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1076 }
1077 }
1078
1079 #[test]
1080 fn compute_ioctl_earlier_redundant_prefixful_not_coalesced_into_prefixless() {
1081 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1082 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1083 let class_id = unvalidated
1084 .0
1085 .classes()
1086 .get_by_name(b"class_earlier_redundant_prefixful_not_coalesced_into_prefixless")
1087 .expect("look up class_earlier_redundant_prefixful_not_coalesced_into_prefixless")
1088 .id();
1089 let policy = unvalidated.validate().expect("validate policy");
1090 let source_context: SecurityContext = policy
1091 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1092 .expect("create source security context");
1093 let target_context_matched: SecurityContext = source_context.clone();
1094
1095 let decision = policy.compute_xperms_access_decision(
1100 XpermsKind::Ioctl,
1101 &source_context,
1102 &target_context_matched,
1103 class_id,
1104 0x7f,
1105 );
1106 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1107 let decision = policy.compute_xperms_access_decision(
1108 XpermsKind::Ioctl,
1109 &source_context,
1110 &target_context_matched,
1111 class_id,
1112 0x80,
1113 );
1114 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1115 let decision = policy.compute_xperms_access_decision(
1116 XpermsKind::Ioctl,
1117 &source_context,
1118 &target_context_matched,
1119 class_id,
1120 0x81,
1121 );
1122 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1123 }
1124
1125 #[test]
1126 fn compute_ioctl_later_redundant_prefixful_not_coalesced_into_prefixless() {
1127 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1128 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1129 let class_id = unvalidated
1130 .0
1131 .classes()
1132 .get_by_name(b"class_later_redundant_prefixful_not_coalesced_into_prefixless")
1133 .expect("look up class_later_redundant_prefixful_not_coalesced_into_prefixless")
1134 .id();
1135 let policy = unvalidated.validate().expect("validate policy");
1136 let source_context: SecurityContext = policy
1137 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1138 .expect("create source security context");
1139 let target_context_matched: SecurityContext = source_context.clone();
1140
1141 let decision = policy.compute_xperms_access_decision(
1146 XpermsKind::Ioctl,
1147 &source_context,
1148 &target_context_matched,
1149 class_id,
1150 0x8f,
1151 );
1152 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1153 let decision = policy.compute_xperms_access_decision(
1154 XpermsKind::Ioctl,
1155 &source_context,
1156 &target_context_matched,
1157 class_id,
1158 0x90,
1159 );
1160 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1161 let decision = policy.compute_xperms_access_decision(
1162 XpermsKind::Ioctl,
1163 &source_context,
1164 &target_context_matched,
1165 class_id,
1166 0x91,
1167 );
1168 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1169 }
1170
1171 #[test]
1172 fn compute_ioctl_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless() {
1173 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1174 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1175 let class_id = unvalidated
1176 .0
1177 .classes()
1178 .get_by_name(
1179 b"class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless",
1180 )
1181 .expect(
1182 "look up class_earlier_and_later_redundant_prefixful_not_coalesced_into_prefixless",
1183 )
1184 .id();
1185 let policy = unvalidated.validate().expect("validate policy");
1186 let source_context: SecurityContext = policy
1187 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1188 .expect("create source security context");
1189 let target_context_matched: SecurityContext = source_context.clone();
1190
1191 let decision = policy.compute_xperms_access_decision(
1197 XpermsKind::Ioctl,
1198 &source_context,
1199 &target_context_matched,
1200 class_id,
1201 0x9f,
1202 );
1203 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1204 let decision = policy.compute_xperms_access_decision(
1205 XpermsKind::Ioctl,
1206 &source_context,
1207 &target_context_matched,
1208 class_id,
1209 0xa0,
1210 );
1211 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1212 let decision = policy.compute_xperms_access_decision(
1213 XpermsKind::Ioctl,
1214 &source_context,
1215 &target_context_matched,
1216 class_id,
1217 0xa1,
1218 );
1219 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1220 }
1221
1222 #[test]
1223 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless() {
1224 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1225 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1226 let class_id: ClassId = unvalidated
1227 .0
1228 .classes()
1229 .get_by_name(b"class_prefixfuls_that_coalesce_to_prefixless")
1230 .expect("look up class_prefixfuls_that_coalesce_to_prefixless")
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 = policy.compute_xperms_access_decision(
1244 XpermsKind::Ioctl,
1245 &source_context,
1246 &target_context_matched,
1247 class_id,
1248 0xaf,
1249 );
1250 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1251 let decision = policy.compute_xperms_access_decision(
1252 XpermsKind::Ioctl,
1253 &source_context,
1254 &target_context_matched,
1255 class_id,
1256 0xb0,
1257 );
1258 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1259 let decision = policy.compute_xperms_access_decision(
1260 XpermsKind::Ioctl,
1261 &source_context,
1262 &target_context_matched,
1263 class_id,
1264 0xb1,
1265 );
1266 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1267 }
1268
1269 #[test]
1270 fn compute_ioctl_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless() {
1271 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1272 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1273 let class_id = unvalidated
1274 .0
1275 .classes()
1276 .get_by_name(b"class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless")
1277 .expect("look up class_prefixfuls_that_coalesce_to_prefixless_just_before_prefixless")
1278 .id();
1279 let policy = unvalidated.validate().expect("validate policy");
1280 let source_context: SecurityContext = policy
1281 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1282 .expect("create source security context");
1283 let target_context_matched: SecurityContext = source_context.clone();
1284
1285 let decision = policy.compute_xperms_access_decision(
1292 XpermsKind::Ioctl,
1293 &source_context,
1294 &target_context_matched,
1295 class_id,
1296 0xbf,
1297 );
1298 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1299 let decision = policy.compute_xperms_access_decision(
1300 XpermsKind::Ioctl,
1301 &source_context,
1302 &target_context_matched,
1303 class_id,
1304 0xc0,
1305 );
1306 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1307 let decision = policy.compute_xperms_access_decision(
1308 XpermsKind::Ioctl,
1309 &source_context,
1310 &target_context_matched,
1311 class_id,
1312 0xc1,
1313 );
1314 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1315 let decision = policy.compute_xperms_access_decision(
1316 XpermsKind::Ioctl,
1317 &source_context,
1318 &target_context_matched,
1319 class_id,
1320 0xc2,
1321 );
1322 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1323 }
1324
1325 #[test]
1326 fn compute_ioctl_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless() {
1327 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1328 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1329 let class_id = unvalidated
1330 .0
1331 .classes()
1332 .get_by_name(b"class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless")
1333 .expect("look up class_prefixless_just_before_prefixfuls_that_coalesce_to_prefixless")
1334 .id();
1335 let policy = unvalidated.validate().expect("validate policy");
1336 let source_context: SecurityContext = policy
1337 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1338 .expect("create source security context");
1339 let target_context_matched: SecurityContext = source_context.clone();
1340
1341 let decision = policy.compute_xperms_access_decision(
1348 XpermsKind::Ioctl,
1349 &source_context,
1350 &target_context_matched,
1351 class_id,
1352 0xd5,
1353 );
1354 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1355 let decision = policy.compute_xperms_access_decision(
1356 XpermsKind::Ioctl,
1357 &source_context,
1358 &target_context_matched,
1359 class_id,
1360 0xd6,
1361 );
1362 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1363 let decision = policy.compute_xperms_access_decision(
1364 XpermsKind::Ioctl,
1365 &source_context,
1366 &target_context_matched,
1367 class_id,
1368 0xd7,
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 0xd8,
1377 );
1378 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1379 }
1380
1381 #[test]
1392 fn compute_ioctl_ridiculous_permission_ordering() {
1393 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1394 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1395 let class_id = unvalidated
1396 .0
1397 .classes()
1398 .get_by_name(b"class_ridiculous_permission_ordering")
1399 .expect("look up class_ridiculous_permission_ordering")
1400 .id();
1401 let policy = unvalidated.validate().expect("validate policy");
1402 let source_context: SecurityContext = policy
1403 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1404 .expect("create source security context");
1405 let target_context_matched: SecurityContext = source_context.clone();
1406
1407 let decision = policy.compute_xperms_access_decision(
1412 XpermsKind::Ioctl,
1413 &source_context,
1414 &target_context_matched,
1415 class_id,
1416 0x00,
1417 );
1418 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1419 let decision = policy.compute_xperms_access_decision(
1420 XpermsKind::Ioctl,
1421 &source_context,
1422 &target_context_matched,
1423 class_id,
1424 0x01,
1425 );
1426 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1427 let decision = policy.compute_xperms_access_decision(
1428 XpermsKind::Ioctl,
1429 &source_context,
1430 &target_context_matched,
1431 class_id,
1432 0xbf,
1433 );
1434 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1435 let decision = policy.compute_xperms_access_decision(
1436 XpermsKind::Ioctl,
1437 &source_context,
1438 &target_context_matched,
1439 class_id,
1440 0xc0,
1441 );
1442 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1443 let decision = policy.compute_xperms_access_decision(
1444 XpermsKind::Ioctl,
1445 &source_context,
1446 &target_context_matched,
1447 class_id,
1448 0xce,
1449 );
1450 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1451 let decision = policy.compute_xperms_access_decision(
1452 XpermsKind::Ioctl,
1453 &source_context,
1454 &target_context_matched,
1455 class_id,
1456 0xcf,
1457 );
1458 assert_eq!(
1459 decision,
1460 XpermsAccessDecision {
1461 allow: xperms_bitmap_from_elements((0x0..=0xf2).collect::<Vec<_>>().as_slice()),
1462 auditallow: XpermsBitmap::NONE,
1463 auditdeny: XpermsBitmap::ALL,
1464 }
1465 );
1466 let decision = policy.compute_xperms_access_decision(
1467 XpermsKind::Ioctl,
1468 &source_context,
1469 &target_context_matched,
1470 class_id,
1471 0xd0,
1472 );
1473 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1474 let decision = policy.compute_xperms_access_decision(
1475 XpermsKind::Ioctl,
1476 &source_context,
1477 &target_context_matched,
1478 class_id,
1479 0xe9,
1480 );
1481 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1482 let decision = policy.compute_xperms_access_decision(
1483 XpermsKind::Ioctl,
1484 &source_context,
1485 &target_context_matched,
1486 class_id,
1487 0xf0,
1488 );
1489 assert_eq!(
1490 decision,
1491 XpermsAccessDecision {
1492 allow: xperms_bitmap_from_elements(&[0x01]),
1493 auditallow: XpermsBitmap::NONE,
1494 auditdeny: XpermsBitmap::ALL,
1495 }
1496 );
1497 let decision = policy.compute_xperms_access_decision(
1498 XpermsKind::Ioctl,
1499 &source_context,
1500 &target_context_matched,
1501 class_id,
1502 0xf1,
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 0xfc,
1511 );
1512 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1513 let decision = policy.compute_xperms_access_decision(
1514 XpermsKind::Ioctl,
1515 &source_context,
1516 &target_context_matched,
1517 class_id,
1518 0xfd,
1519 );
1520 assert_eq!(
1521 decision,
1522 XpermsAccessDecision {
1523 allow: xperms_bitmap_from_elements((0xfa..=0xfd).collect::<Vec<_>>().as_slice()),
1524 auditallow: XpermsBitmap::NONE,
1525 auditdeny: XpermsBitmap::ALL,
1526 }
1527 );
1528 let decision = policy.compute_xperms_access_decision(
1529 XpermsKind::Ioctl,
1530 &source_context,
1531 &target_context_matched,
1532 class_id,
1533 0xfe,
1534 );
1535 assert_eq!(decision, XpermsAccessDecision::DENY_ALL);
1536 }
1537
1538 #[test]
1539 fn compute_nlmsg_access_decision_explicitly_allowed() {
1540 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1541 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1542 let policy = policy.validate().expect("validate policy");
1543
1544 let source_context: SecurityContext = policy
1545 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1546 .expect("create source security context");
1547 let target_context_matched: SecurityContext = source_context.clone();
1548
1549 let decision_single = policy.compute_xperms_access_decision(
1567 XpermsKind::Nlmsg,
1568 &source_context,
1569 &target_context_matched,
1570 KernelClass::NetlinkRouteSocket,
1571 0xab,
1572 );
1573
1574 let mut expected_auditdeny =
1575 xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1576 expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1577
1578 let expected_decision_single = XpermsAccessDecision {
1579 allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1580 auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1581 auditdeny: expected_auditdeny,
1582 };
1583 assert_eq!(decision_single, expected_decision_single);
1584
1585 let decision_range = policy.compute_xperms_access_decision(
1586 XpermsKind::Nlmsg,
1587 &source_context,
1588 &target_context_matched,
1589 KernelClass::NetlinkRouteSocket,
1590 0x10,
1591 );
1592 let expected_decision_range = XpermsAccessDecision {
1593 allow: XpermsBitmap::ALL,
1594 auditallow: XpermsBitmap::ALL,
1595 auditdeny: XpermsBitmap::NONE,
1596 };
1597 assert_eq!(decision_range, expected_decision_range);
1598 }
1599
1600 #[test]
1601 fn compute_nlmsg_access_decision_unmatched() {
1602 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1603 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1604 let policy = policy.validate().expect("validate policy");
1605
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
1610 let target_context_unmatched: SecurityContext = policy
1612 .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1613 .expect("create source security context");
1614
1615 for prefix in 0x0..=0xff {
1616 let decision = policy.compute_xperms_access_decision(
1617 XpermsKind::Nlmsg,
1618 &source_context,
1619 &target_context_unmatched,
1620 KernelClass::NetlinkRouteSocket,
1621 prefix,
1622 );
1623 assert_eq!(decision, XpermsAccessDecision::ALLOW_ALL);
1624 }
1625 }
1626
1627 #[test]
1628 fn compute_ioctl_grant_does_not_cause_nlmsg_deny() {
1629 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1630 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1631 let class_id = unvalidated
1632 .0
1633 .classes()
1634 .get_by_name(b"class_ioctl_grant_does_not_cause_nlmsg_deny")
1635 .expect("look up class_ioctl_grant_does_not_cause_nlmsg_deny")
1636 .id();
1637 let policy = unvalidated.validate().expect("validate policy");
1638 let source_context: SecurityContext = policy
1639 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1640 .expect("create source security context");
1641 let target_context_matched: SecurityContext = source_context.clone();
1642
1643 let ioctl_decision = policy.compute_xperms_access_decision(
1647 XpermsKind::Ioctl,
1648 &source_context,
1649 &target_context_matched,
1650 class_id,
1651 0x00,
1652 );
1653 assert_eq!(
1654 ioctl_decision,
1655 XpermsAccessDecision {
1656 allow: xperms_bitmap_from_elements(&[0x0002]),
1657 auditallow: XpermsBitmap::NONE,
1658 auditdeny: XpermsBitmap::ALL,
1659 }
1660 );
1661 let nlmsg_decision = policy.compute_xperms_access_decision(
1662 XpermsKind::Nlmsg,
1663 &source_context,
1664 &target_context_matched,
1665 class_id,
1666 0x00,
1667 );
1668 assert_eq!(nlmsg_decision, XpermsAccessDecision::ALLOW_ALL);
1669 }
1670
1671 #[test]
1672 fn compute_nlmsg_grant_does_not_cause_ioctl_deny() {
1673 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1674 let unvalidated = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1675 let class_id = unvalidated
1676 .0
1677 .classes()
1678 .get_by_name(b"class_nlmsg_grant_does_not_cause_ioctl_deny")
1679 .expect("look up class_nlmsg_grant_does_not_cause_ioctl_deny")
1680 .id();
1681 let policy = unvalidated.validate().expect("validate policy");
1682 let source_context: SecurityContext = policy
1683 .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1684 .expect("create source security context");
1685 let target_context_matched: SecurityContext = source_context.clone();
1686
1687 let nlmsg_decision = policy.compute_xperms_access_decision(
1691 XpermsKind::Nlmsg,
1692 &source_context,
1693 &target_context_matched,
1694 class_id,
1695 0x00,
1696 );
1697 assert_eq!(
1698 nlmsg_decision,
1699 XpermsAccessDecision {
1700 allow: xperms_bitmap_from_elements(&[0x0003]),
1701 auditallow: XpermsBitmap::NONE,
1702 auditdeny: XpermsBitmap::ALL,
1703 }
1704 );
1705 let ioctl_decision = policy.compute_xperms_access_decision(
1706 XpermsKind::Ioctl,
1707 &source_context,
1708 &target_context_matched,
1709 class_id,
1710 0x00,
1711 );
1712 assert_eq!(ioctl_decision, XpermsAccessDecision::ALLOW_ALL);
1713 }
1714
1715 #[test]
1716 fn compute_create_context_minimal() {
1717 let policy_bytes =
1718 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy");
1719 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1720 let policy = policy.validate().expect("validate policy");
1721 let source = policy
1722 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1723 .expect("valid source security context");
1724 let target = policy
1725 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1726 .expect("valid target security context");
1727
1728 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1729 let expected: SecurityContext = policy
1730 .parse_security_context(b"source_u:object_r:target_t:s0:c0".into())
1731 .expect("valid expected security context");
1732
1733 assert_eq!(expected, actual);
1734 }
1735
1736 #[test]
1737 fn new_security_context_minimal() {
1738 let policy_bytes =
1739 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy");
1740 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1741 let policy = policy.validate().expect("validate policy");
1742 let source = policy
1743 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1744 .expect("valid source security context");
1745 let target = policy
1746 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1747 .expect("valid target security context");
1748
1749 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1750
1751 assert_eq!(source, actual);
1752 }
1753
1754 #[test]
1755 fn compute_create_context_class_defaults() {
1756 let policy_bytes =
1757 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy");
1758 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1759 let policy = policy.validate().expect("validate policy");
1760 let source = policy
1761 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1762 .expect("valid source security context");
1763 let target = policy
1764 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1765 .expect("valid target security context");
1766
1767 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1768 let expected: SecurityContext = policy
1769 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1770 .expect("valid expected security context");
1771
1772 assert_eq!(expected, actual);
1773 }
1774
1775 #[test]
1776 fn new_security_context_class_defaults() {
1777 let policy_bytes =
1778 include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy");
1779 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1780 let policy = policy.validate().expect("validate policy");
1781 let source = policy
1782 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1783 .expect("valid source security context");
1784 let target = policy
1785 .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1786 .expect("valid target security context");
1787
1788 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1789 let expected: SecurityContext = policy
1790 .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1791 .expect("valid expected security context");
1792
1793 assert_eq!(expected, actual);
1794 }
1795
1796 #[test]
1797 fn compute_create_context_role_transition() {
1798 let policy_bytes =
1799 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy");
1800 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1801 let policy = policy.validate().expect("validate policy");
1802 let source = policy
1803 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1804 .expect("valid source security context");
1805 let target = policy
1806 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1807 .expect("valid target security context");
1808
1809 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1810 let expected: SecurityContext = policy
1811 .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
1812 .expect("valid expected security context");
1813
1814 assert_eq!(expected, actual);
1815 }
1816
1817 #[test]
1818 fn new_security_context_role_transition() {
1819 let policy_bytes =
1820 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy");
1821 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1822 let policy = policy.validate().expect("validate policy");
1823 let source = policy
1824 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1825 .expect("valid source security context");
1826 let target = policy
1827 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1828 .expect("valid target security context");
1829
1830 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1831 let expected: SecurityContext = policy
1832 .parse_security_context(b"source_u:transition_r:source_t:s0:c0-s2:c0.c1".into())
1833 .expect("valid expected security context");
1834
1835 assert_eq!(expected, actual);
1836 }
1837
1838 #[test]
1839 #[ignore]
1841 fn compute_create_context_role_transition_not_allowed() {
1842 let policy_bytes = include_bytes!(
1843 "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy"
1844 );
1845 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1846 let policy = policy.validate().expect("validate policy");
1847 let source = policy
1848 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1849 .expect("valid source security context");
1850 let target = policy
1851 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1852 .expect("valid target security context");
1853
1854 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1855
1856 assert!(policy.validate_security_context(&actual).is_err());
1858 }
1859
1860 #[test]
1861 fn compute_create_context_type_transition() {
1862 let policy_bytes =
1863 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy");
1864 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1865 let policy = policy.validate().expect("validate policy");
1866 let source = policy
1867 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1868 .expect("valid source security context");
1869 let target = policy
1870 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1871 .expect("valid target security context");
1872
1873 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1874 let expected: SecurityContext = policy
1875 .parse_security_context(b"source_u:object_r:transition_t:s0:c0".into())
1876 .expect("valid expected security context");
1877
1878 assert_eq!(expected, actual);
1879 }
1880
1881 #[test]
1882 fn new_security_context_type_transition() {
1883 let policy_bytes =
1884 include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy");
1885 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1886 let policy = policy.validate().expect("validate policy");
1887 let source = policy
1888 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1889 .expect("valid source security context");
1890 let target = policy
1891 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1892 .expect("valid target security context");
1893
1894 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1895 let expected: SecurityContext = policy
1896 .parse_security_context(b"source_u:source_r:transition_t:s0:c0-s2:c0.c1".into())
1897 .expect("valid expected security context");
1898
1899 assert_eq!(expected, actual);
1900 }
1901
1902 #[test]
1903 fn compute_create_context_range_transition() {
1904 let policy_bytes =
1905 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy");
1906 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1907 let policy = policy.validate().expect("validate policy");
1908 let source = policy
1909 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1910 .expect("valid source security context");
1911 let target = policy
1912 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1913 .expect("valid target security context");
1914
1915 let actual = policy.compute_create_context(&source, &target, FileClass::File);
1916 let expected: SecurityContext = policy
1917 .parse_security_context(b"source_u:object_r:target_t:s1:c1-s2:c1.c2".into())
1918 .expect("valid expected security context");
1919
1920 assert_eq!(expected, actual);
1921 }
1922
1923 #[test]
1924 fn new_security_context_range_transition() {
1925 let policy_bytes =
1926 include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy");
1927 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1928 let policy = policy.validate().expect("validate policy");
1929 let source = policy
1930 .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1931 .expect("valid source security context");
1932 let target = policy
1933 .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1934 .expect("valid target security context");
1935
1936 let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1937 let expected: SecurityContext = policy
1938 .parse_security_context(b"source_u:source_r:source_t:s1:c1-s2:c1.c2".into())
1939 .expect("valid expected security context");
1940
1941 assert_eq!(expected, actual);
1942 }
1943
1944 #[test]
1945 fn access_vector_formats() {
1946 assert_eq!(format!("{:x}", AccessVector::NONE), "0");
1947 assert_eq!(format!("{:x}", AccessVector::ALL), "ffffffff");
1948 assert_eq!(format!("{:?}", AccessVector::NONE), "AccessVector(00000000)");
1949 assert_eq!(format!("{:?}", AccessVector::ALL), "AccessVector(ffffffff)");
1950 }
1951
1952 #[test]
1953 fn policy_genfscon_root_path() {
1954 let policy_bytes =
1955 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy");
1956 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1957 let policy = policy.validate().expect("validate selinux policy");
1958
1959 {
1960 let context = policy.genfscon_label_for_fs_and_path(
1961 "fs_with_path_rules".into(),
1962 "/".into(),
1963 None,
1964 );
1965 assert_eq!(
1966 policy.serialize_security_context(&context.unwrap()),
1967 b"system_u:object_r:fs_with_path_rules_t:s0"
1968 )
1969 }
1970 {
1971 let context = policy.genfscon_label_for_fs_and_path(
1972 "fs_2_with_path_rules".into(),
1973 "/".into(),
1974 None,
1975 );
1976 assert_eq!(
1977 policy.serialize_security_context(&context.unwrap()),
1978 b"system_u:object_r:fs_2_with_path_rules_t:s0"
1979 )
1980 }
1981 }
1982
1983 #[test]
1984 fn policy_genfscon_subpaths() {
1985 let policy_bytes =
1986 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy");
1987 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1988 let policy = policy.validate().expect("validate selinux policy");
1989
1990 let path_label_expectations = [
1991 ("/a1/", "system_u:object_r:fs_with_path_rules_a1_t:s0"),
1995 ("/a1/b", "system_u:object_r:fs_with_path_rules_a1_t:s0"),
1996 ("/a1/b/c", "system_u:object_r:fs_with_path_rules_a1_b_c_t:s0"),
1997 ("/a2/", "system_u:object_r:fs_with_path_rules_t:s0"),
2000 ("/a2/b/c/d", "system_u:object_r:fs_with_path_rules_a2_b_t:s0"),
2001 ("/a3/b/c/d", "system_u:object_r:fs_with_path_rules_a3_t:s0"),
2004 ];
2005 for (path, expected_label) in path_label_expectations {
2006 let context = policy.genfscon_label_for_fs_and_path(
2007 "fs_with_path_rules".into(),
2008 path.into(),
2009 None,
2010 );
2011 assert_eq!(
2012 policy.serialize_security_context(&context.unwrap()),
2013 expected_label.as_bytes()
2014 )
2015 }
2016 }
2017
2018 #[test]
2019 fn policy_genfscon_mixed_order() {
2020 let policy_bytes =
2021 include_bytes!("../../testdata/composite_policies/compiled/genfscon_policy");
2022 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2023 let policy = policy.validate().expect("validate selinux policy");
2024
2025 let path_label_expectations = [
2026 ("/", "system_u:object_r:fs_mixed_order_t:s0"),
2027 ("/a", "system_u:object_r:fs_mixed_order_a_t:s0"),
2028 ("/a/a", "system_u:object_r:fs_mixed_order_a_a_t:s0"),
2029 ("/a/b", "system_u:object_r:fs_mixed_order_a_b_t:s0"),
2030 ("/a/b/c", "system_u:object_r:fs_mixed_order_a_b_t:s0"),
2031 ];
2032 for (path, expected_label) in path_label_expectations {
2033 let context =
2034 policy.genfscon_label_for_fs_and_path("fs_mixed_order".into(), path.into(), None);
2035 assert_eq!(
2036 policy.serialize_security_context(&context.unwrap()),
2037 expected_label.as_bytes()
2038 );
2039 }
2040 }
2041}