1use crate::policy::view::Hashable;
6
7use super::error::ValidateError;
8use super::extensible_bitmap::ExtensibleBitmap;
9use super::parser::{PolicyCursor, PolicyData, PolicyOffset};
10use super::view::{ArrayView, HasMetadata, Walk};
11use super::{
12 AccessVector, Array, ClassId, Counted, MlsLevel, MlsRange, Parse, PolicyValidationContext,
13 RoleId, TypeId, UserId, Validate, ValidateArray, array_type, array_type_validate_deref_both,
14};
15
16use crate::new_policy::traits::PolicyId;
17use anyhow::Context as _;
18use std::hash::{Hash, Hasher};
19use std::ops::Shl;
20use zerocopy::{FromBytes, Immutable, KnownLayout, Unaligned, little_endian as le};
21
22pub(super) const MIN_POLICY_VERSION_FOR_INFINITIBAND_PARTITION_KEY: u32 = 31;
23
24pub(super) const ACCESS_VECTOR_RULE_DATA_IS_TYPE_ID_MASK: u16 = 0x070;
27pub(super) const ACCESS_VECTOR_RULE_DATA_IS_XPERM_MASK: u16 = 0x0700;
31
32pub(super) const ACCESS_VECTOR_RULE_TYPE_ALLOW: u16 = 0x1;
42pub(super) const ACCESS_VECTOR_RULE_TYPE_AUDITALLOW: u16 = 0x2;
46pub(super) const ACCESS_VECTOR_RULE_TYPE_DONTAUDIT: u16 = 0x4;
50pub(super) const ACCESS_VECTOR_RULE_TYPE_TYPE_TRANSITION: u16 = 0x10;
54#[allow(dead_code)]
58pub(super) const ACCESS_VECTOR_RULE_TYPE_TYPE_MEMBER: u16 = 0x20;
59#[allow(dead_code)]
63pub(super) const ACCESS_VECTOR_RULE_TYPE_TYPE_CHANGE: u16 = 0x40;
64pub(super) const ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM: u16 = 0x100;
69pub(super) const ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM: u16 = 0x200;
74pub(super) const ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM: u16 = 0x400;
79
80pub(super) const XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES: u8 = 1;
86pub(super) const XPERMS_TYPE_IOCTL_PREFIXES: u8 = 2;
90pub(super) const XPERMS_TYPE_NLMSG: u8 = 3;
96
97#[allow(type_alias_bounds)]
98pub(super) type SimpleArray<T> = Array<le::U32, T>;
99
100impl<T: Validate> Validate for SimpleArray<T> {
101 type Error = <T as Validate>::Error;
102 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
106 self.data.validate(context)
107 }
108}
109
110pub(super) type SimpleArrayView<T> = ArrayView<le::U32, T>;
111
112impl<T: Validate + Parse + Walk> Validate for SimpleArrayView<T> {
113 type Error = anyhow::Error;
114
115 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
118 for item in self.data().iter(&context.data) {
119 item.validate(context)?;
120 }
121 Ok(())
122 }
123}
124
125impl Counted for le::U32 {
126 fn count(&self) -> u32 {
127 self.get()
128 }
129}
130
131impl Validate for ConditionalNode {
132 type Error = anyhow::Error;
133
134 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
136 Ok(())
137 }
138}
139
140array_type!(ConditionalNodeItems, ConditionalNodeMetadata, ConditionalNodeDatum);
141
142array_type_validate_deref_both!(ConditionalNodeItems);
143
144impl ValidateArray<ConditionalNodeMetadata, ConditionalNodeDatum> for ConditionalNodeItems {
145 type Error = anyhow::Error;
146
147 fn validate_array(
150 _context: &PolicyValidationContext,
151 _metadata: &ConditionalNodeMetadata,
152 _items: &[ConditionalNodeDatum],
153 ) -> Result<(), Self::Error> {
154 Ok(())
155 }
156}
157
158#[derive(Debug, PartialEq)]
159pub(super) struct ConditionalNode {
160 items: ConditionalNodeItems,
161 true_list: SimpleArray<AccessVectorRule>,
162 false_list: SimpleArray<AccessVectorRule>,
163}
164
165impl Parse for ConditionalNode
166where
167 ConditionalNodeItems: Parse,
168 SimpleArray<AccessVectorRule>: Parse,
169{
170 type Error = anyhow::Error;
171
172 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
173 let tail = bytes;
174
175 let (items, tail) = ConditionalNodeItems::parse(tail)
176 .map_err(Into::<anyhow::Error>::into)
177 .context("parsing conditional node items")?;
178
179 let (true_list, tail) = SimpleArray::<AccessVectorRule>::parse(tail)
180 .map_err(Into::<anyhow::Error>::into)
181 .context("parsing conditional node true list")?;
182
183 let (false_list, tail) = SimpleArray::<AccessVectorRule>::parse(tail)
184 .map_err(Into::<anyhow::Error>::into)
185 .context("parsing conditional node false list")?;
186
187 Ok((Self { items, true_list, false_list }, tail))
188 }
189}
190
191#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
192#[repr(C, packed)]
193pub(super) struct ConditionalNodeMetadata {
194 state: le::U32,
195 count: le::U32,
196}
197
198impl Counted for ConditionalNodeMetadata {
199 fn count(&self) -> u32 {
200 self.count.get()
201 }
202}
203
204impl Validate for ConditionalNodeMetadata {
205 type Error = anyhow::Error;
206
207 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
209 Ok(())
210 }
211}
212
213#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
214#[repr(C, packed)]
215pub(super) struct ConditionalNodeDatum {
216 node_type: le::U32,
217 boolean: le::U32,
218}
219
220impl Validate for ConditionalNodeDatum {
221 type Error = anyhow::Error;
222
223 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
225 Ok(())
226 }
227}
228
229#[derive(Debug, PartialEq)]
238pub(super) struct AccessVectorRule {
239 metadata: AccessVectorRuleMetadata,
240 permission_data: PermissionData,
241}
242
243impl AccessVectorRule {
244 pub fn access_vector(&self) -> Option<AccessVector> {
250 match &self.permission_data {
251 PermissionData::AccessVector(access_vector_raw) => {
252 Some(AccessVector::from(access_vector_raw.get()))
253 }
254 _ => None,
255 }
256 }
257
258 pub fn new_type(&self) -> Option<TypeId> {
264 match &self.permission_data {
265 PermissionData::NewType(new_type) => {
266 Some(TypeId::from_u32(new_type.get().into()).unwrap())
267 }
268 _ => None,
269 }
270 }
271
272 pub fn extended_permissions(&self) -> Option<&ExtendedPermissions> {
278 match &self.permission_data {
279 PermissionData::ExtendedPermissions(xperms) => Some(xperms),
280 _ => None,
281 }
282 }
283}
284
285impl Walk for AccessVectorRule {
286 fn walk(policy_data: &PolicyData, offset: PolicyOffset) -> PolicyOffset {
287 const METADATA_SIZE: u32 = std::mem::size_of::<AccessVectorRuleMetadata>() as u32;
288 let bytes = &policy_data[offset as usize..(offset + METADATA_SIZE) as usize];
289 let metadata = AccessVectorRuleMetadata::read_from_bytes(bytes).unwrap();
290 let permission_data_size = metadata.permission_data_size() as u32;
291 offset + METADATA_SIZE + permission_data_size
292 }
293}
294
295impl HasMetadata for AccessVectorRule {
296 type Metadata = AccessVectorRuleMetadata;
297}
298
299impl Parse for AccessVectorRule {
300 type Error = anyhow::Error;
301
302 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
303 let tail = bytes;
304
305 let (metadata, tail) = PolicyCursor::parse::<AccessVectorRuleMetadata>(tail)?;
306 let access_vector_rule_type = metadata.access_vector_rule_type;
307 let (permission_data, tail) =
308 if (access_vector_rule_type & ACCESS_VECTOR_RULE_DATA_IS_XPERM_MASK) != 0 {
309 let (xperms, tail) = ExtendedPermissions::parse(tail)
310 .map_err(Into::<anyhow::Error>::into)
311 .context("parsing extended permissions")?;
312 (PermissionData::ExtendedPermissions(xperms), tail)
313 } else if (access_vector_rule_type & ACCESS_VECTOR_RULE_DATA_IS_TYPE_ID_MASK) != 0 {
314 let (new_type, tail) = PolicyCursor::parse::<le::U32>(tail)?;
315 (PermissionData::NewType(new_type), tail)
316 } else {
317 let (access_vector, tail) = PolicyCursor::parse::<le::U32>(tail)?;
318 (PermissionData::AccessVector(access_vector), tail)
319 };
320 Ok((Self { metadata, permission_data }, tail))
321 }
322}
323
324impl Validate for AccessVectorRule {
325 type Error = anyhow::Error;
326
327 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
328 if self.metadata.class.get() == 0 {
329 return Err(ValidateError::NonOptionalIdIsZero.into());
330 }
331 if let PermissionData::ExtendedPermissions(xperms) = &self.permission_data {
332 let xperms_type = xperms.xperms_type;
333 if !(xperms_type == XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES
334 || xperms_type == XPERMS_TYPE_IOCTL_PREFIXES
335 || xperms_type == XPERMS_TYPE_NLMSG)
336 {
337 return Err(
338 ValidateError::InvalidExtendedPermissionsType { type_: xperms_type }.into()
339 );
340 }
341 }
342 Ok(())
343 }
344}
345
346#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, Eq, PartialEq, Unaligned, Hash)]
347#[repr(C, packed)]
348pub(super) struct AccessVectorRuleMetadata {
349 source_type: le::U16,
350 target_type: le::U16,
351 class: le::U16,
352 access_vector_rule_type: le::U16,
353}
354
355impl AccessVectorRuleMetadata {
356 pub fn for_query(source: TypeId, target: TypeId, class: ClassId, rule_type: u16) -> Self {
357 let source_type = le::U16::new(source.as_u32() as u16);
358 let target_type = le::U16::new(target.as_u32() as u16);
359 let class = le::U16::new(u32::from(class) as u16);
360 let access_vector_rule_type = le::U16::new(rule_type);
361 Self { source_type, target_type, class, access_vector_rule_type }
362 }
363
364 fn permission_data_size(&self) -> usize {
365 if (self.access_vector_rule_type & ACCESS_VECTOR_RULE_DATA_IS_XPERM_MASK) != 0 {
366 std::mem::size_of::<ExtendedPermissions>()
367 } else if (self.access_vector_rule_type & ACCESS_VECTOR_RULE_DATA_IS_TYPE_ID_MASK) != 0 {
368 std::mem::size_of::<le::U32>()
369 } else {
370 std::mem::size_of::<le::U32>()
371 }
372 }
373}
374
375#[derive(Debug, PartialEq)]
376pub(super) enum PermissionData {
377 AccessVector(le::U32),
378 NewType(le::U32),
379 ExtendedPermissions(ExtendedPermissions),
380}
381
382#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
383#[repr(C, packed)]
384pub(super) struct ExtendedPermissions {
385 pub(super) xperms_type: u8,
386 pub(super) xperms_optional_prefix: u8,
390 pub(super) xperms_bitmap: XpermsBitmap,
391}
392
393impl ExtendedPermissions {
394 #[cfg(test)]
395 fn count(&self) -> u64 {
396 let count = self
397 .xperms_bitmap
398 .0
399 .iter()
400 .fold(0, |count, block| (count as u64) + (block.get().count_ones() as u64));
401 match self.xperms_type {
402 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES | XPERMS_TYPE_NLMSG => count,
403 XPERMS_TYPE_IOCTL_PREFIXES => count * 0x100,
404 _ => unreachable!("invalid xperms_type in validated ExtendedPermissions"),
405 }
406 }
407
408 #[cfg(test)]
409 fn contains(&self, xperm: u16) -> bool {
410 let [postfix, prefix] = xperm.to_le_bytes();
411 if (self.xperms_type == XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES
412 || self.xperms_type == XPERMS_TYPE_NLMSG)
413 && self.xperms_optional_prefix != prefix
414 {
415 return false;
416 }
417 let value = match self.xperms_type {
418 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES | XPERMS_TYPE_NLMSG => postfix,
419 XPERMS_TYPE_IOCTL_PREFIXES => prefix,
420 _ => unreachable!("invalid xperms_type in validated ExtendedPermissions"),
421 };
422 self.xperms_bitmap.contains(value)
423 }
424}
425
426#[derive(Clone, Copy, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
428#[repr(C, packed)]
429pub struct XpermsBitmap([le::U32; 8]);
430
431impl XpermsBitmap {
432 const BITMAP_BLOCKS: usize = 8;
433 pub const ALL: Self = Self([le::U32::MAX_VALUE; Self::BITMAP_BLOCKS]);
434 pub const NONE: Self = Self([le::U32::ZERO; Self::BITMAP_BLOCKS]);
435
436 #[cfg(test)]
437 pub fn new(elements: [le::U32; 8]) -> Self {
438 Self(elements)
439 }
440
441 pub fn contains(&self, value: u8) -> bool {
442 let block_index = (value as usize) / 32;
443 let bit_index = ((value as usize) % 32) as u32;
444 self.0[block_index] & le::U32::new(1).shl(bit_index) != 0
445 }
446}
447
448impl From<[u64; 4]> for XpermsBitmap {
450 fn from(v: [u64; 4]) -> Self {
451 let mut elements = [le::U32::ZERO; 8];
452 for (i, &val) in v.iter().enumerate() {
453 elements[i * 2] = le::U32::new(val as u32);
454 elements[i * 2 + 1] = le::U32::new((val >> 32) as u32);
455 }
456 XpermsBitmap(elements)
457 }
458}
459
460impl From<XpermsBitmap> for [u64; 4] {
461 fn from(v: XpermsBitmap) -> Self {
462 let mut result = [0u64; 4];
463 for i in 0..4 {
464 let low = v.0[i * 2].get() as u64;
465 let high = v.0[i * 2 + 1].get() as u64;
466 result[i] = low | (high << 32);
467 }
468 result
469 }
470}
471
472impl std::ops::BitAnd for XpermsBitmap {
473 type Output = Self;
474 fn bitand(self, rhs: Self) -> Self {
475 let mut result = self;
476 (0..Self::BITMAP_BLOCKS).for_each(|i| result.0[i] &= rhs.0[i]);
477 result
478 }
479}
480
481impl std::ops::BitOr for XpermsBitmap {
482 type Output = Self;
483 fn bitor(self, rhs: Self) -> Self {
484 let mut result = self;
485 (0..Self::BITMAP_BLOCKS).for_each(|i| result.0[i] |= rhs.0[i]);
486 result
487 }
488}
489
490impl std::ops::Not for XpermsBitmap {
491 type Output = Self;
492 fn not(self) -> Self {
493 let mut result = self;
494 (0..Self::BITMAP_BLOCKS).for_each(|i| result.0[i] = !result.0[i]);
495 result
496 }
497}
498
499impl std::ops::BitOrAssign<&Self> for XpermsBitmap {
500 fn bitor_assign(&mut self, rhs: &Self) {
501 (0..Self::BITMAP_BLOCKS).for_each(|i| self.0[i] |= rhs.0[i])
502 }
503}
504
505impl std::ops::SubAssign<&Self> for XpermsBitmap {
506 fn sub_assign(&mut self, rhs: &Self) {
507 (0..Self::BITMAP_BLOCKS).for_each(|i| self.0[i] = self.0[i] ^ (self.0[i] & rhs.0[i]))
508 }
509}
510
511array_type!(RoleTransitions, le::U32, RoleTransition);
512
513array_type_validate_deref_both!(RoleTransitions);
514
515impl ValidateArray<le::U32, RoleTransition> for RoleTransitions {
516 type Error = anyhow::Error;
517
518 fn validate_array(
520 _context: &PolicyValidationContext,
521 _metadata: &le::U32,
522 _items: &[RoleTransition],
523 ) -> Result<(), Self::Error> {
524 Ok(())
525 }
526}
527
528#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
529#[repr(C, packed)]
530pub(super) struct RoleTransition {
531 role: le::U32,
532 role_type: le::U32,
533 new_role: le::U32,
534 tclass: le::U32,
535}
536
537impl RoleTransition {
538 pub(super) fn current_role(&self) -> RoleId {
539 RoleId::from_u32(self.role.get()).unwrap()
540 }
541
542 pub(super) fn type_(&self) -> TypeId {
543 TypeId::from_u32(self.role_type.get()).unwrap()
544 }
545
546 pub(super) fn class(&self) -> ClassId {
547 ClassId::try_from(self.tclass.get()).unwrap()
548 }
549
550 pub(super) fn new_role(&self) -> RoleId {
551 RoleId::from_u32(self.new_role.get()).unwrap()
552 }
553}
554
555impl Validate for RoleTransition {
556 type Error = anyhow::Error;
557
558 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
559 RoleId::from_u32(self.role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
560 TypeId::from_u32(self.role_type.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
561 ClassId::from_u32(self.tclass.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
562 RoleId::from_u32(self.new_role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
563 Ok(())
564 }
565}
566
567array_type!(RoleAllows, le::U32, RoleAllow);
568
569array_type_validate_deref_both!(RoleAllows);
570
571impl ValidateArray<le::U32, RoleAllow> for RoleAllows {
572 type Error = anyhow::Error;
573
574 fn validate_array(
576 _context: &PolicyValidationContext,
577 _metadata: &le::U32,
578 _items: &[RoleAllow],
579 ) -> Result<(), Self::Error> {
580 Ok(())
581 }
582}
583
584#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
585#[repr(C, packed)]
586pub(super) struct RoleAllow {
587 role: le::U32,
588 new_role: le::U32,
589}
590
591impl RoleAllow {
592 pub(super) fn source_role(&self) -> RoleId {
593 RoleId::from_u32(self.role.get()).unwrap()
594 }
595
596 pub(super) fn new_role(&self) -> RoleId {
597 RoleId::from_u32(self.new_role.get()).unwrap()
598 }
599}
600
601impl Validate for RoleAllow {
602 type Error = anyhow::Error;
603
604 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
605 RoleId::from_u32(self.role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
606 RoleId::from_u32(self.new_role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
607 Ok(())
608 }
609}
610
611#[derive(Debug, PartialEq)]
612pub(super) enum FilenameTransitionList {
613 PolicyVersionGeq33(SimpleArray<FilenameTransition>),
614 PolicyVersionLeq32(SimpleArray<DeprecatedFilenameTransition>),
615}
616
617impl Validate for FilenameTransitionList {
618 type Error = anyhow::Error;
619
620 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
621 match self {
622 Self::PolicyVersionLeq32(list) => {
623 list.validate(context).map_err(Into::<anyhow::Error>::into)
624 }
625 Self::PolicyVersionGeq33(list) => {
626 list.validate(context).map_err(Into::<anyhow::Error>::into)
627 }
628 }
629 }
630}
631
632impl Validate for FilenameTransition {
633 type Error = anyhow::Error;
634 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
635 Ok(())
636 }
637}
638
639#[derive(Debug, PartialEq)]
640pub(super) struct FilenameTransition {
641 filename: SimpleArray<u8>,
642 transition_type: le::U32,
643 transition_class: le::U32,
644 items: SimpleArray<FilenameTransitionItem>,
645}
646
647impl FilenameTransition {
648 pub(super) fn name_bytes(&self) -> &[u8] {
649 &self.filename.data
650 }
651
652 pub(super) fn target_type(&self) -> TypeId {
653 TypeId::from_u32(self.transition_type.get()).unwrap()
654 }
655
656 pub(super) fn target_class(&self) -> ClassId {
657 ClassId::try_from(self.transition_class.get()).unwrap()
658 }
659
660 pub(super) fn outputs(&self) -> &[FilenameTransitionItem] {
661 &self.items.data
662 }
663}
664
665impl Parse for FilenameTransition
666where
667 SimpleArray<u8>: Parse,
668 SimpleArray<FilenameTransitionItem>: Parse,
669{
670 type Error = anyhow::Error;
671
672 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
673 let tail = bytes;
674
675 let (filename, tail) = SimpleArray::<u8>::parse(tail)
676 .map_err(Into::<anyhow::Error>::into)
677 .context("parsing filename for filename transition")?;
678
679 let (transition_type, tail) = PolicyCursor::parse::<le::U32>(tail)?;
680
681 let (transition_class, tail) = PolicyCursor::parse::<le::U32>(tail)?;
682
683 let (items, tail) = SimpleArray::<FilenameTransitionItem>::parse(tail)
684 .map_err(Into::<anyhow::Error>::into)
685 .context("parsing items for filename transition")?;
686
687 Ok((Self { filename, transition_type, transition_class, items }, tail))
688 }
689}
690
691#[derive(Debug, PartialEq)]
692pub(super) struct FilenameTransitionItem {
693 stypes: ExtensibleBitmap,
694 out_type: le::U32,
695}
696
697impl FilenameTransitionItem {
698 pub(super) fn has_source_type(&self, source_type: TypeId) -> bool {
699 self.stypes.is_set(source_type.as_u32() - 1)
700 }
701
702 pub(super) fn out_type(&self) -> TypeId {
703 TypeId::from_u32(self.out_type.get()).unwrap()
704 }
705}
706
707impl Parse for FilenameTransitionItem
708where
709 ExtensibleBitmap: Parse,
710{
711 type Error = anyhow::Error;
712
713 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
714 let tail = bytes;
715
716 let (stypes, tail) = ExtensibleBitmap::parse(tail)
717 .map_err(Into::<anyhow::Error>::into)
718 .context("parsing stypes extensible bitmap for file transition")?;
719
720 let (out_type, tail) = PolicyCursor::parse::<le::U32>(tail)?;
721
722 Ok((Self { stypes, out_type }, tail))
723 }
724}
725
726impl Validate for DeprecatedFilenameTransition {
727 type Error = anyhow::Error;
728 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
729 Ok(())
730 }
731}
732
733#[derive(Debug, PartialEq)]
734pub(super) struct DeprecatedFilenameTransition {
735 filename: SimpleArray<u8>,
736 metadata: DeprecatedFilenameTransitionMetadata,
737}
738
739impl DeprecatedFilenameTransition {
740 pub(super) fn name_bytes(&self) -> &[u8] {
741 &self.filename.data
742 }
743
744 pub(super) fn source_type(&self) -> TypeId {
745 TypeId::from_u32(self.metadata.source_type.get()).unwrap()
746 }
747
748 pub(super) fn target_type(&self) -> TypeId {
749 TypeId::from_u32(self.metadata.transition_type.get()).unwrap()
750 }
751
752 pub(super) fn target_class(&self) -> ClassId {
753 ClassId::try_from(self.metadata.transition_class.get()).unwrap()
754 }
755
756 pub(super) fn out_type(&self) -> TypeId {
757 TypeId::from_u32(self.metadata.out_type.get()).unwrap()
758 }
759}
760
761impl Parse for DeprecatedFilenameTransition
762where
763 SimpleArray<u8>: Parse,
764{
765 type Error = anyhow::Error;
766
767 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
768 let tail = bytes;
769
770 let (filename, tail) = SimpleArray::<u8>::parse(tail)
771 .map_err(Into::<anyhow::Error>::into)
772 .context("parsing filename for deprecated filename transition")?;
773
774 let (metadata, tail) = PolicyCursor::parse::<DeprecatedFilenameTransitionMetadata>(tail)?;
775
776 Ok((Self { filename, metadata }, tail))
777 }
778}
779
780#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
781#[repr(C, packed)]
782pub(super) struct DeprecatedFilenameTransitionMetadata {
783 source_type: le::U32,
784 transition_type: le::U32,
785 transition_class: le::U32,
786 out_type: le::U32,
787}
788
789impl Validate for SimpleArray<InitialSid> {
790 type Error = anyhow::Error;
791
792 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
793 for initial_sid in crate::InitialSid::all_variants() {
794 if *initial_sid == crate::InitialSid::Init && !context.need_init_sid {
795 continue;
796 }
797 self.data
798 .iter()
799 .find(|initial| initial.id().get() == *initial_sid as u32)
800 .ok_or(ValidateError::MissingInitialSid { initial_sid: *initial_sid })?;
801 }
802 Ok(())
803 }
804}
805
806#[derive(Debug, PartialEq)]
807pub(super) struct InitialSid {
808 id: le::U32,
809 context: Context,
810}
811
812impl InitialSid {
813 pub(super) fn id(&self) -> le::U32 {
814 self.id
815 }
816
817 pub(super) fn context(&self) -> &Context {
818 &self.context
819 }
820}
821
822impl Parse for InitialSid
823where
824 Context: Parse,
825{
826 type Error = anyhow::Error;
827
828 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
829 let tail = bytes;
830
831 let (id, tail) = PolicyCursor::parse::<le::U32>(tail)?;
832
833 let (context, tail) = Context::parse(tail)
834 .map_err(Into::<anyhow::Error>::into)
835 .context("parsing context for initial sid")?;
836
837 Ok((Self { id, context }, tail))
838 }
839}
840
841#[derive(Debug, PartialEq)]
842pub(super) struct Context {
843 metadata: ContextMetadata,
844 mls_range: MlsRange,
845}
846
847impl Context {
848 pub(super) fn user_id(&self) -> UserId {
849 UserId::from_u32(self.metadata.user.get()).unwrap()
850 }
851 pub(super) fn role_id(&self) -> RoleId {
852 RoleId::from_u32(self.metadata.role.get()).unwrap()
853 }
854 pub(super) fn type_id(&self) -> TypeId {
855 TypeId::from_u32(self.metadata.context_type.get()).unwrap()
856 }
857 pub(super) fn low_level(&self) -> &MlsLevel {
858 self.mls_range.low()
859 }
860 pub(super) fn high_level(&self) -> &Option<MlsLevel> {
861 self.mls_range.high()
862 }
863}
864
865impl Parse for Context
866where
867 MlsRange: Parse,
868{
869 type Error = anyhow::Error;
870
871 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
872 let tail = bytes;
873
874 let (metadata, tail) =
875 PolicyCursor::parse::<ContextMetadata>(tail).context("parsing metadata for context")?;
876
877 let (mls_range, tail) = MlsRange::parse(tail)
878 .map_err(Into::<anyhow::Error>::into)
879 .context("parsing mls range for context")?;
880
881 Ok((Self { metadata, mls_range }, tail))
882 }
883}
884
885#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
886#[repr(C, packed)]
887pub(super) struct ContextMetadata {
888 user: le::U32,
889 role: le::U32,
890 context_type: le::U32,
891}
892
893impl Validate for NamedContextPair {
894 type Error = anyhow::Error;
895
896 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
901 Ok(())
902 }
903}
904
905#[derive(Debug, PartialEq)]
906pub(super) struct NamedContextPair {
907 name: SimpleArray<u8>,
908 context1: Context,
909 context2: Context,
910}
911
912impl Parse for NamedContextPair
913where
914 SimpleArray<u8>: Parse,
915 Context: Parse,
916{
917 type Error = anyhow::Error;
918
919 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
920 let tail = bytes;
921
922 let (name, tail) = SimpleArray::parse(tail)
923 .map_err(Into::<anyhow::Error>::into)
924 .context("parsing filesystem context name")?;
925
926 let (context1, tail) = Context::parse(tail)
927 .map_err(Into::<anyhow::Error>::into)
928 .context("parsing first context for filesystem context")?;
929
930 let (context2, tail) = Context::parse(tail)
931 .map_err(Into::<anyhow::Error>::into)
932 .context("parsing second context for filesystem context")?;
933
934 Ok((Self { name, context1, context2 }, tail))
935 }
936}
937
938impl Validate for Port {
939 type Error = anyhow::Error;
940
941 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
943 Ok(())
944 }
945}
946
947#[derive(Debug, PartialEq)]
948pub(super) struct Port {
949 metadata: PortMetadata,
950 context: Context,
951}
952
953impl Parse for Port
954where
955 Context: Parse,
956{
957 type Error = anyhow::Error;
958
959 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
960 let tail = bytes;
961
962 let (metadata, tail) =
963 PolicyCursor::parse::<PortMetadata>(tail).context("parsing metadata for context")?;
964
965 let (context, tail) = Context::parse(tail)
966 .map_err(Into::<anyhow::Error>::into)
967 .context("parsing context for port")?;
968
969 Ok((Self { metadata, context }, tail))
970 }
971}
972
973#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
974#[repr(C, packed)]
975pub(super) struct PortMetadata {
976 protocol: le::U32,
977 low_port: le::U32,
978 high_port: le::U32,
979}
980
981impl Validate for Node {
982 type Error = anyhow::Error;
983
984 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
986 Ok(())
987 }
988}
989
990#[derive(Debug, PartialEq)]
991pub(super) struct Node {
992 address: le::U32,
993 mask: le::U32,
994 context: Context,
995}
996
997impl Parse for Node
998where
999 Context: Parse,
1000{
1001 type Error = anyhow::Error;
1002
1003 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1004 let tail = bytes;
1005
1006 let (address, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1007
1008 let (mask, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1009
1010 let (context, tail) = Context::parse(tail)
1011 .map_err(Into::<anyhow::Error>::into)
1012 .context("parsing context for node")?;
1013
1014 Ok((Self { address, mask, context }, tail))
1015 }
1016}
1017
1018#[derive(Debug, PartialEq)]
1019pub(super) struct FsUse {
1020 behavior_and_name: Array<FsUseMetadata, u8>,
1021 context: Context,
1022}
1023
1024impl FsUse {
1025 pub fn fs_type(&self) -> &[u8] {
1026 &self.behavior_and_name.data
1027 }
1028
1029 pub(super) fn behavior(&self) -> FsUseType {
1030 FsUseType::try_from(self.behavior_and_name.metadata.behavior).unwrap()
1031 }
1032
1033 pub(super) fn context(&self) -> &Context {
1034 &self.context
1035 }
1036}
1037
1038impl Parse for FsUse
1039where
1040 Array<FsUseMetadata, u8>: Parse,
1041 Context: Parse,
1042{
1043 type Error = anyhow::Error;
1044
1045 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1046 let tail = bytes;
1047
1048 let (behavior_and_name, tail) = Array::<FsUseMetadata, u8>::parse(tail)
1049 .map_err(Into::<anyhow::Error>::into)
1050 .context("parsing fs use metadata")?;
1051
1052 let (context, tail) = Context::parse(tail)
1053 .map_err(Into::<anyhow::Error>::into)
1054 .context("parsing context for fs use")?;
1055
1056 Ok((Self { behavior_and_name, context }, tail))
1057 }
1058}
1059
1060impl Validate for FsUse {
1061 type Error = anyhow::Error;
1062
1063 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1064 FsUseType::try_from(self.behavior_and_name.metadata.behavior)?;
1065
1066 Ok(())
1067 }
1068}
1069
1070#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1071#[repr(C, packed)]
1072pub(super) struct FsUseMetadata {
1073 behavior: le::U32,
1075 name_length: le::U32,
1077}
1078
1079impl Counted for FsUseMetadata {
1080 fn count(&self) -> u32 {
1081 self.name_length.get()
1082 }
1083}
1084
1085#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
1088pub enum FsUseType {
1089 Xattr = 1,
1090 Trans = 2,
1091 Task = 3,
1092}
1093
1094impl TryFrom<le::U32> for FsUseType {
1095 type Error = anyhow::Error;
1096
1097 fn try_from(value: le::U32) -> Result<Self, Self::Error> {
1098 match value.get() {
1099 1 => Ok(FsUseType::Xattr),
1100 2 => Ok(FsUseType::Trans),
1101 3 => Ok(FsUseType::Task),
1102 _ => Err(ValidateError::InvalidFsUseType { value: value.get() }.into()),
1103 }
1104 }
1105}
1106
1107impl Validate for IPv6Node {
1108 type Error = anyhow::Error;
1109
1110 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1112 Ok(())
1113 }
1114}
1115
1116#[derive(Debug, PartialEq)]
1117pub(super) struct IPv6Node {
1118 address: [le::U32; 4],
1119 mask: [le::U32; 4],
1120 context: Context,
1121}
1122
1123impl Parse for IPv6Node
1124where
1125 Context: Parse,
1126{
1127 type Error = anyhow::Error;
1128
1129 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1130 let tail = bytes;
1131
1132 let (address, tail) = PolicyCursor::parse::<[le::U32; 4]>(tail)?;
1133
1134 let (mask, tail) = PolicyCursor::parse::<[le::U32; 4]>(tail)?;
1135
1136 let (context, tail) = Context::parse(tail)
1137 .map_err(Into::<anyhow::Error>::into)
1138 .context("parsing context for ipv6 node")?;
1139
1140 Ok((Self { address, mask, context }, tail))
1141 }
1142}
1143
1144impl Validate for InfinitiBandPartitionKey {
1145 type Error = anyhow::Error;
1146
1147 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1149 Ok(())
1150 }
1151}
1152
1153#[derive(Debug, PartialEq)]
1154pub(super) struct InfinitiBandPartitionKey {
1155 low: le::U32,
1156 high: le::U32,
1157 context: Context,
1158}
1159
1160impl Parse for InfinitiBandPartitionKey
1161where
1162 Context: Parse,
1163{
1164 type Error = anyhow::Error;
1165
1166 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1167 let tail = bytes;
1168
1169 let (low, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1170
1171 let (high, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1172
1173 let (context, tail) = Context::parse(tail)
1174 .map_err(Into::<anyhow::Error>::into)
1175 .context("parsing context for infiniti band partition key")?;
1176
1177 Ok((Self { low, high, context }, tail))
1178 }
1179}
1180
1181impl Validate for InfinitiBandEndPort {
1182 type Error = anyhow::Error;
1183
1184 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1186 Ok(())
1187 }
1188}
1189
1190#[derive(Debug, PartialEq)]
1191pub(super) struct InfinitiBandEndPort {
1192 port_and_name: Array<InfinitiBandEndPortMetadata, u8>,
1193 context: Context,
1194}
1195
1196impl Parse for InfinitiBandEndPort
1197where
1198 Array<InfinitiBandEndPortMetadata, u8>: Parse,
1199 Context: Parse,
1200{
1201 type Error = anyhow::Error;
1202
1203 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1204 let tail = bytes;
1205
1206 let (port_and_name, tail) = Array::<InfinitiBandEndPortMetadata, u8>::parse(tail)
1207 .map_err(Into::<anyhow::Error>::into)
1208 .context("parsing infiniti band end port metadata")?;
1209
1210 let (context, tail) = Context::parse(tail)
1211 .map_err(Into::<anyhow::Error>::into)
1212 .context("parsing context for infiniti band end port")?;
1213
1214 Ok((Self { port_and_name, context }, tail))
1215 }
1216}
1217
1218#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1219#[repr(C, packed)]
1220pub(super) struct InfinitiBandEndPortMetadata {
1221 length: le::U32,
1222 port: le::U32,
1223}
1224
1225impl Counted for InfinitiBandEndPortMetadata {
1226 fn count(&self) -> u32 {
1227 self.length.get()
1228 }
1229}
1230
1231impl Validate for GenericFsContext {
1232 type Error = anyhow::Error;
1233
1234 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1236 Ok(())
1237 }
1238}
1239
1240#[derive(Debug)]
1243pub(super) struct GenericFsContext {
1244 fs_type: SimpleArray<u8>,
1245 fs_context: SimpleArrayView<FsContext>,
1246}
1247
1248impl GenericFsContext {
1249 pub(super) fn for_query(fs_type: &str) -> SimpleArray<u8> {
1251 Array { data: fs_type.as_bytes().to_vec(), metadata: le::U32::new(fs_type.len() as u32) }
1252 }
1253}
1254
1255impl Parse for GenericFsContext {
1256 type Error = anyhow::Error;
1257
1258 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1259 let tail = bytes;
1260
1261 let (fs_type, tail) = SimpleArray::<u8>::parse(tail)
1262 .map_err(Into::<anyhow::Error>::into)
1263 .context("parsing fs_type for generic fs context")?;
1264
1265 let (fs_context, tail) = SimpleArrayView::<FsContext>::parse(tail)
1266 .map_err(Into::<anyhow::Error>::into)
1267 .context("parsing fs_context for generic fs context")?;
1268
1269 Ok((Self { fs_type, fs_context }, tail))
1270 }
1271}
1272
1273impl Hashable for GenericFsContext {
1274 type Key = SimpleArray<u8>;
1275 type Value = FsContext;
1276
1277 fn key(&self) -> &Self::Key {
1278 &self.fs_type
1279 }
1280
1281 fn values(&self) -> &SimpleArrayView<Self::Value> {
1282 &self.fs_context
1283 }
1284}
1285
1286impl Eq for SimpleArray<u8> {}
1287
1288impl Hash for SimpleArray<u8> {
1289 fn hash<H: Hasher>(&self, state: &mut H) {
1290 self.data.hash(state);
1291 }
1292}
1293
1294impl SimpleArrayView<FsContext> {
1295 fn try_validate_alphabetic_order(&self, context: &PolicyValidationContext) -> bool {
1296 self.data()
1297 .iter(&context.data)
1298 .map(|view| view.parse(&context.data).partial_path().to_vec())
1299 .is_sorted_by(|a, b| a <= b)
1300 }
1301
1302 fn try_validate_length_descending_order(&self, context: &PolicyValidationContext) -> bool {
1303 self.data()
1304 .iter(&context.data)
1305 .map(|view| view.parse(&context.data).partial_path().len())
1306 .is_sorted_by(|a, b| a >= b)
1307 }
1308}
1309
1310impl Validate for SimpleArrayView<FsContext> {
1311 type Error = anyhow::Error;
1312
1313 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
1318 if !self.try_validate_alphabetic_order(context)
1319 && !self.try_validate_length_descending_order(context)
1320 {
1321 return Err(anyhow::anyhow!(
1322 "FsContexts must be sorted by partial path length (descending) or alphabetically.",
1323 ));
1324 }
1325 Ok(())
1326 }
1327}
1328
1329#[derive(Debug, PartialEq)]
1330pub(super) struct FsContext {
1331 partial_path: SimpleArray<u8>,
1334 class: le::U32,
1338 context: Context,
1340}
1341
1342impl FsContext {
1343 pub(super) fn partial_path(&self) -> &[u8] {
1344 &self.partial_path.data
1345 }
1346
1347 pub(super) fn context(&self) -> &Context {
1348 &self.context
1349 }
1350
1351 pub(super) fn class(&self) -> Option<ClassId> {
1352 ClassId::try_from(self.class.get()).ok()
1353 }
1354}
1355
1356impl Parse for FsContext
1357where
1358 SimpleArray<u8>: Parse,
1359 Context: Parse,
1360{
1361 type Error = anyhow::Error;
1362
1363 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1364 let tail = bytes;
1365
1366 let (partial_path, tail) = SimpleArray::<u8>::parse(tail)
1367 .map_err(Into::<anyhow::Error>::into)
1368 .context("parsing filesystem context partial path")?;
1369
1370 let (class, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1371
1372 let (context, tail) = Context::parse(tail)
1373 .map_err(Into::<anyhow::Error>::into)
1374 .context("parsing context for filesystem context")?;
1375
1376 Ok((Self { partial_path, class, context }, tail))
1377 }
1378}
1379
1380impl Walk for FsContext {
1381 fn walk(policy_data: &PolicyData, offset: PolicyOffset) -> PolicyOffset {
1382 let cursor = PolicyCursor::new_at(policy_data, offset);
1383 let (_, tail) = FsContext::parse(cursor)
1384 .map_err(Into::<anyhow::Error>::into)
1385 .expect("policy should be valid");
1386 tail.offset()
1387 }
1388}
1389
1390impl Validate for RangeTransition {
1391 type Error = anyhow::Error;
1392 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1393 if self.metadata.target_class.get() == 0 {
1394 return Err(ValidateError::NonOptionalIdIsZero.into());
1395 }
1396 Ok(())
1397 }
1398}
1399
1400#[derive(Debug, PartialEq)]
1401pub(super) struct RangeTransition {
1402 metadata: RangeTransitionMetadata,
1403 mls_range: MlsRange,
1404}
1405
1406impl RangeTransition {
1407 pub fn source_type(&self) -> TypeId {
1408 TypeId::from_u32(self.metadata.source_type.get()).unwrap()
1409 }
1410
1411 pub fn target_type(&self) -> TypeId {
1412 TypeId::from_u32(self.metadata.target_type.get()).unwrap()
1413 }
1414
1415 pub fn target_class(&self) -> ClassId {
1416 ClassId::try_from(self.metadata.target_class.get()).unwrap()
1417 }
1418
1419 pub fn mls_range(&self) -> &MlsRange {
1420 &self.mls_range
1421 }
1422}
1423
1424impl Parse for RangeTransition
1425where
1426 MlsRange: Parse,
1427{
1428 type Error = anyhow::Error;
1429
1430 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1431 let tail = bytes;
1432
1433 let (metadata, tail) = PolicyCursor::parse::<RangeTransitionMetadata>(tail)
1434 .context("parsing range transition metadata")?;
1435
1436 let (mls_range, tail) = MlsRange::parse(tail)
1437 .map_err(Into::<anyhow::Error>::into)
1438 .context("parsing mls range for range transition")?;
1439
1440 Ok((Self { metadata, mls_range }, tail))
1441 }
1442}
1443
1444#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1445#[repr(C, packed)]
1446pub(super) struct RangeTransitionMetadata {
1447 source_type: le::U32,
1448 target_type: le::U32,
1449 target_class: le::U32,
1450}
1451
1452#[cfg(test)]
1453pub(super) mod testing {
1454 use super::AccessVectorRule;
1455 use std::cmp::Ordering;
1456
1457 pub(in super::super) fn access_vector_rule_ordering(
1458 left: &AccessVectorRule,
1459 right: &AccessVectorRule,
1460 ) -> Ordering {
1461 (
1462 left.metadata.source_type,
1463 left.metadata.target_type,
1464 left.metadata.class,
1465 left.metadata.access_vector_rule_type,
1466 )
1467 .cmp(&(
1468 right.metadata.source_type,
1469 right.metadata.target_type,
1470 right.metadata.class,
1471 right.metadata.access_vector_rule_type,
1472 ))
1473 }
1474}
1475
1476#[cfg(test)]
1477mod tests {
1478 use super::super::{ClassId, parse_policy_by_value};
1479 use super::{
1480 ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM, ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM,
1481 ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES,
1482 XPERMS_TYPE_IOCTL_PREFIXES, XPERMS_TYPE_NLMSG,
1483 };
1484 use crate::new_policy::traits::HasPolicyId;
1485
1486 impl super::AccessVectorRuleMetadata {
1487 pub fn is_allowxperm(&self) -> bool {
1491 (self.access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM) != 0
1492 }
1493
1494 pub fn is_auditallowxperm(&self) -> bool {
1498 (self.access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM) != 0
1499 }
1500
1501 pub fn is_dontauditxperm(&self) -> bool {
1505 (self.access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM) != 0
1506 }
1507
1508 pub fn target_class(&self) -> ClassId {
1513 ClassId::try_from(self.class.get() as u32).unwrap()
1514 }
1515 }
1516
1517 #[test]
1518 fn parse_allowxperm_one_ioctl() {
1519 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1520 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1521 let policy = policy.validate().expect("validate policy");
1522
1523 let class_id =
1524 policy.classes().get_by_name(b"class_one_ioctl").expect("look up class_one_ioctl").id();
1525
1526 let rules: Vec<_> = policy
1527 .access_vector_rules_for_test()
1528 .filter(|rule| rule.metadata.target_class() == class_id)
1529 .collect();
1530
1531 assert_eq!(rules.len(), 1);
1532 assert!(rules[0].metadata.is_allowxperm());
1533 if let Some(xperms) = rules[0].extended_permissions() {
1534 assert_eq!(xperms.count(), 1);
1535 assert!(xperms.contains(0xabcd));
1536 } else {
1537 panic!("unexpected permission data type")
1538 }
1539 }
1540
1541 #[test]
1544 fn parse_allowxperm_two_ioctls_same_range() {
1545 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1546 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1547 let policy = policy.validate().expect("validate policy");
1548
1549 let class_id = policy
1550 .classes()
1551 .get_by_name(b"class_two_ioctls_same_range")
1552 .expect("look up class_two_ioctls_same_range")
1553 .id();
1554
1555 let rules: Vec<_> = policy
1556 .access_vector_rules_for_test()
1557 .filter(|rule| rule.metadata.target_class() == class_id)
1558 .collect();
1559
1560 assert_eq!(rules.len(), 1);
1561 assert!(rules[0].metadata.is_allowxperm());
1562 if let Some(xperms) = rules[0].extended_permissions() {
1563 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1564 assert_eq!(xperms.xperms_optional_prefix, 0x12);
1565 assert_eq!(xperms.count(), 2);
1566 assert!(xperms.contains(0x1234));
1567 assert!(xperms.contains(0x1256));
1568 } else {
1569 panic!("unexpected permission data type")
1570 }
1571 }
1572
1573 #[test]
1576 fn parse_allowxperm_two_ioctls_same_range_diff_rules() {
1577 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1578 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1579 let policy = policy.validate().expect("validate policy");
1580
1581 let class_id = policy
1582 .classes()
1583 .get_by_name(b"class_four_ioctls_same_range_diff_rules")
1584 .expect("look up class_four_ioctls_same_range_diff_rules")
1585 .id();
1586
1587 let rules: Vec<_> = policy
1588 .access_vector_rules_for_test()
1589 .filter(|rule| rule.metadata.target_class() == class_id)
1590 .collect();
1591
1592 assert_eq!(rules.len(), 1);
1593 assert!(rules[0].metadata.is_allowxperm());
1594 if let Some(xperms) = rules[0].extended_permissions() {
1595 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1596 assert_eq!(xperms.xperms_optional_prefix, 0x30);
1597 assert_eq!(xperms.count(), 4);
1598 assert!(xperms.contains(0x3008));
1599 assert!(xperms.contains(0x3009));
1600 assert!(xperms.contains(0x3011));
1601 assert!(xperms.contains(0x3013));
1602 } else {
1603 panic!("unexpected permission data type")
1604 }
1605 }
1606
1607 #[test]
1610 fn parse_allowxperm_two_ioctls_different_range() {
1611 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1612 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1613 let policy = policy.validate().expect("validate policy");
1614
1615 let class_id = policy
1616 .classes()
1617 .get_by_name(b"class_two_ioctls_diff_range")
1618 .expect("look up class_two_ioctls_diff_range")
1619 .id();
1620
1621 let rules: Vec<_> = policy
1622 .access_vector_rules_for_test()
1623 .filter(|rule| rule.metadata.target_class() == class_id)
1624 .collect();
1625
1626 assert_eq!(rules.len(), 2);
1627 assert!(rules[0].metadata.is_allowxperm());
1628 if let Some(xperms) = rules[0].extended_permissions() {
1629 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1630 assert_eq!(xperms.xperms_optional_prefix, 0x56);
1631 assert_eq!(xperms.count(), 1);
1632 assert!(xperms.contains(0x5678));
1633 } else {
1634 panic!("unexpected permission data type")
1635 }
1636 assert!(rules[1].metadata.is_allowxperm());
1637 if let Some(xperms) = rules[1].extended_permissions() {
1638 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1639 assert_eq!(xperms.xperms_optional_prefix, 0x12);
1640 assert_eq!(xperms.count(), 1);
1641 assert!(xperms.contains(0x1234));
1642 } else {
1643 panic!("unexpected permission data type")
1644 }
1645 }
1646
1647 #[test]
1650 fn parse_allowxperm_one_driver_range() {
1651 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1652 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1653 let policy = policy.validate().expect("validate policy");
1654
1655 let class_id = policy
1656 .classes()
1657 .get_by_name(b"class_one_driver_range")
1658 .expect("look up class_one_driver_range")
1659 .id();
1660
1661 let rules: Vec<_> = policy
1662 .access_vector_rules_for_test()
1663 .filter(|rule| rule.metadata.target_class() == class_id)
1664 .collect();
1665
1666 assert_eq!(rules.len(), 1);
1667 assert!(rules[0].metadata.is_allowxperm());
1668 if let Some(xperms) = rules[0].extended_permissions() {
1669 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1670 assert_eq!(xperms.count(), 0x100);
1671 assert!(xperms.contains(0x1000));
1672 assert!(xperms.contains(0x10ab));
1673 } else {
1674 panic!("unexpected permission data type")
1675 }
1676 }
1677
1678 #[test]
1682 fn parse_allowxperm_most_ioctls() {
1683 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1684 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1685 let policy = policy.validate().expect("validate policy");
1686
1687 let class_id = policy
1688 .classes()
1689 .get_by_name(b"class_most_ioctls")
1690 .expect("look up class_most_ioctls")
1691 .id();
1692
1693 let rules: Vec<_> = policy
1694 .access_vector_rules_for_test()
1695 .filter(|rule| rule.metadata.target_class() == class_id)
1696 .collect();
1697
1698 assert_eq!(rules.len(), 3);
1699 assert!(rules[0].metadata.is_allowxperm());
1700 if let Some(xperms) = rules[0].extended_permissions() {
1701 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1702 assert_eq!(xperms.xperms_optional_prefix, 0xff);
1703 assert_eq!(xperms.count(), 0xfe);
1704 for xperm in 0xff00..0xfffd {
1705 assert!(xperms.contains(xperm));
1706 }
1707 } else {
1708 panic!("unexpected permission data type")
1709 }
1710 if let Some(xperms) = rules[1].extended_permissions() {
1711 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1712 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1713 assert_eq!(xperms.count(), 0xfe);
1714 for xperm in 0x0002..0x0100 {
1715 assert!(xperms.contains(xperm));
1716 }
1717 } else {
1718 panic!("unexpected permission data type")
1719 }
1720 if let Some(xperms) = rules[2].extended_permissions() {
1721 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1722 assert_eq!(xperms.count(), 0xfe00);
1723 for xperm in 0x0100..0xff00 {
1724 assert!(xperms.contains(xperm));
1725 }
1726 } else {
1727 panic!("unexpected permission data type")
1728 }
1729 }
1730
1731 #[test]
1735 fn parse_allowxperm_most_ioctls_with_hole() {
1736 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1737 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1738 let policy = policy.validate().expect("validate policy");
1739
1740 let class_id = policy
1741 .classes()
1742 .get_by_name(b"class_most_ioctls_with_hole")
1743 .expect("look up class_most_ioctls_with_hole")
1744 .id();
1745
1746 let rules: Vec<_> = policy
1747 .access_vector_rules_for_test()
1748 .filter(|rule| rule.metadata.target_class() == class_id)
1749 .collect();
1750
1751 assert_eq!(rules.len(), 5);
1752 assert!(rules[0].metadata.is_allowxperm());
1753 if let Some(xperms) = rules[0].extended_permissions() {
1754 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1755 assert_eq!(xperms.xperms_optional_prefix, 0xff);
1756 assert_eq!(xperms.count(), 0xfe);
1757 for xperm in 0xff00..0xfffd {
1758 assert!(xperms.contains(xperm));
1759 }
1760 } else {
1761 panic!("unexpected permission data type")
1762 }
1763 if let Some(xperms) = rules[1].extended_permissions() {
1764 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1765 assert_eq!(xperms.xperms_optional_prefix, 0x40);
1766 assert_eq!(xperms.count(), 0xfe);
1767 for xperm in 0x4002..0x4100 {
1768 assert!(xperms.contains(xperm));
1769 }
1770 } else {
1771 panic!("unexpected permission data type")
1772 }
1773 assert!(rules[0].metadata.is_allowxperm());
1774 if let Some(xperms) = rules[2].extended_permissions() {
1775 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1776 assert_eq!(xperms.xperms_optional_prefix, 0x2f);
1777 assert_eq!(xperms.count(), 0xfe);
1778 for xperm in 0x2f00..0x2ffd {
1779 assert!(xperms.contains(xperm));
1780 }
1781 } else {
1782 panic!("unexpected permission data type")
1783 }
1784 if let Some(xperms) = rules[3].extended_permissions() {
1785 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1786 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1787 assert_eq!(xperms.count(), 0xfe);
1788 for xperm in 0x0002..0x0100 {
1789 assert!(xperms.contains(xperm));
1790 }
1791 } else {
1792 panic!("unexpected permission data type")
1793 }
1794 if let Some(xperms) = rules[4].extended_permissions() {
1795 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1796 assert_eq!(xperms.count(), 0xec00);
1797 for xperm in 0x0100..0x2f00 {
1798 assert!(xperms.contains(xperm));
1799 }
1800 for xperm in 0x4100..0xff00 {
1801 assert!(xperms.contains(xperm));
1802 }
1803 } else {
1804 panic!("unexpected permission data type")
1805 }
1806 }
1807
1808 #[test]
1813 fn parse_allowxperm_all_ioctls() {
1814 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1815 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1816 let policy = policy.validate().expect("validate policy");
1817
1818 let class_id = policy
1819 .classes()
1820 .get_by_name(b"class_all_ioctls")
1821 .expect("look up class_all_ioctls")
1822 .id();
1823
1824 let rules: Vec<_> = policy
1825 .access_vector_rules_for_test()
1826 .filter(|rule| rule.metadata.target_class() == class_id)
1827 .collect();
1828
1829 assert_eq!(rules.len(), 1);
1830 assert!(rules[0].metadata.is_allowxperm());
1831 if let Some(xperms) = rules[0].extended_permissions() {
1832 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1833 assert_eq!(xperms.count(), 0x10000);
1834 } else {
1835 panic!("unexpected permission data type")
1836 }
1837 }
1838
1839 #[test]
1840 fn parse_allowxperm_one_nlmsg() {
1841 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1842 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1843 let policy = policy.validate().expect("validate policy");
1844
1845 let class_id =
1846 policy.classes().get_by_name(b"class_one_nlmsg").expect("look up class_one_nlmsg").id();
1847
1848 let rules: Vec<_> = policy
1849 .access_vector_rules_for_test()
1850 .filter(|rule| rule.metadata.target_class() == class_id)
1851 .collect();
1852
1853 assert_eq!(rules.len(), 1);
1854 assert!(rules[0].metadata.is_allowxperm());
1855 if let Some(xperms) = rules[0].extended_permissions() {
1856 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1857 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1858 assert_eq!(xperms.count(), 1);
1859 assert!(xperms.contains(0x12));
1860 } else {
1861 panic!("unexpected permission data type")
1862 }
1863 }
1864
1865 #[test]
1868 fn parse_allowxperm_two_nlmsg_same_range() {
1869 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1870 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1871 let policy = policy.validate().expect("validate policy");
1872
1873 let class_id = policy
1874 .classes()
1875 .get_by_name(b"class_two_nlmsg_same_range")
1876 .expect("look up class_two_nlmsg_same_range")
1877 .id();
1878
1879 let rules: Vec<_> = policy
1880 .access_vector_rules_for_test()
1881 .filter(|rule| rule.metadata.target_class() == class_id)
1882 .collect();
1883
1884 assert_eq!(rules.len(), 1);
1885 assert!(rules[0].metadata.is_allowxperm());
1886 if let Some(xperms) = rules[0].extended_permissions() {
1887 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1888 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1889 assert_eq!(xperms.count(), 2);
1890 assert!(xperms.contains(0x12));
1891 assert!(xperms.contains(0x24));
1892 } else {
1893 panic!("unexpected permission data type")
1894 }
1895 }
1896
1897 #[test]
1900 fn parse_allowxperm_two_nlmsg_different_range() {
1901 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1902 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1903 let policy = policy.validate().expect("validate policy");
1904
1905 let class_id = policy
1906 .classes()
1907 .get_by_name(b"class_two_nlmsg_diff_range")
1908 .expect("look up class_two_nlmsg_diff_range")
1909 .id();
1910
1911 let rules: Vec<_> = policy
1912 .access_vector_rules_for_test()
1913 .filter(|rule| rule.metadata.target_class() == class_id)
1914 .collect();
1915
1916 assert_eq!(rules.len(), 2);
1917 assert!(rules[0].metadata.is_allowxperm());
1918 if let Some(xperms) = rules[0].extended_permissions() {
1919 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1920 assert_eq!(xperms.xperms_optional_prefix, 0x10);
1921 assert_eq!(xperms.count(), 1);
1922 assert!(xperms.contains(0x1024));
1923 } else {
1924 panic!("unexpected permission data type")
1925 }
1926 assert!(rules[1].metadata.is_allowxperm());
1927 if let Some(xperms) = rules[1].extended_permissions() {
1928 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1929 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1930 assert_eq!(xperms.count(), 1);
1931 assert!(xperms.contains(0x12));
1932 } else {
1933 panic!("unexpected permission data type")
1934 }
1935 }
1936
1937 #[test]
1940 fn parse_allowxperm_one_nlmsg_range() {
1941 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1942 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1943 let policy = policy.validate().expect("validate policy");
1944
1945 let class_id = policy
1946 .classes()
1947 .get_by_name(b"class_one_nlmsg_range")
1948 .expect("look up class_one_nlmsg_range")
1949 .id();
1950
1951 let rules: Vec<_> = policy
1952 .access_vector_rules_for_test()
1953 .filter(|rule| rule.metadata.target_class() == class_id)
1954 .collect();
1955
1956 assert_eq!(rules.len(), 1);
1957 assert!(rules[0].metadata.is_allowxperm());
1958 if let Some(xperms) = rules[0].extended_permissions() {
1959 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1960 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1961 assert_eq!(xperms.count(), 0x100);
1962 for i in 0x0..0xff {
1963 assert!(xperms.contains(i), "{i}");
1964 }
1965 } else {
1966 panic!("unexpected permission data type")
1967 }
1968 }
1969
1970 #[test]
1976 fn parse_allowxperm_two_nlmsg_ranges() {
1977 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1978 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1979 let policy = policy.validate().expect("validate policy");
1980
1981 let class_id = policy
1982 .classes()
1983 .get_by_name(b"class_two_nlmsg_ranges")
1984 .expect("look up class_two_nlmsg_ranges")
1985 .id();
1986
1987 let rules: Vec<_> = policy
1988 .access_vector_rules_for_test()
1989 .filter(|rule| rule.metadata.target_class() == class_id)
1990 .collect();
1991
1992 assert_eq!(rules.len(), 2);
1993 assert!(rules[0].metadata.is_allowxperm());
1994 if let Some(xperms) = rules[0].extended_permissions() {
1995 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1996 assert_eq!(xperms.xperms_optional_prefix, 0x01);
1997 assert_eq!(xperms.count(), 0x100);
1998 for i in 0x0100..0x01ff {
1999 assert!(xperms.contains(i), "{i}");
2000 }
2001 } else {
2002 panic!("unexpected permission data type")
2003 }
2004 if let Some(xperms) = rules[1].extended_permissions() {
2005 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2006 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2007 assert_eq!(xperms.count(), 0x100);
2008 for i in 0x0..0xff {
2009 assert!(xperms.contains(i), "{i}");
2010 }
2011 } else {
2012 panic!("unexpected permission data type")
2013 }
2014 }
2015
2016 #[test]
2023 fn parse_allowxperm_three_separate_nlmsg_ranges() {
2024 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
2025 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2026 let policy = policy.validate().expect("validate policy");
2027
2028 let class_id = policy
2029 .classes()
2030 .get_by_name(b"class_three_separate_nlmsg_ranges")
2031 .expect("look up class_three_separate_nlmsg_ranges")
2032 .id();
2033
2034 let rules: Vec<_> = policy
2035 .access_vector_rules_for_test()
2036 .filter(|rule| rule.metadata.target_class() == class_id)
2037 .collect();
2038
2039 assert_eq!(rules.len(), 3);
2040 assert!(rules[0].metadata.is_allowxperm());
2041 if let Some(xperms) = rules[0].extended_permissions() {
2042 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2043 assert_eq!(xperms.xperms_optional_prefix, 0x20);
2044 assert_eq!(xperms.count(), 0x100);
2045 for i in 0x2000..0x20ff {
2046 assert!(xperms.contains(i), "{i}");
2047 }
2048 } else {
2049 panic!("unexpected permission data type")
2050 }
2051 if let Some(xperms) = rules[1].extended_permissions() {
2052 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2053 assert_eq!(xperms.xperms_optional_prefix, 0x10);
2054 assert_eq!(xperms.count(), 0x100);
2055 for i in 0x1000..0x10ff {
2056 assert!(xperms.contains(i), "{i}");
2057 }
2058 } else {
2059 panic!("unexpected permission data type")
2060 }
2061 if let Some(xperms) = rules[2].extended_permissions() {
2062 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2063 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2064 assert_eq!(xperms.count(), 0x100);
2065 for i in 0x0..0xff {
2066 assert!(xperms.contains(i), "{i}");
2067 }
2068 } else {
2069 panic!("unexpected permission data type")
2070 }
2071 }
2072
2073 #[test]
2080 fn parse_allowxperm_three_contiguous_nlmsg_ranges() {
2081 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
2082 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2083 let policy = policy.validate().expect("validate policy");
2084
2085 let class_id = policy
2086 .classes()
2087 .get_by_name(b"class_three_contiguous_nlmsg_ranges")
2088 .expect("look up class_three_contiguous_nlmsg_ranges")
2089 .id();
2090
2091 let rules: Vec<_> = policy
2092 .access_vector_rules_for_test()
2093 .filter(|rule| rule.metadata.target_class() == class_id)
2094 .collect();
2095
2096 assert_eq!(rules.len(), 2);
2097 assert!(rules[0].metadata.is_allowxperm());
2098 if let Some(xperms) = rules[0].extended_permissions() {
2099 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2100 assert_eq!(xperms.xperms_optional_prefix, 0x02);
2101 assert_eq!(xperms.count(), 0x100);
2102 for i in 0x0200..0x02ff {
2103 assert!(xperms.contains(i), "{i}");
2104 }
2105 } else {
2106 panic!("unexpected permission data type")
2107 }
2108 if let Some(xperms) = rules[1].extended_permissions() {
2109 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2110 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2111 assert_eq!(xperms.count(), 0x100);
2112 for i in 0x0..0xff {
2113 assert!(xperms.contains(i), "{i}");
2114 }
2115 } else {
2116 panic!("unexpected permission data type")
2117 }
2118 }
2119
2120 #[test]
2123 fn parse_auditallowxperm() {
2124 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
2125 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2126 let policy = policy.validate().expect("validate policy");
2127
2128 let class_id = policy
2129 .classes()
2130 .get_by_name(b"class_auditallowxperm")
2131 .expect("look up class_auditallowxperm")
2132 .id();
2133
2134 let rules: Vec<_> = policy
2135 .access_vector_rules_for_test()
2136 .filter(|rule| rule.metadata.target_class() == class_id)
2137 .collect();
2138
2139 assert_eq!(rules.len(), 2);
2140 assert!(rules[0].metadata.is_auditallowxperm());
2141 if let Some(xperms) = rules[0].extended_permissions() {
2142 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2143 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2144 assert_eq!(xperms.count(), 1);
2145 assert!(xperms.contains(0x10));
2146 } else {
2147 panic!("unexpected permission data type")
2148 }
2149 if let Some(xperms) = rules[1].extended_permissions() {
2150 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
2151 assert_eq!(xperms.xperms_optional_prefix, 0x10);
2152 assert_eq!(xperms.count(), 1);
2153 assert!(xperms.contains(0x1000));
2154 } else {
2155 panic!("unexpected permission data type")
2156 }
2157 }
2158
2159 #[test]
2167 fn parse_dontauditxperm() {
2168 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
2169 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2170 let policy = policy.validate().expect("validate policy");
2171
2172 let class_id = policy
2173 .classes()
2174 .get_by_name(b"class_dontauditxperm")
2175 .expect("look up class_dontauditxperm")
2176 .id();
2177
2178 let rules: Vec<_> = policy
2179 .access_vector_rules_for_test()
2180 .filter(|rule| rule.metadata.target_class() == class_id)
2181 .collect();
2182
2183 assert_eq!(rules.len(), 2);
2184 assert!(rules[0].metadata.is_dontauditxperm());
2185 if let Some(xperms) = rules[0].extended_permissions() {
2186 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2187 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2188 assert_eq!(xperms.count(), 1);
2189 assert!(xperms.contains(0x11));
2190 } else {
2191 panic!("unexpected permission data type")
2192 }
2193 if let Some(xperms) = rules[1].extended_permissions() {
2194 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
2195 assert_eq!(xperms.xperms_optional_prefix, 0x10);
2196 assert_eq!(xperms.count(), 1);
2197 assert!(xperms.contains(0x1000));
2198 } else {
2199 panic!("unexpected permission data type")
2200 }
2201 }
2202
2203 #[test]
2207 fn parse_auditallowxperm_not_coalesced() {
2208 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
2209 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2210 let policy = policy.validate().expect("validate policy");
2211
2212 let class_id = policy
2213 .classes()
2214 .get_by_name(b"class_auditallowxperm_not_coalesced")
2215 .expect("class_auditallowxperm_not_coalesced")
2216 .id();
2217
2218 let rules: Vec<_> = policy
2219 .access_vector_rules_for_test()
2220 .filter(|rule| rule.metadata.target_class() == class_id)
2221 .collect();
2222
2223 assert_eq!(rules.len(), 2);
2224 assert!(rules[0].metadata.is_allowxperm());
2225 assert!(!rules[0].metadata.is_auditallowxperm());
2226 if let Some(xperms) = rules[0].extended_permissions() {
2227 assert_eq!(xperms.count(), 1);
2228 assert!(xperms.contains(0xabcd));
2229 } else {
2230 panic!("unexpected permission data type")
2231 }
2232 assert!(!rules[1].metadata.is_allowxperm());
2233 assert!(rules[1].metadata.is_auditallowxperm());
2234 if let Some(xperms) = rules[1].extended_permissions() {
2235 assert_eq!(xperms.count(), 1);
2236 assert!(xperms.contains(0xabcd));
2237 } else {
2238 panic!("unexpected permission data type")
2239 }
2240 }
2241}