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 std::ops::BitAnd for XpermsBitmap {
450 type Output = Self;
451 fn bitand(self, rhs: Self) -> Self {
452 let mut result = self;
453 (0..Self::BITMAP_BLOCKS).for_each(|i| result.0[i] &= rhs.0[i]);
454 result
455 }
456}
457
458impl std::ops::BitOr for XpermsBitmap {
459 type Output = Self;
460 fn bitor(self, rhs: Self) -> Self {
461 let mut result = self;
462 (0..Self::BITMAP_BLOCKS).for_each(|i| result.0[i] |= rhs.0[i]);
463 result
464 }
465}
466
467impl std::ops::Not for XpermsBitmap {
468 type Output = Self;
469 fn not(self) -> Self {
470 let mut result = self;
471 (0..Self::BITMAP_BLOCKS).for_each(|i| result.0[i] = !result.0[i]);
472 result
473 }
474}
475
476impl std::ops::BitOrAssign<&Self> for XpermsBitmap {
477 fn bitor_assign(&mut self, rhs: &Self) {
478 (0..Self::BITMAP_BLOCKS).for_each(|i| self.0[i] |= rhs.0[i])
479 }
480}
481
482impl std::ops::SubAssign<&Self> for XpermsBitmap {
483 fn sub_assign(&mut self, rhs: &Self) {
484 (0..Self::BITMAP_BLOCKS).for_each(|i| self.0[i] = self.0[i] ^ (self.0[i] & rhs.0[i]))
485 }
486}
487
488array_type!(RoleTransitions, le::U32, RoleTransition);
489
490array_type_validate_deref_both!(RoleTransitions);
491
492impl ValidateArray<le::U32, RoleTransition> for RoleTransitions {
493 type Error = anyhow::Error;
494
495 fn validate_array(
497 _context: &PolicyValidationContext,
498 _metadata: &le::U32,
499 _items: &[RoleTransition],
500 ) -> Result<(), Self::Error> {
501 Ok(())
502 }
503}
504
505#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
506#[repr(C, packed)]
507pub(super) struct RoleTransition {
508 role: le::U32,
509 role_type: le::U32,
510 new_role: le::U32,
511 tclass: le::U32,
512}
513
514impl RoleTransition {
515 pub(super) fn current_role(&self) -> RoleId {
516 RoleId(NonZeroU32::new(self.role.get()).unwrap())
517 }
518
519 pub(super) fn type_(&self) -> TypeId {
520 TypeId(NonZeroU32::new(self.role_type.get()).unwrap())
521 }
522
523 pub(super) fn class(&self) -> ClassId {
524 ClassId(NonZeroU32::new(self.tclass.get()).unwrap())
525 }
526
527 pub(super) fn new_role(&self) -> RoleId {
528 RoleId(NonZeroU32::new(self.new_role.get()).unwrap())
529 }
530}
531
532impl Validate for RoleTransition {
533 type Error = anyhow::Error;
534
535 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
536 NonZeroU32::new(self.role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
537 NonZeroU32::new(self.role_type.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
538 NonZeroU32::new(self.tclass.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
539 NonZeroU32::new(self.new_role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
540 Ok(())
541 }
542}
543
544array_type!(RoleAllows, le::U32, RoleAllow);
545
546array_type_validate_deref_both!(RoleAllows);
547
548impl ValidateArray<le::U32, RoleAllow> for RoleAllows {
549 type Error = anyhow::Error;
550
551 fn validate_array(
553 _context: &PolicyValidationContext,
554 _metadata: &le::U32,
555 _items: &[RoleAllow],
556 ) -> Result<(), Self::Error> {
557 Ok(())
558 }
559}
560
561#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
562#[repr(C, packed)]
563pub(super) struct RoleAllow {
564 role: le::U32,
565 new_role: le::U32,
566}
567
568impl RoleAllow {
569 pub(super) fn source_role(&self) -> RoleId {
570 RoleId(NonZeroU32::new(self.role.get()).unwrap())
571 }
572
573 pub(super) fn new_role(&self) -> RoleId {
574 RoleId(NonZeroU32::new(self.new_role.get()).unwrap())
575 }
576}
577
578impl Validate for RoleAllow {
579 type Error = anyhow::Error;
580
581 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
582 NonZeroU32::new(self.role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
583 NonZeroU32::new(self.new_role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
584 Ok(())
585 }
586}
587
588#[derive(Debug, PartialEq)]
589pub(super) enum FilenameTransitionList {
590 PolicyVersionGeq33(SimpleArray<FilenameTransition>),
591 PolicyVersionLeq32(SimpleArray<DeprecatedFilenameTransition>),
592}
593
594impl Validate for FilenameTransitionList {
595 type Error = anyhow::Error;
596
597 fn validate(&self, context: &PolicyValidationContext) -> Result<(), Self::Error> {
598 match self {
599 Self::PolicyVersionLeq32(list) => {
600 list.validate(context).map_err(Into::<anyhow::Error>::into)
601 }
602 Self::PolicyVersionGeq33(list) => {
603 list.validate(context).map_err(Into::<anyhow::Error>::into)
604 }
605 }
606 }
607}
608
609impl Validate for FilenameTransition {
610 type Error = anyhow::Error;
611 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
612 Ok(())
613 }
614}
615
616#[derive(Debug, PartialEq)]
617pub(super) struct FilenameTransition {
618 filename: SimpleArray<u8>,
619 transition_type: le::U32,
620 transition_class: le::U32,
621 items: SimpleArray<FilenameTransitionItem>,
622}
623
624impl FilenameTransition {
625 pub(super) fn name_bytes(&self) -> &[u8] {
626 &self.filename.data
627 }
628
629 pub(super) fn target_type(&self) -> TypeId {
630 TypeId(NonZeroU32::new(self.transition_type.get()).unwrap())
631 }
632
633 pub(super) fn target_class(&self) -> ClassId {
634 ClassId(NonZeroU32::new(self.transition_class.get()).unwrap())
635 }
636
637 pub(super) fn outputs(&self) -> &[FilenameTransitionItem] {
638 &self.items.data
639 }
640}
641
642impl Parse for FilenameTransition
643where
644 SimpleArray<u8>: Parse,
645 SimpleArray<FilenameTransitionItem>: Parse,
646{
647 type Error = anyhow::Error;
648
649 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
650 let tail = bytes;
651
652 let (filename, tail) = SimpleArray::<u8>::parse(tail)
653 .map_err(Into::<anyhow::Error>::into)
654 .context("parsing filename for filename transition")?;
655
656 let (transition_type, tail) = PolicyCursor::parse::<le::U32>(tail)?;
657
658 let (transition_class, tail) = PolicyCursor::parse::<le::U32>(tail)?;
659
660 let (items, tail) = SimpleArray::<FilenameTransitionItem>::parse(tail)
661 .map_err(Into::<anyhow::Error>::into)
662 .context("parsing items for filename transition")?;
663
664 Ok((Self { filename, transition_type, transition_class, items }, tail))
665 }
666}
667
668#[derive(Debug, PartialEq)]
669pub(super) struct FilenameTransitionItem {
670 stypes: ExtensibleBitmap,
671 out_type: le::U32,
672}
673
674impl FilenameTransitionItem {
675 pub(super) fn has_source_type(&self, source_type: TypeId) -> bool {
676 self.stypes.is_set(source_type.0.get() - 1)
677 }
678
679 pub(super) fn out_type(&self) -> TypeId {
680 TypeId(NonZeroU32::new(self.out_type.get()).unwrap())
681 }
682}
683
684impl Parse for FilenameTransitionItem
685where
686 ExtensibleBitmap: Parse,
687{
688 type Error = anyhow::Error;
689
690 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
691 let tail = bytes;
692
693 let (stypes, tail) = ExtensibleBitmap::parse(tail)
694 .map_err(Into::<anyhow::Error>::into)
695 .context("parsing stypes extensible bitmap for file transition")?;
696
697 let (out_type, tail) = PolicyCursor::parse::<le::U32>(tail)?;
698
699 Ok((Self { stypes, out_type }, tail))
700 }
701}
702
703impl Validate for DeprecatedFilenameTransition {
704 type Error = anyhow::Error;
705 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
706 Ok(())
707 }
708}
709
710#[derive(Debug, PartialEq)]
711pub(super) struct DeprecatedFilenameTransition {
712 filename: SimpleArray<u8>,
713 metadata: DeprecatedFilenameTransitionMetadata,
714}
715
716impl DeprecatedFilenameTransition {
717 pub(super) fn name_bytes(&self) -> &[u8] {
718 &self.filename.data
719 }
720
721 pub(super) fn source_type(&self) -> TypeId {
722 TypeId(NonZeroU32::new(self.metadata.source_type.get()).unwrap())
723 }
724
725 pub(super) fn target_type(&self) -> TypeId {
726 TypeId(NonZeroU32::new(self.metadata.transition_type.get()).unwrap())
727 }
728
729 pub(super) fn target_class(&self) -> ClassId {
730 ClassId(NonZeroU32::new(self.metadata.transition_class.get()).unwrap())
731 }
732
733 pub(super) fn out_type(&self) -> TypeId {
734 TypeId(NonZeroU32::new(self.metadata.out_type.get()).unwrap())
735 }
736}
737
738impl Parse for DeprecatedFilenameTransition
739where
740 SimpleArray<u8>: Parse,
741{
742 type Error = anyhow::Error;
743
744 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
745 let tail = bytes;
746
747 let (filename, tail) = SimpleArray::<u8>::parse(tail)
748 .map_err(Into::<anyhow::Error>::into)
749 .context("parsing filename for deprecated filename transition")?;
750
751 let (metadata, tail) = PolicyCursor::parse::<DeprecatedFilenameTransitionMetadata>(tail)?;
752
753 Ok((Self { filename, metadata }, tail))
754 }
755}
756
757#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
758#[repr(C, packed)]
759pub(super) struct DeprecatedFilenameTransitionMetadata {
760 source_type: le::U32,
761 transition_type: le::U32,
762 transition_class: le::U32,
763 out_type: le::U32,
764}
765
766impl Validate for SimpleArray<InitialSid> {
767 type Error = anyhow::Error;
768 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
769 for initial_sid in crate::InitialSid::all_variants() {
770 self.data
771 .iter()
772 .find(|initial| initial.id().get() == *initial_sid as u32)
773 .ok_or(ValidateError::MissingInitialSid { initial_sid: *initial_sid })?;
774 }
775 Ok(())
776 }
777}
778
779#[derive(Debug, PartialEq)]
780pub(super) struct InitialSid {
781 id: le::U32,
782 context: Context,
783}
784
785impl InitialSid {
786 pub(super) fn id(&self) -> le::U32 {
787 self.id
788 }
789
790 pub(super) fn context(&self) -> &Context {
791 &self.context
792 }
793}
794
795impl Parse for InitialSid
796where
797 Context: Parse,
798{
799 type Error = anyhow::Error;
800
801 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
802 let tail = bytes;
803
804 let (id, tail) = PolicyCursor::parse::<le::U32>(tail)?;
805
806 let (context, tail) = Context::parse(tail)
807 .map_err(Into::<anyhow::Error>::into)
808 .context("parsing context for initial sid")?;
809
810 Ok((Self { id, context }, tail))
811 }
812}
813
814#[derive(Debug, PartialEq)]
815pub(super) struct Context {
816 metadata: ContextMetadata,
817 mls_range: MlsRange,
818}
819
820impl Context {
821 pub(super) fn user_id(&self) -> UserId {
822 UserId(NonZeroU32::new(self.metadata.user.get()).unwrap())
823 }
824 pub(super) fn role_id(&self) -> RoleId {
825 RoleId(NonZeroU32::new(self.metadata.role.get()).unwrap())
826 }
827 pub(super) fn type_id(&self) -> TypeId {
828 TypeId(NonZeroU32::new(self.metadata.context_type.get()).unwrap())
829 }
830 pub(super) fn low_level(&self) -> &MlsLevel {
831 self.mls_range.low()
832 }
833 pub(super) fn high_level(&self) -> &Option<MlsLevel> {
834 self.mls_range.high()
835 }
836}
837
838impl Parse for Context
839where
840 MlsRange: Parse,
841{
842 type Error = anyhow::Error;
843
844 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
845 let tail = bytes;
846
847 let (metadata, tail) =
848 PolicyCursor::parse::<ContextMetadata>(tail).context("parsing metadata for context")?;
849
850 let (mls_range, tail) = MlsRange::parse(tail)
851 .map_err(Into::<anyhow::Error>::into)
852 .context("parsing mls range for context")?;
853
854 Ok((Self { metadata, mls_range }, tail))
855 }
856}
857
858#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
859#[repr(C, packed)]
860pub(super) struct ContextMetadata {
861 user: le::U32,
862 role: le::U32,
863 context_type: le::U32,
864}
865
866impl Validate for NamedContextPair {
867 type Error = anyhow::Error;
868
869 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
874 Ok(())
875 }
876}
877
878#[derive(Debug, PartialEq)]
879pub(super) struct NamedContextPair {
880 name: SimpleArray<u8>,
881 context1: Context,
882 context2: Context,
883}
884
885impl Parse for NamedContextPair
886where
887 SimpleArray<u8>: Parse,
888 Context: Parse,
889{
890 type Error = anyhow::Error;
891
892 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
893 let tail = bytes;
894
895 let (name, tail) = SimpleArray::parse(tail)
896 .map_err(Into::<anyhow::Error>::into)
897 .context("parsing filesystem context name")?;
898
899 let (context1, tail) = Context::parse(tail)
900 .map_err(Into::<anyhow::Error>::into)
901 .context("parsing first context for filesystem context")?;
902
903 let (context2, tail) = Context::parse(tail)
904 .map_err(Into::<anyhow::Error>::into)
905 .context("parsing second context for filesystem context")?;
906
907 Ok((Self { name, context1, context2 }, tail))
908 }
909}
910
911impl Validate for Port {
912 type Error = anyhow::Error;
913
914 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
916 Ok(())
917 }
918}
919
920#[derive(Debug, PartialEq)]
921pub(super) struct Port {
922 metadata: PortMetadata,
923 context: Context,
924}
925
926impl Parse for Port
927where
928 Context: Parse,
929{
930 type Error = anyhow::Error;
931
932 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
933 let tail = bytes;
934
935 let (metadata, tail) =
936 PolicyCursor::parse::<PortMetadata>(tail).context("parsing metadata for context")?;
937
938 let (context, tail) = Context::parse(tail)
939 .map_err(Into::<anyhow::Error>::into)
940 .context("parsing context for port")?;
941
942 Ok((Self { metadata, context }, tail))
943 }
944}
945
946#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
947#[repr(C, packed)]
948pub(super) struct PortMetadata {
949 protocol: le::U32,
950 low_port: le::U32,
951 high_port: le::U32,
952}
953
954impl Validate for Node {
955 type Error = anyhow::Error;
956
957 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
959 Ok(())
960 }
961}
962
963#[derive(Debug, PartialEq)]
964pub(super) struct Node {
965 address: le::U32,
966 mask: le::U32,
967 context: Context,
968}
969
970impl Parse for Node
971where
972 Context: Parse,
973{
974 type Error = anyhow::Error;
975
976 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
977 let tail = bytes;
978
979 let (address, tail) = PolicyCursor::parse::<le::U32>(tail)?;
980
981 let (mask, tail) = PolicyCursor::parse::<le::U32>(tail)?;
982
983 let (context, tail) = Context::parse(tail)
984 .map_err(Into::<anyhow::Error>::into)
985 .context("parsing context for node")?;
986
987 Ok((Self { address, mask, context }, tail))
988 }
989}
990
991#[derive(Debug, PartialEq)]
992pub(super) struct FsUse {
993 behavior_and_name: Array<FsUseMetadata, u8>,
994 context: Context,
995}
996
997impl FsUse {
998 pub fn fs_type(&self) -> &[u8] {
999 &self.behavior_and_name.data
1000 }
1001
1002 pub(super) fn behavior(&self) -> FsUseType {
1003 FsUseType::try_from(self.behavior_and_name.metadata.behavior).unwrap()
1004 }
1005
1006 pub(super) fn context(&self) -> &Context {
1007 &self.context
1008 }
1009}
1010
1011impl Parse for FsUse
1012where
1013 Array<FsUseMetadata, u8>: Parse,
1014 Context: Parse,
1015{
1016 type Error = anyhow::Error;
1017
1018 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1019 let tail = bytes;
1020
1021 let (behavior_and_name, tail) = Array::<FsUseMetadata, u8>::parse(tail)
1022 .map_err(Into::<anyhow::Error>::into)
1023 .context("parsing fs use metadata")?;
1024
1025 let (context, tail) = Context::parse(tail)
1026 .map_err(Into::<anyhow::Error>::into)
1027 .context("parsing context for fs use")?;
1028
1029 Ok((Self { behavior_and_name, context }, tail))
1030 }
1031}
1032
1033impl Validate for FsUse {
1034 type Error = anyhow::Error;
1035
1036 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1037 FsUseType::try_from(self.behavior_and_name.metadata.behavior)?;
1038
1039 Ok(())
1040 }
1041}
1042
1043#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1044#[repr(C, packed)]
1045pub(super) struct FsUseMetadata {
1046 behavior: le::U32,
1048 name_length: le::U32,
1050}
1051
1052impl Counted for FsUseMetadata {
1053 fn count(&self) -> u32 {
1054 self.name_length.get()
1055 }
1056}
1057
1058#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
1061pub enum FsUseType {
1062 Xattr = 1,
1063 Trans = 2,
1064 Task = 3,
1065}
1066
1067impl TryFrom<le::U32> for FsUseType {
1068 type Error = anyhow::Error;
1069
1070 fn try_from(value: le::U32) -> Result<Self, Self::Error> {
1071 match value.get() {
1072 1 => Ok(FsUseType::Xattr),
1073 2 => Ok(FsUseType::Trans),
1074 3 => Ok(FsUseType::Task),
1075 _ => Err(ValidateError::InvalidFsUseType { value: value.get() }.into()),
1076 }
1077 }
1078}
1079
1080impl Validate for IPv6Node {
1081 type Error = anyhow::Error;
1082
1083 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1085 Ok(())
1086 }
1087}
1088
1089#[derive(Debug, PartialEq)]
1090pub(super) struct IPv6Node {
1091 address: [le::U32; 4],
1092 mask: [le::U32; 4],
1093 context: Context,
1094}
1095
1096impl Parse for IPv6Node
1097where
1098 Context: Parse,
1099{
1100 type Error = anyhow::Error;
1101
1102 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1103 let tail = bytes;
1104
1105 let (address, tail) = PolicyCursor::parse::<[le::U32; 4]>(tail)?;
1106
1107 let (mask, tail) = PolicyCursor::parse::<[le::U32; 4]>(tail)?;
1108
1109 let (context, tail) = Context::parse(tail)
1110 .map_err(Into::<anyhow::Error>::into)
1111 .context("parsing context for ipv6 node")?;
1112
1113 Ok((Self { address, mask, context }, tail))
1114 }
1115}
1116
1117impl Validate for InfinitiBandPartitionKey {
1118 type Error = anyhow::Error;
1119
1120 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1122 Ok(())
1123 }
1124}
1125
1126#[derive(Debug, PartialEq)]
1127pub(super) struct InfinitiBandPartitionKey {
1128 low: le::U32,
1129 high: le::U32,
1130 context: Context,
1131}
1132
1133impl Parse for InfinitiBandPartitionKey
1134where
1135 Context: Parse,
1136{
1137 type Error = anyhow::Error;
1138
1139 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1140 let tail = bytes;
1141
1142 let (low, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1143
1144 let (high, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1145
1146 let (context, tail) = Context::parse(tail)
1147 .map_err(Into::<anyhow::Error>::into)
1148 .context("parsing context for infiniti band partition key")?;
1149
1150 Ok((Self { low, high, context }, tail))
1151 }
1152}
1153
1154impl Validate for InfinitiBandEndPort {
1155 type Error = anyhow::Error;
1156
1157 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1159 Ok(())
1160 }
1161}
1162
1163#[derive(Debug, PartialEq)]
1164pub(super) struct InfinitiBandEndPort {
1165 port_and_name: Array<InfinitiBandEndPortMetadata, u8>,
1166 context: Context,
1167}
1168
1169impl Parse for InfinitiBandEndPort
1170where
1171 Array<InfinitiBandEndPortMetadata, u8>: Parse,
1172 Context: Parse,
1173{
1174 type Error = anyhow::Error;
1175
1176 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1177 let tail = bytes;
1178
1179 let (port_and_name, tail) = Array::<InfinitiBandEndPortMetadata, u8>::parse(tail)
1180 .map_err(Into::<anyhow::Error>::into)
1181 .context("parsing infiniti band end port metadata")?;
1182
1183 let (context, tail) = Context::parse(tail)
1184 .map_err(Into::<anyhow::Error>::into)
1185 .context("parsing context for infiniti band end port")?;
1186
1187 Ok((Self { port_and_name, context }, tail))
1188 }
1189}
1190
1191#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1192#[repr(C, packed)]
1193pub(super) struct InfinitiBandEndPortMetadata {
1194 length: le::U32,
1195 port: le::U32,
1196}
1197
1198impl Counted for InfinitiBandEndPortMetadata {
1199 fn count(&self) -> u32 {
1200 self.length.get()
1201 }
1202}
1203
1204impl Validate for GenericFsContext {
1205 type Error = anyhow::Error;
1206
1207 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1209 Ok(())
1210 }
1211}
1212
1213#[derive(Debug)]
1216pub(super) struct GenericFsContext {
1217 fs_type: SimpleArray<u8>,
1218 fs_context: SimpleArrayView<FsContext>,
1219}
1220
1221impl GenericFsContext {
1222 pub(super) fn for_query(fs_type: &str) -> SimpleArray<u8> {
1224 Array { data: fs_type.as_bytes().to_vec(), metadata: le::U32::new(fs_type.len() as u32) }
1225 }
1226}
1227
1228impl Hashable for GenericFsContext {
1229 type Key = SimpleArray<u8>;
1230 type Value = FsContext;
1231
1232 fn key(&self) -> &Self::Key {
1233 &self.fs_type
1234 }
1235
1236 fn values(&self) -> &SimpleArrayView<Self::Value> {
1237 &self.fs_context
1238 }
1239}
1240
1241impl Eq for SimpleArray<u8> {}
1242
1243impl Hash for SimpleArray<u8> {
1244 fn hash<H: Hasher>(&self, state: &mut H) {
1245 self.data.hash(state);
1246 }
1247}
1248
1249impl Parse for GenericFsContext {
1250 type Error = anyhow::Error;
1251
1252 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1253 let tail = bytes;
1254
1255 let (fs_type, tail) = SimpleArray::<u8>::parse(tail)
1256 .map_err(Into::<anyhow::Error>::into)
1257 .context("parsing fs_type for generic fs context")?;
1258
1259 let (fs_context, tail) = SimpleArrayView::<FsContext>::parse(tail)
1260 .map_err(Into::<anyhow::Error>::into)
1261 .context("parsing fs_context for generic fs context")?;
1262
1263 Ok((Self { fs_type, fs_context }, tail))
1264 }
1265}
1266
1267#[derive(Debug, PartialEq)]
1268pub(super) struct FsContext {
1269 partial_path: SimpleArray<u8>,
1272 class: le::U32,
1276 context: Context,
1278}
1279
1280impl FsContext {
1281 pub(super) fn partial_path(&self) -> &[u8] {
1282 &self.partial_path.data
1283 }
1284
1285 pub(super) fn context(&self) -> &Context {
1286 &self.context
1287 }
1288
1289 pub(super) fn class(&self) -> Option<ClassId> {
1290 NonZeroU32::new(self.class.into()).map(ClassId)
1291 }
1292}
1293
1294impl Parse for FsContext
1295where
1296 SimpleArray<u8>: Parse,
1297 Context: Parse,
1298{
1299 type Error = anyhow::Error;
1300
1301 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1302 let tail = bytes;
1303
1304 let (partial_path, tail) = SimpleArray::<u8>::parse(tail)
1305 .map_err(Into::<anyhow::Error>::into)
1306 .context("parsing filesystem context partial path")?;
1307
1308 let (class, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1309
1310 let (context, tail) = Context::parse(tail)
1311 .map_err(Into::<anyhow::Error>::into)
1312 .context("parsing context for filesystem context")?;
1313
1314 Ok((Self { partial_path, class, context }, tail))
1315 }
1316}
1317
1318impl Validate for FsContext {
1319 type Error = anyhow::Error;
1320
1321 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1323 Ok(())
1324 }
1325}
1326
1327impl Walk for FsContext {
1328 fn walk(policy_data: &PolicyData, offset: PolicyOffset) -> PolicyOffset {
1329 let cursor = PolicyCursor::new_at(policy_data, offset);
1330 let (_, tail) = FsContext::parse(cursor)
1331 .map_err(Into::<anyhow::Error>::into)
1332 .expect("policy should be valid");
1333 tail.offset()
1334 }
1335}
1336
1337impl Validate for RangeTransition {
1338 type Error = anyhow::Error;
1339 fn validate(&self, _context: &PolicyValidationContext) -> Result<(), Self::Error> {
1340 if self.metadata.target_class.get() == 0 {
1341 return Err(ValidateError::NonOptionalIdIsZero.into());
1342 }
1343 Ok(())
1344 }
1345}
1346
1347#[derive(Debug, PartialEq)]
1348pub(super) struct RangeTransition {
1349 metadata: RangeTransitionMetadata,
1350 mls_range: MlsRange,
1351}
1352
1353impl RangeTransition {
1354 pub fn source_type(&self) -> TypeId {
1355 TypeId(NonZeroU32::new(self.metadata.source_type.get()).unwrap())
1356 }
1357
1358 pub fn target_type(&self) -> TypeId {
1359 TypeId(NonZeroU32::new(self.metadata.target_type.get()).unwrap())
1360 }
1361
1362 pub fn target_class(&self) -> ClassId {
1363 ClassId(NonZeroU32::new(self.metadata.target_class.get()).unwrap())
1364 }
1365
1366 pub fn mls_range(&self) -> &MlsRange {
1367 &self.mls_range
1368 }
1369}
1370
1371impl Parse for RangeTransition
1372where
1373 MlsRange: Parse,
1374{
1375 type Error = anyhow::Error;
1376
1377 fn parse<'a>(bytes: PolicyCursor<'a>) -> Result<(Self, PolicyCursor<'a>), Self::Error> {
1378 let tail = bytes;
1379
1380 let (metadata, tail) = PolicyCursor::parse::<RangeTransitionMetadata>(tail)
1381 .context("parsing range transition metadata")?;
1382
1383 let (mls_range, tail) = MlsRange::parse(tail)
1384 .map_err(Into::<anyhow::Error>::into)
1385 .context("parsing mls range for range transition")?;
1386
1387 Ok((Self { metadata, mls_range }, tail))
1388 }
1389}
1390
1391#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1392#[repr(C, packed)]
1393pub(super) struct RangeTransitionMetadata {
1394 source_type: le::U32,
1395 target_type: le::U32,
1396 target_class: le::U32,
1397}
1398
1399#[cfg(test)]
1400pub(super) mod testing {
1401 use super::AccessVectorRule;
1402 use std::cmp::Ordering;
1403
1404 pub(in super::super) fn access_vector_rule_ordering(
1405 left: &AccessVectorRule,
1406 right: &AccessVectorRule,
1407 ) -> Ordering {
1408 (
1409 left.metadata.source_type,
1410 left.metadata.target_type,
1411 left.metadata.class,
1412 left.metadata.access_vector_rule_type,
1413 )
1414 .cmp(&(
1415 right.metadata.source_type,
1416 right.metadata.target_type,
1417 right.metadata.class,
1418 right.metadata.access_vector_rule_type,
1419 ))
1420 }
1421}
1422
1423#[cfg(test)]
1424mod tests {
1425 use super::super::{ClassId, find_class_by_name, parse_policy_by_value};
1426 use super::{
1427 ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM, ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM,
1428 ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES,
1429 XPERMS_TYPE_IOCTL_PREFIXES, XPERMS_TYPE_NLMSG,
1430 };
1431 use std::num::NonZeroU32;
1432
1433 impl super::AccessVectorRuleMetadata {
1434 pub fn is_allowxperm(&self) -> bool {
1438 (self.access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM) != 0
1439 }
1440
1441 pub fn is_auditallowxperm(&self) -> bool {
1445 (self.access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM) != 0
1446 }
1447
1448 pub fn is_dontauditxperm(&self) -> bool {
1452 (self.access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM) != 0
1453 }
1454
1455 pub fn target_class(&self) -> ClassId {
1460 ClassId(NonZeroU32::new(self.class.into()).unwrap())
1461 }
1462 }
1463
1464 #[test]
1465 fn parse_allowxperm_one_ioctl() {
1466 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1467 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1468 let parsed_policy = &policy.0;
1469 parsed_policy.validate().expect("validate policy");
1470
1471 let class_id = find_class_by_name(&parsed_policy.classes(), "class_one_ioctl")
1472 .expect("look up class_one_ioctl")
1473 .id();
1474
1475 let rules: Vec<_> = parsed_policy
1476 .access_vector_rules_for_test()
1477 .filter(|rule| rule.metadata.target_class() == class_id)
1478 .collect();
1479
1480 assert_eq!(rules.len(), 1);
1481 assert!(rules[0].metadata.is_allowxperm());
1482 if let Some(xperms) = rules[0].extended_permissions() {
1483 assert_eq!(xperms.count(), 1);
1484 assert!(xperms.contains(0xabcd));
1485 } else {
1486 panic!("unexpected permission data type")
1487 }
1488 }
1489
1490 #[test]
1493 fn parse_allowxperm_two_ioctls_same_range() {
1494 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1495 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1496 let parsed_policy = &policy.0;
1497 parsed_policy.validate().expect("validate policy");
1498
1499 let class_id = find_class_by_name(&parsed_policy.classes(), "class_two_ioctls_same_range")
1500 .expect("look up class_two_ioctls_same_range")
1501 .id();
1502
1503 let rules: Vec<_> = parsed_policy
1504 .access_vector_rules_for_test()
1505 .filter(|rule| rule.metadata.target_class() == class_id)
1506 .collect();
1507
1508 assert_eq!(rules.len(), 1);
1509 assert!(rules[0].metadata.is_allowxperm());
1510 if let Some(xperms) = rules[0].extended_permissions() {
1511 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1512 assert_eq!(xperms.xperms_optional_prefix, 0x12);
1513 assert_eq!(xperms.count(), 2);
1514 assert!(xperms.contains(0x1234));
1515 assert!(xperms.contains(0x1256));
1516 } else {
1517 panic!("unexpected permission data type")
1518 }
1519 }
1520
1521 #[test]
1524 fn parse_allowxperm_two_ioctls_same_range_diff_rules() {
1525 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1526 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1527 let parsed_policy = &policy.0;
1528 parsed_policy.validate().expect("validate policy");
1529
1530 let class_id =
1531 find_class_by_name(&parsed_policy.classes(), "class_four_ioctls_same_range_diff_rules")
1532 .expect("look up class_four_ioctls_same_range_diff_rules")
1533 .id();
1534
1535 let rules: Vec<_> = parsed_policy
1536 .access_vector_rules_for_test()
1537 .filter(|rule| rule.metadata.target_class() == class_id)
1538 .collect();
1539
1540 assert_eq!(rules.len(), 1);
1541 assert!(rules[0].metadata.is_allowxperm());
1542 if let Some(xperms) = rules[0].extended_permissions() {
1543 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1544 assert_eq!(xperms.xperms_optional_prefix, 0x30);
1545 assert_eq!(xperms.count(), 4);
1546 assert!(xperms.contains(0x3008));
1547 assert!(xperms.contains(0x3009));
1548 assert!(xperms.contains(0x3011));
1549 assert!(xperms.contains(0x3013));
1550 } else {
1551 panic!("unexpected permission data type")
1552 }
1553 }
1554
1555 #[test]
1558 fn parse_allowxperm_two_ioctls_different_range() {
1559 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1560 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1561 let parsed_policy = &policy.0;
1562 parsed_policy.validate().expect("validate policy");
1563
1564 let class_id = find_class_by_name(&parsed_policy.classes(), "class_two_ioctls_diff_range")
1565 .expect("look up class_two_ioctls_diff_range")
1566 .id();
1567
1568 let rules: Vec<_> = parsed_policy
1569 .access_vector_rules_for_test()
1570 .filter(|rule| rule.metadata.target_class() == class_id)
1571 .collect();
1572
1573 assert_eq!(rules.len(), 2);
1574 assert!(rules[0].metadata.is_allowxperm());
1575 if let Some(xperms) = rules[0].extended_permissions() {
1576 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1577 assert_eq!(xperms.xperms_optional_prefix, 0x56);
1578 assert_eq!(xperms.count(), 1);
1579 assert!(xperms.contains(0x5678));
1580 } else {
1581 panic!("unexpected permission data type")
1582 }
1583 assert!(rules[1].metadata.is_allowxperm());
1584 if let Some(xperms) = rules[1].extended_permissions() {
1585 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1586 assert_eq!(xperms.xperms_optional_prefix, 0x12);
1587 assert_eq!(xperms.count(), 1);
1588 assert!(xperms.contains(0x1234));
1589 } else {
1590 panic!("unexpected permission data type")
1591 }
1592 }
1593
1594 #[test]
1597 fn parse_allowxperm_one_driver_range() {
1598 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1599 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1600 let parsed_policy = &policy.0;
1601 parsed_policy.validate().expect("validate policy");
1602
1603 let class_id = find_class_by_name(&parsed_policy.classes(), "class_one_driver_range")
1604 .expect("look up class_one_driver_range")
1605 .id();
1606
1607 let rules: Vec<_> = parsed_policy
1608 .access_vector_rules_for_test()
1609 .filter(|rule| rule.metadata.target_class() == class_id)
1610 .collect();
1611
1612 assert_eq!(rules.len(), 1);
1613 assert!(rules[0].metadata.is_allowxperm());
1614 if let Some(xperms) = rules[0].extended_permissions() {
1615 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1616 assert_eq!(xperms.count(), 0x100);
1617 assert!(xperms.contains(0x1000));
1618 assert!(xperms.contains(0x10ab));
1619 } else {
1620 panic!("unexpected permission data type")
1621 }
1622 }
1623
1624 #[test]
1628 fn parse_allowxperm_most_ioctls() {
1629 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1630 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1631 let parsed_policy = &policy.0;
1632 parsed_policy.validate().expect("validate policy");
1633
1634 let class_id = find_class_by_name(&parsed_policy.classes(), "class_most_ioctls")
1635 .expect("look up class_most_ioctls")
1636 .id();
1637
1638 let rules: Vec<_> = parsed_policy
1639 .access_vector_rules_for_test()
1640 .filter(|rule| rule.metadata.target_class() == class_id)
1641 .collect();
1642
1643 assert_eq!(rules.len(), 3);
1644 assert!(rules[0].metadata.is_allowxperm());
1645 if let Some(xperms) = rules[0].extended_permissions() {
1646 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1647 assert_eq!(xperms.xperms_optional_prefix, 0xff);
1648 assert_eq!(xperms.count(), 0xfe);
1649 for xperm in 0xff00..0xfffd {
1650 assert!(xperms.contains(xperm));
1651 }
1652 } else {
1653 panic!("unexpected permission data type")
1654 }
1655 if let Some(xperms) = rules[1].extended_permissions() {
1656 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1657 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1658 assert_eq!(xperms.count(), 0xfe);
1659 for xperm in 0x0002..0x0100 {
1660 assert!(xperms.contains(xperm));
1661 }
1662 } else {
1663 panic!("unexpected permission data type")
1664 }
1665 if let Some(xperms) = rules[2].extended_permissions() {
1666 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1667 assert_eq!(xperms.count(), 0xfe00);
1668 for xperm in 0x0100..0xff00 {
1669 assert!(xperms.contains(xperm));
1670 }
1671 } else {
1672 panic!("unexpected permission data type")
1673 }
1674 }
1675
1676 #[test]
1680 fn parse_allowxperm_most_ioctls_with_hole() {
1681 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1682 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1683 let parsed_policy = &policy.0;
1684 parsed_policy.validate().expect("validate policy");
1685
1686 let class_id = find_class_by_name(&parsed_policy.classes(), "class_most_ioctls_with_hole")
1687 .expect("look up class_most_ioctls_with_hole")
1688 .id();
1689
1690 let rules: Vec<_> = parsed_policy
1691 .access_vector_rules_for_test()
1692 .filter(|rule| rule.metadata.target_class() == class_id)
1693 .collect();
1694
1695 assert_eq!(rules.len(), 5);
1696 assert!(rules[0].metadata.is_allowxperm());
1697 if let Some(xperms) = rules[0].extended_permissions() {
1698 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1699 assert_eq!(xperms.xperms_optional_prefix, 0xff);
1700 assert_eq!(xperms.count(), 0xfe);
1701 for xperm in 0xff00..0xfffd {
1702 assert!(xperms.contains(xperm));
1703 }
1704 } else {
1705 panic!("unexpected permission data type")
1706 }
1707 if let Some(xperms) = rules[1].extended_permissions() {
1708 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1709 assert_eq!(xperms.xperms_optional_prefix, 0x40);
1710 assert_eq!(xperms.count(), 0xfe);
1711 for xperm in 0x4002..0x4100 {
1712 assert!(xperms.contains(xperm));
1713 }
1714 } else {
1715 panic!("unexpected permission data type")
1716 }
1717 assert!(rules[0].metadata.is_allowxperm());
1718 if let Some(xperms) = rules[2].extended_permissions() {
1719 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1720 assert_eq!(xperms.xperms_optional_prefix, 0x2f);
1721 assert_eq!(xperms.count(), 0xfe);
1722 for xperm in 0x2f00..0x2ffd {
1723 assert!(xperms.contains(xperm));
1724 }
1725 } else {
1726 panic!("unexpected permission data type")
1727 }
1728 if let Some(xperms) = rules[3].extended_permissions() {
1729 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1730 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1731 assert_eq!(xperms.count(), 0xfe);
1732 for xperm in 0x0002..0x0100 {
1733 assert!(xperms.contains(xperm));
1734 }
1735 } else {
1736 panic!("unexpected permission data type")
1737 }
1738 if let Some(xperms) = rules[4].extended_permissions() {
1739 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1740 assert_eq!(xperms.count(), 0xec00);
1741 for xperm in 0x0100..0x2f00 {
1742 assert!(xperms.contains(xperm));
1743 }
1744 for xperm in 0x4100..0xff00 {
1745 assert!(xperms.contains(xperm));
1746 }
1747 } else {
1748 panic!("unexpected permission data type")
1749 }
1750 }
1751
1752 #[test]
1757 fn parse_allowxperm_all_ioctls() {
1758 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1759 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1760 let parsed_policy = &policy.0;
1761 parsed_policy.validate().expect("validate policy");
1762
1763 let class_id = find_class_by_name(&parsed_policy.classes(), "class_all_ioctls")
1764 .expect("look up class_all_ioctls")
1765 .id();
1766
1767 let rules: Vec<_> = parsed_policy
1768 .access_vector_rules_for_test()
1769 .filter(|rule| rule.metadata.target_class() == class_id)
1770 .collect();
1771
1772 assert_eq!(rules.len(), 1);
1773 assert!(rules[0].metadata.is_allowxperm());
1774 if let Some(xperms) = rules[0].extended_permissions() {
1775 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1776 assert_eq!(xperms.count(), 0x10000);
1777 } else {
1778 panic!("unexpected permission data type")
1779 }
1780 }
1781
1782 #[test]
1783 fn parse_allowxperm_one_nlmsg() {
1784 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1785 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1786 let parsed_policy = &policy.0;
1787 parsed_policy.validate().expect("validate policy");
1788
1789 let class_id = find_class_by_name(&parsed_policy.classes(), "class_one_nlmsg")
1790 .expect("look up class_one_nlmsg")
1791 .id();
1792
1793 let rules: Vec<_> = parsed_policy
1794 .access_vector_rules_for_test()
1795 .filter(|rule| rule.metadata.target_class() == class_id)
1796 .collect();
1797
1798 assert_eq!(rules.len(), 1);
1799 assert!(rules[0].metadata.is_allowxperm());
1800 if let Some(xperms) = rules[0].extended_permissions() {
1801 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1802 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1803 assert_eq!(xperms.count(), 1);
1804 assert!(xperms.contains(0x12));
1805 } else {
1806 panic!("unexpected permission data type")
1807 }
1808 }
1809
1810 #[test]
1813 fn parse_allowxperm_two_nlmsg_same_range() {
1814 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1815 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1816 let parsed_policy = &policy.0;
1817 parsed_policy.validate().expect("validate policy");
1818
1819 let class_id = find_class_by_name(&parsed_policy.classes(), "class_two_nlmsg_same_range")
1820 .expect("look up class_two_nlmsg_same_range")
1821 .id();
1822
1823 let rules: Vec<_> = parsed_policy
1824 .access_vector_rules_for_test()
1825 .filter(|rule| rule.metadata.target_class() == class_id)
1826 .collect();
1827
1828 assert_eq!(rules.len(), 1);
1829 assert!(rules[0].metadata.is_allowxperm());
1830 if let Some(xperms) = rules[0].extended_permissions() {
1831 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1832 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1833 assert_eq!(xperms.count(), 2);
1834 assert!(xperms.contains(0x12));
1835 assert!(xperms.contains(0x24));
1836 } else {
1837 panic!("unexpected permission data type")
1838 }
1839 }
1840
1841 #[test]
1844 fn parse_allowxperm_two_nlmsg_different_range() {
1845 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1846 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1847 let parsed_policy = &policy.0;
1848 parsed_policy.validate().expect("validate policy");
1849
1850 let class_id = find_class_by_name(&parsed_policy.classes(), "class_two_nlmsg_diff_range")
1851 .expect("look up class_two_nlmsg_diff_range")
1852 .id();
1853
1854 let rules: Vec<_> = parsed_policy
1855 .access_vector_rules_for_test()
1856 .filter(|rule| rule.metadata.target_class() == class_id)
1857 .collect();
1858
1859 assert_eq!(rules.len(), 2);
1860 assert!(rules[0].metadata.is_allowxperm());
1861 if let Some(xperms) = rules[0].extended_permissions() {
1862 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1863 assert_eq!(xperms.xperms_optional_prefix, 0x10);
1864 assert_eq!(xperms.count(), 1);
1865 assert!(xperms.contains(0x1024));
1866 } else {
1867 panic!("unexpected permission data type")
1868 }
1869 assert!(rules[1].metadata.is_allowxperm());
1870 if let Some(xperms) = rules[1].extended_permissions() {
1871 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1872 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1873 assert_eq!(xperms.count(), 1);
1874 assert!(xperms.contains(0x12));
1875 } else {
1876 panic!("unexpected permission data type")
1877 }
1878 }
1879
1880 #[test]
1883 fn parse_allowxperm_one_nlmsg_range() {
1884 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1885 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1886 let parsed_policy = &policy.0;
1887 parsed_policy.validate().expect("validate policy");
1888
1889 let class_id = find_class_by_name(&parsed_policy.classes(), "class_one_nlmsg_range")
1890 .expect("look up class_one_nlmsg_range")
1891 .id();
1892
1893 let rules: Vec<_> = parsed_policy
1894 .access_vector_rules_for_test()
1895 .filter(|rule| rule.metadata.target_class() == class_id)
1896 .collect();
1897
1898 assert_eq!(rules.len(), 1);
1899 assert!(rules[0].metadata.is_allowxperm());
1900 if let Some(xperms) = rules[0].extended_permissions() {
1901 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1902 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1903 assert_eq!(xperms.count(), 0x100);
1904 for i in 0x0..0xff {
1905 assert!(xperms.contains(i), "{i}");
1906 }
1907 } else {
1908 panic!("unexpected permission data type")
1909 }
1910 }
1911
1912 #[test]
1918 fn parse_allowxperm_two_nlmsg_ranges() {
1919 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1920 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1921 let parsed_policy = &policy.0;
1922 parsed_policy.validate().expect("validate policy");
1923
1924 let class_id = find_class_by_name(&parsed_policy.classes(), "class_two_nlmsg_ranges")
1925 .expect("look up class_two_nlmsg_ranges")
1926 .id();
1927
1928 let rules: Vec<_> = parsed_policy
1929 .access_vector_rules_for_test()
1930 .filter(|rule| rule.metadata.target_class() == class_id)
1931 .collect();
1932
1933 assert_eq!(rules.len(), 2);
1934 assert!(rules[0].metadata.is_allowxperm());
1935 if let Some(xperms) = rules[0].extended_permissions() {
1936 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1937 assert_eq!(xperms.xperms_optional_prefix, 0x01);
1938 assert_eq!(xperms.count(), 0x100);
1939 for i in 0x0100..0x01ff {
1940 assert!(xperms.contains(i), "{i}");
1941 }
1942 } else {
1943 panic!("unexpected permission data type")
1944 }
1945 if let Some(xperms) = rules[1].extended_permissions() {
1946 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1947 assert_eq!(xperms.xperms_optional_prefix, 0x00);
1948 assert_eq!(xperms.count(), 0x100);
1949 for i in 0x0..0xff {
1950 assert!(xperms.contains(i), "{i}");
1951 }
1952 } else {
1953 panic!("unexpected permission data type")
1954 }
1955 }
1956
1957 #[test]
1964 fn parse_allowxperm_three_separate_nlmsg_ranges() {
1965 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1966 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1967 let parsed_policy = &policy.0;
1968 parsed_policy.validate().expect("validate policy");
1969
1970 let class_id =
1971 find_class_by_name(&parsed_policy.classes(), "class_three_separate_nlmsg_ranges")
1972 .expect("look up class_three_separate_nlmsg_ranges")
1973 .id();
1974
1975 let rules: Vec<_> = parsed_policy
1976 .access_vector_rules_for_test()
1977 .filter(|rule| rule.metadata.target_class() == class_id)
1978 .collect();
1979
1980 assert_eq!(rules.len(), 3);
1981 assert!(rules[0].metadata.is_allowxperm());
1982 if let Some(xperms) = rules[0].extended_permissions() {
1983 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1984 assert_eq!(xperms.xperms_optional_prefix, 0x20);
1985 assert_eq!(xperms.count(), 0x100);
1986 for i in 0x2000..0x20ff {
1987 assert!(xperms.contains(i), "{i}");
1988 }
1989 } else {
1990 panic!("unexpected permission data type")
1991 }
1992 if let Some(xperms) = rules[1].extended_permissions() {
1993 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1994 assert_eq!(xperms.xperms_optional_prefix, 0x10);
1995 assert_eq!(xperms.count(), 0x100);
1996 for i in 0x1000..0x10ff {
1997 assert!(xperms.contains(i), "{i}");
1998 }
1999 } else {
2000 panic!("unexpected permission data type")
2001 }
2002 if let Some(xperms) = rules[2].extended_permissions() {
2003 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2004 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2005 assert_eq!(xperms.count(), 0x100);
2006 for i in 0x0..0xff {
2007 assert!(xperms.contains(i), "{i}");
2008 }
2009 } else {
2010 panic!("unexpected permission data type")
2011 }
2012 }
2013
2014 #[test]
2021 fn parse_allowxperm_three_contiguous_nlmsg_ranges() {
2022 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
2023 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2024 let parsed_policy = &policy.0;
2025 parsed_policy.validate().expect("validate policy");
2026
2027 let class_id =
2028 find_class_by_name(&parsed_policy.classes(), "class_three_contiguous_nlmsg_ranges")
2029 .expect("look up class_three_contiguous_nlmsg_ranges")
2030 .id();
2031
2032 let rules: Vec<_> = parsed_policy
2033 .access_vector_rules_for_test()
2034 .filter(|rule| rule.metadata.target_class() == class_id)
2035 .collect();
2036
2037 assert_eq!(rules.len(), 2);
2038 assert!(rules[0].metadata.is_allowxperm());
2039 if let Some(xperms) = rules[0].extended_permissions() {
2040 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2041 assert_eq!(xperms.xperms_optional_prefix, 0x02);
2042 assert_eq!(xperms.count(), 0x100);
2043 for i in 0x0200..0x02ff {
2044 assert!(xperms.contains(i), "{i}");
2045 }
2046 } else {
2047 panic!("unexpected permission data type")
2048 }
2049 if let Some(xperms) = rules[1].extended_permissions() {
2050 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2051 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2052 assert_eq!(xperms.count(), 0x100);
2053 for i in 0x0..0xff {
2054 assert!(xperms.contains(i), "{i}");
2055 }
2056 } else {
2057 panic!("unexpected permission data type")
2058 }
2059 }
2060
2061 #[test]
2064 fn parse_auditallowxperm() {
2065 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
2066 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2067 let parsed_policy = &policy.0;
2068 parsed_policy.validate().expect("validate policy");
2069
2070 let class_id = find_class_by_name(&parsed_policy.classes(), "class_auditallowxperm")
2071 .expect("look up class_auditallowxperm")
2072 .id();
2073
2074 let rules: Vec<_> = parsed_policy
2075 .access_vector_rules_for_test()
2076 .filter(|rule| rule.metadata.target_class() == class_id)
2077 .collect();
2078
2079 assert_eq!(rules.len(), 2);
2080 assert!(rules[0].metadata.is_auditallowxperm());
2081 if let Some(xperms) = rules[0].extended_permissions() {
2082 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2083 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2084 assert_eq!(xperms.count(), 1);
2085 assert!(xperms.contains(0x10));
2086 } else {
2087 panic!("unexpected permission data type")
2088 }
2089 if let Some(xperms) = rules[1].extended_permissions() {
2090 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
2091 assert_eq!(xperms.xperms_optional_prefix, 0x10);
2092 assert_eq!(xperms.count(), 1);
2093 assert!(xperms.contains(0x1000));
2094 } else {
2095 panic!("unexpected permission data type")
2096 }
2097 }
2098
2099 #[test]
2107 fn parse_dontauditxperm() {
2108 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
2109 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2110 let parsed_policy = &policy.0;
2111 parsed_policy.validate().expect("validate policy");
2112
2113 let class_id = find_class_by_name(&parsed_policy.classes(), "class_dontauditxperm")
2114 .expect("look up class_dontauditxperm")
2115 .id();
2116
2117 let rules: Vec<_> = parsed_policy
2118 .access_vector_rules_for_test()
2119 .filter(|rule| rule.metadata.target_class() == class_id)
2120 .collect();
2121
2122 assert_eq!(rules.len(), 2);
2123 assert!(rules[0].metadata.is_dontauditxperm());
2124 if let Some(xperms) = rules[0].extended_permissions() {
2125 assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2126 assert_eq!(xperms.xperms_optional_prefix, 0x00);
2127 assert_eq!(xperms.count(), 1);
2128 assert!(xperms.contains(0x11));
2129 } else {
2130 panic!("unexpected permission data type")
2131 }
2132 if let Some(xperms) = rules[1].extended_permissions() {
2133 assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
2134 assert_eq!(xperms.xperms_optional_prefix, 0x10);
2135 assert_eq!(xperms.count(), 1);
2136 assert!(xperms.contains(0x1000));
2137 } else {
2138 panic!("unexpected permission data type")
2139 }
2140 }
2141
2142 #[test]
2146 fn parse_auditallowxperm_not_coalesced() {
2147 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
2148 let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2149 let parsed_policy = &policy.0;
2150 parsed_policy.validate().expect("validate policy");
2151
2152 let class_id =
2153 find_class_by_name(&parsed_policy.classes(), "class_auditallowxperm_not_coalesced")
2154 .expect("class_auditallowxperm_not_coalesced")
2155 .id();
2156
2157 let rules: Vec<_> = parsed_policy
2158 .access_vector_rules_for_test()
2159 .filter(|rule| rule.metadata.target_class() == class_id)
2160 .collect();
2161
2162 assert_eq!(rules.len(), 2);
2163 assert!(rules[0].metadata.is_allowxperm());
2164 assert!(!rules[0].metadata.is_auditallowxperm());
2165 if let Some(xperms) = rules[0].extended_permissions() {
2166 assert_eq!(xperms.count(), 1);
2167 assert!(xperms.contains(0xabcd));
2168 } else {
2169 panic!("unexpected permission data type")
2170 }
2171 assert!(!rules[1].metadata.is_allowxperm());
2172 assert!(rules[1].metadata.is_auditallowxperm());
2173 if let Some(xperms) = rules[1].extended_permissions() {
2174 assert_eq!(xperms.count(), 1);
2175 assert!(xperms.contains(0xabcd));
2176 } else {
2177 panic!("unexpected permission data type")
2178 }
2179 }
2180}