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