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