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
793 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
794 for initial_sid in crate::InitialSid::all_variants() {
795 if *initial_sid == crate::InitialSid::Init && !context.need_init_sid {
796 continue;
797 }
798 self.data
799 .iter()
800 .find(|initial| initial.id().get() == *initial_sid as u32)
801 .ok_or(ValidateError::MissingInitialSid { initial_sid: *initial_sid })?;
802 }
803 Ok(())
804 }
805}
806
807#[derive(Debug, PartialEq)]
808pub(super) struct InitialSid {
809 id: le::U32,
810 context: Context,
811}
812
813impl InitialSid {
814 pub(super) fn id(&self) -> le::U32 {
815 self.id
816 }
817
818 pub(super) fn context(&self) -> &Context {
819 &self.context
820 }
821}
822
823impl Parse for InitialSid
824where
825 Context: Parse,
826{
827 type Error = anyhow::Error;
828
829 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
830 let tail = bytes;
831
832 let (id, tail) = PolicyCursor::parse::<le::U32>(tail)?;
833
834 let (context, tail) = Context::parse(tail)
835 .map_err(Into::<anyhow::Error>::into)
836 .context("parsing context for initial sid")?;
837
838 Ok((Self { id, context }, tail))
839 }
840}
841
842#[derive(Debug, PartialEq)]
843pub(super) struct Context {
844 metadata: ContextMetadata,
845 mls_range: MlsRange,
846}
847
848impl Context {
849 pub(super) fn user_id(&self) -> UserId {
850 UserId(NonZeroU32::new(self.metadata.user.get()).unwrap())
851 }
852 pub(super) fn role_id(&self) -> RoleId {
853 RoleId(NonZeroU32::new(self.metadata.role.get()).unwrap())
854 }
855 pub(super) fn type_id(&self) -> TypeId {
856 TypeId(NonZeroU32::new(self.metadata.context_type.get()).unwrap())
857 }
858 pub(super) fn low_level(&self) -> &MlsLevel {
859 self.mls_range.low()
860 }
861 pub(super) fn high_level(&self) -> &Option<MlsLevel> {
862 self.mls_range.high()
863 }
864}
865
866impl Parse for Context
867where
868 MlsRange: Parse,
869{
870 type Error = anyhow::Error;
871
872 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
873 let tail = bytes;
874
875 let (metadata, tail) =
876 PolicyCursor::parse::<ContextMetadata>(tail).context("parsing metadata for context")?;
877
878 let (mls_range, tail) = MlsRange::parse(tail)
879 .map_err(Into::<anyhow::Error>::into)
880 .context("parsing mls range for context")?;
881
882 Ok((Self { metadata, mls_range }, tail))
883 }
884}
885
886#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
887#[repr(C, packed)]
888pub(super) struct ContextMetadata {
889 user: le::U32,
890 role: le::U32,
891 context_type: le::U32,
892}
893
894impl Validate for NamedContextPair {
895 type Error = anyhow::Error;
896
897 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
902 Ok(())
903 }
904}
905
906#[derive(Debug, PartialEq)]
907pub(super) struct NamedContextPair {
908 name: SimpleArray<u8>,
909 context1: Context,
910 context2: Context,
911}
912
913impl Parse for NamedContextPair
914where
915 SimpleArray<u8>: Parse,
916 Context: Parse,
917{
918 type Error = anyhow::Error;
919
920 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
921 let tail = bytes;
922
923 let (name, tail) = SimpleArray::parse(tail)
924 .map_err(Into::<anyhow::Error>::into)
925 .context("parsing filesystem context name")?;
926
927 let (context1, tail) = Context::parse(tail)
928 .map_err(Into::<anyhow::Error>::into)
929 .context("parsing first context for filesystem context")?;
930
931 let (context2, tail) = Context::parse(tail)
932 .map_err(Into::<anyhow::Error>::into)
933 .context("parsing second context for filesystem context")?;
934
935 Ok((Self { name, context1, context2 }, tail))
936 }
937}
938
939impl Validate for Port {
940 type Error = anyhow::Error;
941
942 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
944 Ok(())
945 }
946}
947
948#[derive(Debug, PartialEq)]
949pub(super) struct Port {
950 metadata: PortMetadata,
951 context: Context,
952}
953
954impl Parse for Port
955where
956 Context: Parse,
957{
958 type Error = anyhow::Error;
959
960 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
961 let tail = bytes;
962
963 let (metadata, tail) =
964 PolicyCursor::parse::<PortMetadata>(tail).context("parsing metadata for context")?;
965
966 let (context, tail) = Context::parse(tail)
967 .map_err(Into::<anyhow::Error>::into)
968 .context("parsing context for port")?;
969
970 Ok((Self { metadata, context }, tail))
971 }
972}
973
974#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
975#[repr(C, packed)]
976pub(super) struct PortMetadata {
977 protocol: le::U32,
978 low_port: le::U32,
979 high_port: le::U32,
980}
981
982impl Validate for Node {
983 type Error = anyhow::Error;
984
985 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
987 Ok(())
988 }
989}
990
991#[derive(Debug, PartialEq)]
992pub(super) struct Node {
993 address: le::U32,
994 mask: le::U32,
995 context: Context,
996}
997
998impl Parse for Node
999where
1000 Context: Parse,
1001{
1002 type Error = anyhow::Error;
1003
1004 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1005 let tail = bytes;
1006
1007 let (address, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1008
1009 let (mask, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1010
1011 let (context, tail) = Context::parse(tail)
1012 .map_err(Into::<anyhow::Error>::into)
1013 .context("parsing context for node")?;
1014
1015 Ok((Self { address, mask, context }, tail))
1016 }
1017}
1018
1019#[derive(Debug, PartialEq)]
1020pub(super) struct FsUse {
1021 behavior_and_name: Array<FsUseMetadata, u8>,
1022 context: Context,
1023}
1024
1025impl FsUse {
1026 pub fn fs_type(&self) -> &[u8] {
1027 &self.behavior_and_name.data
1028 }
1029
1030 pub(super) fn behavior(&self) -> FsUseType {
1031 FsUseType::try_from(self.behavior_and_name.metadata.behavior).unwrap()
1032 }
1033
1034 pub(super) fn context(&self) -> &Context {
1035 &self.context
1036 }
1037}
1038
1039impl Parse for FsUse
1040where
1041 Array<FsUseMetadata, u8>: Parse,
1042 Context: Parse,
1043{
1044 type Error = anyhow::Error;
1045
1046 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1047 let tail = bytes;
1048
1049 let (behavior_and_name, tail) = Array::<FsUseMetadata, u8>::parse(tail)
1050 .map_err(Into::<anyhow::Error>::into)
1051 .context("parsing fs use metadata")?;
1052
1053 let (context, tail) = Context::parse(tail)
1054 .map_err(Into::<anyhow::Error>::into)
1055 .context("parsing context for fs use")?;
1056
1057 Ok((Self { behavior_and_name, context }, tail))
1058 }
1059}
1060
1061impl Validate for FsUse {
1062 type Error = anyhow::Error;
1063
1064 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1065 FsUseType::try_from(self.behavior_and_name.metadata.behavior)?;
1066
1067 Ok(())
1068 }
1069}
1070
1071#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1072#[repr(C, packed)]
1073pub(super) struct FsUseMetadata {
1074 behavior: le::U32,
1076 name_length: le::U32,
1078}
1079
1080impl Counted for FsUseMetadata {
1081 fn count(&self) -> u32 {
1082 self.name_length.get()
1083 }
1084}
1085
1086#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
1089pub enum FsUseType {
1090 Xattr = 1,
1091 Trans = 2,
1092 Task = 3,
1093}
1094
1095impl TryFrom<le::U32> for FsUseType {
1096 type Error = anyhow::Error;
1097
1098 fn try_from(value: le::U32) -> Result<Self, Self::Error> {
1099 match value.get() {
1100 1 => Ok(FsUseType::Xattr),
1101 2 => Ok(FsUseType::Trans),
1102 3 => Ok(FsUseType::Task),
1103 _ => Err(ValidateError::InvalidFsUseType { value: value.get() }.into()),
1104 }
1105 }
1106}
1107
1108impl Validate for IPv6Node {
1109 type Error = anyhow::Error;
1110
1111 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1113 Ok(())
1114 }
1115}
1116
1117#[derive(Debug, PartialEq)]
1118pub(super) struct IPv6Node {
1119 address: [le::U32; 4],
1120 mask: [le::U32; 4],
1121 context: Context,
1122}
1123
1124impl Parse for IPv6Node
1125where
1126 Context: Parse,
1127{
1128 type Error = anyhow::Error;
1129
1130 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1131 let tail = bytes;
1132
1133 let (address, tail) = PolicyCursor::parse::<[le::U32; 4]>(tail)?;
1134
1135 let (mask, tail) = PolicyCursor::parse::<[le::U32; 4]>(tail)?;
1136
1137 let (context, tail) = Context::parse(tail)
1138 .map_err(Into::<anyhow::Error>::into)
1139 .context("parsing context for ipv6 node")?;
1140
1141 Ok((Self { address, mask, context }, tail))
1142 }
1143}
1144
1145impl Validate for InfinitiBandPartitionKey {
1146 type Error = anyhow::Error;
1147
1148 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1150 Ok(())
1151 }
1152}
1153
1154#[derive(Debug, PartialEq)]
1155pub(super) struct InfinitiBandPartitionKey {
1156 low: le::U32,
1157 high: le::U32,
1158 context: Context,
1159}
1160
1161impl Parse for InfinitiBandPartitionKey
1162where
1163 Context: Parse,
1164{
1165 type Error = anyhow::Error;
1166
1167 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1168 let tail = bytes;
1169
1170 let (low, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1171
1172 let (high, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1173
1174 let (context, tail) = Context::parse(tail)
1175 .map_err(Into::<anyhow::Error>::into)
1176 .context("parsing context for infiniti band partition key")?;
1177
1178 Ok((Self { low, high, context }, tail))
1179 }
1180}
1181
1182impl Validate for InfinitiBandEndPort {
1183 type Error = anyhow::Error;
1184
1185 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1187 Ok(())
1188 }
1189}
1190
1191#[derive(Debug, PartialEq)]
1192pub(super) struct InfinitiBandEndPort {
1193 port_and_name: Array<InfinitiBandEndPortMetadata, u8>,
1194 context: Context,
1195}
1196
1197impl Parse for InfinitiBandEndPort
1198where
1199 Array<InfinitiBandEndPortMetadata, u8>: Parse,
1200 Context: Parse,
1201{
1202 type Error = anyhow::Error;
1203
1204 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1205 let tail = bytes;
1206
1207 let (port_and_name, tail) = Array::<InfinitiBandEndPortMetadata, u8>::parse(tail)
1208 .map_err(Into::<anyhow::Error>::into)
1209 .context("parsing infiniti band end port metadata")?;
1210
1211 let (context, tail) = Context::parse(tail)
1212 .map_err(Into::<anyhow::Error>::into)
1213 .context("parsing context for infiniti band end port")?;
1214
1215 Ok((Self { port_and_name, context }, tail))
1216 }
1217}
1218
1219#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1220#[repr(C, packed)]
1221pub(super) struct InfinitiBandEndPortMetadata {
1222 length: le::U32,
1223 port: le::U32,
1224}
1225
1226impl Counted for InfinitiBandEndPortMetadata {
1227 fn count(&self) -> u32 {
1228 self.length.get()
1229 }
1230}
1231
1232impl Validate for GenericFsContext {
1233 type Error = anyhow::Error;
1234
1235 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1237 Ok(())
1238 }
1239}
1240
1241#[derive(Debug)]
1244pub(super) struct GenericFsContext {
1245 fs_type: SimpleArray<u8>,
1246 fs_context: SimpleArrayView<FsContext>,
1247}
1248
1249impl GenericFsContext {
1250 pub(super) fn for_query(fs_type: &str) -> SimpleArray<u8> {
1252 Array { data: fs_type.as_bytes().to_vec(), metadata: le::U32::new(fs_type.len() as u32) }
1253 }
1254}
1255
1256impl Parse for GenericFsContext {
1257 type Error = anyhow::Error;
1258
1259 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1260 let tail = bytes;
1261
1262 let (fs_type, tail) = SimpleArray::<u8>::parse(tail)
1263 .map_err(Into::<anyhow::Error>::into)
1264 .context("parsing fs_type for generic fs context")?;
1265
1266 let (fs_context, tail) = SimpleArrayView::<FsContext>::parse(tail)
1267 .map_err(Into::<anyhow::Error>::into)
1268 .context("parsing fs_context for generic fs context")?;
1269
1270 Ok((Self { fs_type, fs_context }, tail))
1271 }
1272}
1273
1274impl Hashable for GenericFsContext {
1275 type Key = SimpleArray<u8>;
1276 type Value = FsContext;
1277
1278 fn key(&self) -> &Self::Key {
1279 &self.fs_type
1280 }
1281
1282 fn values(&self) -> &SimpleArrayView<Self::Value> {
1283 &self.fs_context
1284 }
1285}
1286
1287impl Eq for SimpleArray<u8> {}
1288
1289impl Hash for SimpleArray<u8> {
1290 fn hash<H: Hasher>(&self, state: &mut H) {
1291 self.data.hash(state);
1292 }
1293}
1294
1295impl SimpleArrayView<FsContext> {
1296 fn try_validate_alphabetic_order(&self, context: &PolicyValidationContext) -> bool {
1297 self.data()
1298 .iter(&context.data)
1299 .map(|view| view.parse(&context.data).partial_path().to_vec())
1300 .is_sorted_by(|a, b| a <= b)
1301 }
1302
1303 fn try_validate_length_descending_order(&self, context: &PolicyValidationContext) -> bool {
1304 self.data()
1305 .iter(&context.data)
1306 .map(|view| view.parse(&context.data).partial_path().len())
1307 .is_sorted_by(|a, b| a >= b)
1308 }
1309}
1310
1311impl Validate for SimpleArrayView<FsContext> {
1312 type Error = anyhow::Error;
1313
1314 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
1319 if !self.try_validate_alphabetic_order(context)
1320 && !self.try_validate_length_descending_order(context)
1321 {
1322 return Err(anyhow::anyhow!(
1323 "FsContexts must be sorted by partial path length (descending) or alphabetically.",
1324 ));
1325 }
1326 Ok(())
1327 }
1328}
1329
1330#[derive(Debug, PartialEq)]
1331pub(super) struct FsContext {
1332 partial_path: SimpleArray<u8>,
1335 class: le::U32,
1339 context: Context,
1341}
1342
1343impl FsContext {
1344 pub(super) fn partial_path(&self) -> &[u8] {
1345 &self.partial_path.data
1346 }
1347
1348 pub(super) fn context(&self) -> &Context {
1349 &self.context
1350 }
1351
1352 pub(super) fn class(&self) -> Option<ClassId> {
1353 NonZeroU32::new(self.class.into()).map(ClassId)
1354 }
1355}
1356
1357impl Parse for FsContext
1358where
1359 SimpleArray<u8>: Parse,
1360 Context: Parse,
1361{
1362 type Error = anyhow::Error;
1363
1364 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1365 let tail = bytes;
1366
1367 let (partial_path, tail) = SimpleArray::<u8>::parse(tail)
1368 .map_err(Into::<anyhow::Error>::into)
1369 .context("parsing filesystem context partial path")?;
1370
1371 let (class, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1372
1373 let (context, tail) = Context::parse(tail)
1374 .map_err(Into::<anyhow::Error>::into)
1375 .context("parsing context for filesystem context")?;
1376
1377 Ok((Self { partial_path, class, context }, tail))
1378 }
1379}
1380
1381impl Walk for FsContext {
1382 fn walk(policy_data: &PolicyData, offset: PolicyOffset) -> PolicyOffset {
1383 let cursor = PolicyCursor::new_at(policy_data, offset);
1384 let (_, tail) = FsContext::parse(cursor)
1385 .map_err(Into::<anyhow::Error>::into)
1386 .expect("policy should be valid");
1387 tail.offset()
1388 }
1389}
1390
1391impl Validate for RangeTransition {
1392 type Error = anyhow::Error;
1393 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1394 if self.metadata.target_class.get() == 0 {
1395 return Err(ValidateError::NonOptionalIdIsZero.into());
1396 }
1397 Ok(())
1398 }
1399}
1400
1401#[derive(Debug, PartialEq)]
1402pub(super) struct RangeTransition {
1403 metadata: RangeTransitionMetadata,
1404 mls_range: MlsRange,
1405}
1406
1407impl RangeTransition {
1408 pub fn source_type(&self) -> TypeId {
1409 TypeId(NonZeroU32::new(self.metadata.source_type.get()).unwrap())
1410 }
1411
1412 pub fn target_type(&self) -> TypeId {
1413 TypeId(NonZeroU32::new(self.metadata.target_type.get()).unwrap())
1414 }
1415
1416 pub fn target_class(&self) -> ClassId {
1417 ClassId(NonZeroU32::new(self.metadata.target_class.get()).unwrap())
1418 }
1419
1420 pub fn mls_range(&self) -> &MlsRange {
1421 &self.mls_range
1422 }
1423}
1424
1425impl Parse for RangeTransition
1426where
1427 MlsRange: Parse,
1428{
1429 type Error = anyhow::Error;
1430
1431 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1432 let tail = bytes;
1433
1434 let (metadata, tail) = PolicyCursor::parse::<RangeTransitionMetadata>(tail)
1435 .context("parsing range transition metadata")?;
1436
1437 let (mls_range, tail) = MlsRange::parse(tail)
1438 .map_err(Into::<anyhow::Error>::into)
1439 .context("parsing mls range for range transition")?;
1440
1441 Ok((Self { metadata, mls_range }, tail))
1442 }
1443}
1444
1445#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1446#[repr(C, packed)]
1447pub(super) struct RangeTransitionMetadata {
1448 source_type: le::U32,
1449 target_type: le::U32,
1450 target_class: le::U32,
1451}
1452
1453#[cfg(test)]
1454pub(super) mod testing {
1455 use super::AccessVectorRule;
1456 use std::cmp::Ordering;
1457
1458 pub(in super::super) fn access_vector_rule_ordering(
1459 left: &AccessVectorRule,
1460 right: &AccessVectorRule,
1461 ) -> Ordering {
1462 (
1463 left.metadata.source_type,
1464 left.metadata.target_type,
1465 left.metadata.class,
1466 left.metadata.access_vector_rule_type,
1467 )
1468 .cmp(&(
1469 right.metadata.source_type,
1470 right.metadata.target_type,
1471 right.metadata.class,
1472 right.metadata.access_vector_rule_type,
1473 ))
1474 }
1475}
1476
1477#[cfg(test)]
1478mod tests {
1479 use super::super::{ClassId, find_class_by_name, parse_policy_by_value};
1480 use super::{
1481 ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM, ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM,
1482 ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES,
1483 XPERMS_TYPE_IOCTL_PREFIXES, XPERMS_TYPE_NLMSG,
1484 };
1485 use std::num::NonZeroU32;
1486
1487 impl super::AccessVectorRuleMetadata {
1488 pub fn is_allowxperm(&self) -> bool {
1492 (self.access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM) != 0
1493 }
1494
1495 pub fn is_auditallowxperm(&self) -> bool {
1499 (self.access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM) != 0
1500 }
1501
1502 pub fn is_dontauditxperm(&self) -> bool {
1506 (self.access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM) != 0
1507 }
1508
1509 pub fn target_class(&self) -> ClassId {
1514 ClassId(NonZeroU32::new(self.class.into()).unwrap())
1515 }
1516 }
1517
1518 #[test]
1519 fn parse_allowxperm_one_ioctl() {
1520 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1521 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1522 let parsed_policy = &policy.0;
1523 parsed_policy.validate().expect("validate policy");
1524
1525 let class_id = find_class_by_name(&parsed_policy.classes(), "class_one_ioctl")
1526 .expect("look up class_one_ioctl")
1527 .id();
1528
1529 let rules: Vec<_> = parsed_policy
1530 .access_vector_rules_for_test()
1531 .filter(|rule| rule.metadata.target_class() == class_id)
1532 .collect();
1533
1534 assert_eq!(rules.len(), 1);
1535 assert!(rules[0].metadata.is_allowxperm());
1536 if let Some(xperms) = rules[0].extended_permissions() {
1537 assert_eq!(xperms.count(), 1);
1538 assert!(xperms.contains(0xabcd));
1539 } else {
1540 panic!("unexpected permission data type")
1541 }
1542 }
1543
1544 #[test]
1547 fn parse_allowxperm_two_ioctls_same_range() {
1548 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1549 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1550 let parsed_policy = &policy.0;
1551 parsed_policy.validate().expect("validate policy");
1552
1553 let class_id = find_class_by_name(&parsed_policy.classes(), "class_two_ioctls_same_range")
1554 .expect("look up class_two_ioctls_same_range")
1555 .id();
1556
1557 let rules: Vec<_> = parsed_policy
1558 .access_vector_rules_for_test()
1559 .filter(|rule| rule.metadata.target_class() == class_id)
1560 .collect();
1561
1562 assert_eq!(rules.len(), 1);
1563 assert!(rules[0].metadata.is_allowxperm());
1564 if let Some(xperms) = rules[0].extended_permissions() {
1565 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1566 assert_eq!(xperms.xperms_optional_prefix, 0x12);
1567 assert_eq!(xperms.count(), 2);
1568 assert!(xperms.contains(0x1234));
1569 assert!(xperms.contains(0x1256));
1570 } else {
1571 panic!("unexpected permission data type")
1572 }
1573 }
1574
1575 #[test]
1578 fn parse_allowxperm_two_ioctls_same_range_diff_rules() {
1579 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1580 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1581 let parsed_policy = &policy.0;
1582 parsed_policy.validate().expect("validate policy");
1583
1584 let class_id =
1585 find_class_by_name(&parsed_policy.classes(), "class_four_ioctls_same_range_diff_rules")
1586 .expect("look up class_four_ioctls_same_range_diff_rules")
1587 .id();
1588
1589 let rules: Vec<_> = parsed_policy
1590 .access_vector_rules_for_test()
1591 .filter(|rule| rule.metadata.target_class() == class_id)
1592 .collect();
1593
1594 assert_eq!(rules.len(), 1);
1595 assert!(rules[0].metadata.is_allowxperm());
1596 if let Some(xperms) = rules[0].extended_permissions() {
1597 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1598 assert_eq!(xperms.xperms_optional_prefix, 0x30);
1599 assert_eq!(xperms.count(), 4);
1600 assert!(xperms.contains(0x3008));
1601 assert!(xperms.contains(0x3009));
1602 assert!(xperms.contains(0x3011));
1603 assert!(xperms.contains(0x3013));
1604 } else {
1605 panic!("unexpected permission data type")
1606 }
1607 }
1608
1609 #[test]
1612 fn parse_allowxperm_two_ioctls_different_range() {
1613 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1614 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1615 let parsed_policy = &policy.0;
1616 parsed_policy.validate().expect("validate policy");
1617
1618 let class_id = find_class_by_name(&parsed_policy.classes(), "class_two_ioctls_diff_range")
1619 .expect("look up class_two_ioctls_diff_range")
1620 .id();
1621
1622 let rules: Vec<_> = parsed_policy
1623 .access_vector_rules_for_test()
1624 .filter(|rule| rule.metadata.target_class() == class_id)
1625 .collect();
1626
1627 assert_eq!(rules.len(), 2);
1628 assert!(rules[0].metadata.is_allowxperm());
1629 if let Some(xperms) = rules[0].extended_permissions() {
1630 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1631 assert_eq!(xperms.xperms_optional_prefix, 0x56);
1632 assert_eq!(xperms.count(), 1);
1633 assert!(xperms.contains(0x5678));
1634 } else {
1635 panic!("unexpected permission data type")
1636 }
1637 assert!(rules[1].metadata.is_allowxperm());
1638 if let Some(xperms) = rules[1].extended_permissions() {
1639 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1640 assert_eq!(xperms.xperms_optional_prefix, 0x12);
1641 assert_eq!(xperms.count(), 1);
1642 assert!(xperms.contains(0x1234));
1643 } else {
1644 panic!("unexpected permission data type")
1645 }
1646 }
1647
1648 #[test]
1651 fn parse_allowxperm_one_driver_range() {
1652 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1653 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1654 let parsed_policy = &policy.0;
1655 parsed_policy.validate().expect("validate policy");
1656
1657 let class_id = find_class_by_name(&parsed_policy.classes(), "class_one_driver_range")
1658 .expect("look up class_one_driver_range")
1659 .id();
1660
1661 let rules: Vec<_> = parsed_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 parsed_policy = &policy.0;
1686 parsed_policy.validate().expect("validate policy");
1687
1688 let class_id = find_class_by_name(&parsed_policy.classes(), "class_most_ioctls")
1689 .expect("look up class_most_ioctls")
1690 .id();
1691
1692 let rules: Vec<_> = parsed_policy
1693 .access_vector_rules_for_test()
1694 .filter(|rule| rule.metadata.target_class() == class_id)
1695 .collect();
1696
1697 assert_eq!(rules.len(), 3);
1698 assert!(rules[0].metadata.is_allowxperm());
1699 if let Some(xperms) = rules[0].extended_permissions() {
1700 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1701 assert_eq!(xperms.xperms_optional_prefix, 0xff);
1702 assert_eq!(xperms.count(), 0xfe);
1703 for xperm in 0xff00..0xfffd {
1704 assert!(xperms.contains(xperm));
1705 }
1706 } else {
1707 panic!("unexpected permission data type")
1708 }
1709 if let Some(xperms) = rules[1].extended_permissions() {
1710 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1711 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1712 assert_eq!(xperms.count(), 0xfe);
1713 for xperm in 0x0002..0x0100 {
1714 assert!(xperms.contains(xperm));
1715 }
1716 } else {
1717 panic!("unexpected permission data type")
1718 }
1719 if let Some(xperms) = rules[2].extended_permissions() {
1720 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1721 assert_eq!(xperms.count(), 0xfe00);
1722 for xperm in 0x0100..0xff00 {
1723 assert!(xperms.contains(xperm));
1724 }
1725 } else {
1726 panic!("unexpected permission data type")
1727 }
1728 }
1729
1730 #[test]
1734 fn parse_allowxperm_most_ioctls_with_hole() {
1735 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1736 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1737 let parsed_policy = &policy.0;
1738 parsed_policy.validate().expect("validate policy");
1739
1740 let class_id = find_class_by_name(&parsed_policy.classes(), "class_most_ioctls_with_hole")
1741 .expect("look up class_most_ioctls_with_hole")
1742 .id();
1743
1744 let rules: Vec<_> = parsed_policy
1745 .access_vector_rules_for_test()
1746 .filter(|rule| rule.metadata.target_class() == class_id)
1747 .collect();
1748
1749 assert_eq!(rules.len(), 5);
1750 assert!(rules[0].metadata.is_allowxperm());
1751 if let Some(xperms) = rules[0].extended_permissions() {
1752 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1753 assert_eq!(xperms.xperms_optional_prefix, 0xff);
1754 assert_eq!(xperms.count(), 0xfe);
1755 for xperm in 0xff00..0xfffd {
1756 assert!(xperms.contains(xperm));
1757 }
1758 } else {
1759 panic!("unexpected permission data type")
1760 }
1761 if let Some(xperms) = rules[1].extended_permissions() {
1762 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1763 assert_eq!(xperms.xperms_optional_prefix, 0x40);
1764 assert_eq!(xperms.count(), 0xfe);
1765 for xperm in 0x4002..0x4100 {
1766 assert!(xperms.contains(xperm));
1767 }
1768 } else {
1769 panic!("unexpected permission data type")
1770 }
1771 assert!(rules[0].metadata.is_allowxperm());
1772 if let Some(xperms) = rules[2].extended_permissions() {
1773 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1774 assert_eq!(xperms.xperms_optional_prefix, 0x2f);
1775 assert_eq!(xperms.count(), 0xfe);
1776 for xperm in 0x2f00..0x2ffd {
1777 assert!(xperms.contains(xperm));
1778 }
1779 } else {
1780 panic!("unexpected permission data type")
1781 }
1782 if let Some(xperms) = rules[3].extended_permissions() {
1783 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1784 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1785 assert_eq!(xperms.count(), 0xfe);
1786 for xperm in 0x0002..0x0100 {
1787 assert!(xperms.contains(xperm));
1788 }
1789 } else {
1790 panic!("unexpected permission data type")
1791 }
1792 if let Some(xperms) = rules[4].extended_permissions() {
1793 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1794 assert_eq!(xperms.count(), 0xec00);
1795 for xperm in 0x0100..0x2f00 {
1796 assert!(xperms.contains(xperm));
1797 }
1798 for xperm in 0x4100..0xff00 {
1799 assert!(xperms.contains(xperm));
1800 }
1801 } else {
1802 panic!("unexpected permission data type")
1803 }
1804 }
1805
1806 #[test]
1811 fn parse_allowxperm_all_ioctls() {
1812 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1813 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1814 let parsed_policy = &policy.0;
1815 parsed_policy.validate().expect("validate policy");
1816
1817 let class_id = find_class_by_name(&parsed_policy.classes(), "class_all_ioctls")
1818 .expect("look up class_all_ioctls")
1819 .id();
1820
1821 let rules: Vec<_> = parsed_policy
1822 .access_vector_rules_for_test()
1823 .filter(|rule| rule.metadata.target_class() == class_id)
1824 .collect();
1825
1826 assert_eq!(rules.len(), 1);
1827 assert!(rules[0].metadata.is_allowxperm());
1828 if let Some(xperms) = rules[0].extended_permissions() {
1829 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1830 assert_eq!(xperms.count(), 0x10000);
1831 } else {
1832 panic!("unexpected permission data type")
1833 }
1834 }
1835
1836 #[test]
1837 fn parse_allowxperm_one_nlmsg() {
1838 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1839 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1840 let parsed_policy = &policy.0;
1841 parsed_policy.validate().expect("validate policy");
1842
1843 let class_id = find_class_by_name(&parsed_policy.classes(), "class_one_nlmsg")
1844 .expect("look up class_one_nlmsg")
1845 .id();
1846
1847 let rules: Vec<_> = parsed_policy
1848 .access_vector_rules_for_test()
1849 .filter(|rule| rule.metadata.target_class() == class_id)
1850 .collect();
1851
1852 assert_eq!(rules.len(), 1);
1853 assert!(rules[0].metadata.is_allowxperm());
1854 if let Some(xperms) = rules[0].extended_permissions() {
1855 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1856 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1857 assert_eq!(xperms.count(), 1);
1858 assert!(xperms.contains(0x12));
1859 } else {
1860 panic!("unexpected permission data type")
1861 }
1862 }
1863
1864 #[test]
1867 fn parse_allowxperm_two_nlmsg_same_range() {
1868 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1869 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1870 let parsed_policy = &policy.0;
1871 parsed_policy.validate().expect("validate policy");
1872
1873 let class_id = find_class_by_name(&parsed_policy.classes(), "class_two_nlmsg_same_range")
1874 .expect("look up class_two_nlmsg_same_range")
1875 .id();
1876
1877 let rules: Vec<_> = parsed_policy
1878 .access_vector_rules_for_test()
1879 .filter(|rule| rule.metadata.target_class() == class_id)
1880 .collect();
1881
1882 assert_eq!(rules.len(), 1);
1883 assert!(rules[0].metadata.is_allowxperm());
1884 if let Some(xperms) = rules[0].extended_permissions() {
1885 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1886 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1887 assert_eq!(xperms.count(), 2);
1888 assert!(xperms.contains(0x12));
1889 assert!(xperms.contains(0x24));
1890 } else {
1891 panic!("unexpected permission data type")
1892 }
1893 }
1894
1895 #[test]
1898 fn parse_allowxperm_two_nlmsg_different_range() {
1899 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1900 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1901 let parsed_policy = &policy.0;
1902 parsed_policy.validate().expect("validate policy");
1903
1904 let class_id = find_class_by_name(&parsed_policy.classes(), "class_two_nlmsg_diff_range")
1905 .expect("look up class_two_nlmsg_diff_range")
1906 .id();
1907
1908 let rules: Vec<_> = parsed_policy
1909 .access_vector_rules_for_test()
1910 .filter(|rule| rule.metadata.target_class() == class_id)
1911 .collect();
1912
1913 assert_eq!(rules.len(), 2);
1914 assert!(rules[0].metadata.is_allowxperm());
1915 if let Some(xperms) = rules[0].extended_permissions() {
1916 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1917 assert_eq!(xperms.xperms_optional_prefix, 0x10);
1918 assert_eq!(xperms.count(), 1);
1919 assert!(xperms.contains(0x1024));
1920 } else {
1921 panic!("unexpected permission data type")
1922 }
1923 assert!(rules[1].metadata.is_allowxperm());
1924 if let Some(xperms) = rules[1].extended_permissions() {
1925 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1926 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1927 assert_eq!(xperms.count(), 1);
1928 assert!(xperms.contains(0x12));
1929 } else {
1930 panic!("unexpected permission data type")
1931 }
1932 }
1933
1934 #[test]
1937 fn parse_allowxperm_one_nlmsg_range() {
1938 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1939 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1940 let parsed_policy = &policy.0;
1941 parsed_policy.validate().expect("validate policy");
1942
1943 let class_id = find_class_by_name(&parsed_policy.classes(), "class_one_nlmsg_range")
1944 .expect("look up class_one_nlmsg_range")
1945 .id();
1946
1947 let rules: Vec<_> = parsed_policy
1948 .access_vector_rules_for_test()
1949 .filter(|rule| rule.metadata.target_class() == class_id)
1950 .collect();
1951
1952 assert_eq!(rules.len(), 1);
1953 assert!(rules[0].metadata.is_allowxperm());
1954 if let Some(xperms) = rules[0].extended_permissions() {
1955 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1956 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1957 assert_eq!(xperms.count(), 0x100);
1958 for i in 0x0..0xff {
1959 assert!(xperms.contains(i), "{i}");
1960 }
1961 } else {
1962 panic!("unexpected permission data type")
1963 }
1964 }
1965
1966 #[test]
1972 fn parse_allowxperm_two_nlmsg_ranges() {
1973 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
1974 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1975 let parsed_policy = &policy.0;
1976 parsed_policy.validate().expect("validate policy");
1977
1978 let class_id = find_class_by_name(&parsed_policy.classes(), "class_two_nlmsg_ranges")
1979 .expect("look up class_two_nlmsg_ranges")
1980 .id();
1981
1982 let rules: Vec<_> = parsed_policy
1983 .access_vector_rules_for_test()
1984 .filter(|rule| rule.metadata.target_class() == class_id)
1985 .collect();
1986
1987 assert_eq!(rules.len(), 2);
1988 assert!(rules[0].metadata.is_allowxperm());
1989 if let Some(xperms) = rules[0].extended_permissions() {
1990 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1991 assert_eq!(xperms.xperms_optional_prefix, 0x01);
1992 assert_eq!(xperms.count(), 0x100);
1993 for i in 0x0100..0x01ff {
1994 assert!(xperms.contains(i), "{i}");
1995 }
1996 } else {
1997 panic!("unexpected permission data type")
1998 }
1999 if let Some(xperms) = rules[1].extended_permissions() {
2000 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2001 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2002 assert_eq!(xperms.count(), 0x100);
2003 for i in 0x0..0xff {
2004 assert!(xperms.contains(i), "{i}");
2005 }
2006 } else {
2007 panic!("unexpected permission data type")
2008 }
2009 }
2010
2011 #[test]
2018 fn parse_allowxperm_three_separate_nlmsg_ranges() {
2019 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
2020 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2021 let parsed_policy = &policy.0;
2022 parsed_policy.validate().expect("validate policy");
2023
2024 let class_id =
2025 find_class_by_name(&parsed_policy.classes(), "class_three_separate_nlmsg_ranges")
2026 .expect("look up class_three_separate_nlmsg_ranges")
2027 .id();
2028
2029 let rules: Vec<_> = parsed_policy
2030 .access_vector_rules_for_test()
2031 .filter(|rule| rule.metadata.target_class() == class_id)
2032 .collect();
2033
2034 assert_eq!(rules.len(), 3);
2035 assert!(rules[0].metadata.is_allowxperm());
2036 if let Some(xperms) = rules[0].extended_permissions() {
2037 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2038 assert_eq!(xperms.xperms_optional_prefix, 0x20);
2039 assert_eq!(xperms.count(), 0x100);
2040 for i in 0x2000..0x20ff {
2041 assert!(xperms.contains(i), "{i}");
2042 }
2043 } else {
2044 panic!("unexpected permission data type")
2045 }
2046 if let Some(xperms) = rules[1].extended_permissions() {
2047 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2048 assert_eq!(xperms.xperms_optional_prefix, 0x10);
2049 assert_eq!(xperms.count(), 0x100);
2050 for i in 0x1000..0x10ff {
2051 assert!(xperms.contains(i), "{i}");
2052 }
2053 } else {
2054 panic!("unexpected permission data type")
2055 }
2056 if let Some(xperms) = rules[2].extended_permissions() {
2057 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2058 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2059 assert_eq!(xperms.count(), 0x100);
2060 for i in 0x0..0xff {
2061 assert!(xperms.contains(i), "{i}");
2062 }
2063 } else {
2064 panic!("unexpected permission data type")
2065 }
2066 }
2067
2068 #[test]
2075 fn parse_allowxperm_three_contiguous_nlmsg_ranges() {
2076 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
2077 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2078 let parsed_policy = &policy.0;
2079 parsed_policy.validate().expect("validate policy");
2080
2081 let class_id =
2082 find_class_by_name(&parsed_policy.classes(), "class_three_contiguous_nlmsg_ranges")
2083 .expect("look up class_three_contiguous_nlmsg_ranges")
2084 .id();
2085
2086 let rules: Vec<_> = parsed_policy
2087 .access_vector_rules_for_test()
2088 .filter(|rule| rule.metadata.target_class() == class_id)
2089 .collect();
2090
2091 assert_eq!(rules.len(), 2);
2092 assert!(rules[0].metadata.is_allowxperm());
2093 if let Some(xperms) = rules[0].extended_permissions() {
2094 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2095 assert_eq!(xperms.xperms_optional_prefix, 0x02);
2096 assert_eq!(xperms.count(), 0x100);
2097 for i in 0x0200..0x02ff {
2098 assert!(xperms.contains(i), "{i}");
2099 }
2100 } else {
2101 panic!("unexpected permission data type")
2102 }
2103 if let Some(xperms) = rules[1].extended_permissions() {
2104 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2105 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2106 assert_eq!(xperms.count(), 0x100);
2107 for i in 0x0..0xff {
2108 assert!(xperms.contains(i), "{i}");
2109 }
2110 } else {
2111 panic!("unexpected permission data type")
2112 }
2113 }
2114
2115 #[test]
2118 fn parse_auditallowxperm() {
2119 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
2120 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2121 let parsed_policy = &policy.0;
2122 parsed_policy.validate().expect("validate policy");
2123
2124 let class_id = find_class_by_name(&parsed_policy.classes(), "class_auditallowxperm")
2125 .expect("look up class_auditallowxperm")
2126 .id();
2127
2128 let rules: Vec<_> = parsed_policy
2129 .access_vector_rules_for_test()
2130 .filter(|rule| rule.metadata.target_class() == class_id)
2131 .collect();
2132
2133 assert_eq!(rules.len(), 2);
2134 assert!(rules[0].metadata.is_auditallowxperm());
2135 if let Some(xperms) = rules[0].extended_permissions() {
2136 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2137 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2138 assert_eq!(xperms.count(), 1);
2139 assert!(xperms.contains(0x10));
2140 } else {
2141 panic!("unexpected permission data type")
2142 }
2143 if let Some(xperms) = rules[1].extended_permissions() {
2144 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
2145 assert_eq!(xperms.xperms_optional_prefix, 0x10);
2146 assert_eq!(xperms.count(), 1);
2147 assert!(xperms.contains(0x1000));
2148 } else {
2149 panic!("unexpected permission data type")
2150 }
2151 }
2152
2153 #[test]
2161 fn parse_dontauditxperm() {
2162 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
2163 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2164 let parsed_policy = &policy.0;
2165 parsed_policy.validate().expect("validate policy");
2166
2167 let class_id = find_class_by_name(&parsed_policy.classes(), "class_dontauditxperm")
2168 .expect("look up class_dontauditxperm")
2169 .id();
2170
2171 let rules: Vec<_> = parsed_policy
2172 .access_vector_rules_for_test()
2173 .filter(|rule| rule.metadata.target_class() == class_id)
2174 .collect();
2175
2176 assert_eq!(rules.len(), 2);
2177 assert!(rules[0].metadata.is_dontauditxperm());
2178 if let Some(xperms) = rules[0].extended_permissions() {
2179 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2180 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2181 assert_eq!(xperms.count(), 1);
2182 assert!(xperms.contains(0x11));
2183 } else {
2184 panic!("unexpected permission data type")
2185 }
2186 if let Some(xperms) = rules[1].extended_permissions() {
2187 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
2188 assert_eq!(xperms.xperms_optional_prefix, 0x10);
2189 assert_eq!(xperms.count(), 1);
2190 assert!(xperms.contains(0x1000));
2191 } else {
2192 panic!("unexpected permission data type")
2193 }
2194 }
2195
2196 #[test]
2200 fn parse_auditallowxperm_not_coalesced() {
2201 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy");
2202 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2203 let parsed_policy = &policy.0;
2204 parsed_policy.validate().expect("validate policy");
2205
2206 let class_id =
2207 find_class_by_name(&parsed_policy.classes(), "class_auditallowxperm_not_coalesced")
2208 .expect("class_auditallowxperm_not_coalesced")
2209 .id();
2210
2211 let rules: Vec<_> = parsed_policy
2212 .access_vector_rules_for_test()
2213 .filter(|rule| rule.metadata.target_class() == class_id)
2214 .collect();
2215
2216 assert_eq!(rules.len(), 2);
2217 assert!(rules[0].metadata.is_allowxperm());
2218 assert!(!rules[0].metadata.is_auditallowxperm());
2219 if let Some(xperms) = rules[0].extended_permissions() {
2220 assert_eq!(xperms.count(), 1);
2221 assert!(xperms.contains(0xabcd));
2222 } else {
2223 panic!("unexpected permission data type")
2224 }
2225 assert!(!rules[1].metadata.is_allowxperm());
2226 assert!(rules[1].metadata.is_auditallowxperm());
2227 if let Some(xperms) = rules[1].extended_permissions() {
2228 assert_eq!(xperms.count(), 1);
2229 assert!(xperms.contains(0xabcd));
2230 } else {
2231 panic!("unexpected permission data type")
2232 }
2233 }
2234}