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