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