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