1use super::error::{ParseError, ValidateError};
9use super::extensible_bitmap::ExtensibleBitmap;
10use super::parser::ParseStrategy;
11use super::symbols::{MlsLevel, MlsRange};
12use super::{
13 array_type, array_type_validate_deref_both, AccessVector, Array, ClassId, Counted, Parse,
14 RoleId, TypeId, UserId, Validate, ValidateArray,
15};
16
17use anyhow::Context as _;
18use std::fmt::Debug;
19use std::num::NonZeroU32;
20use std::ops::Shl;
21use zerocopy::{little_endian as le, FromBytes, Immutable, KnownLayout, Unaligned};
22
23pub(super) const MIN_POLICY_VERSION_FOR_INFINITIBAND_PARTITION_KEY: u32 = 31;
24
25pub(super) const ACCESS_VECTOR_RULE_DATA_IS_TYPE_ID_MASK: u16 = 0x070;
28pub(super) const ACCESS_VECTOR_RULE_DATA_IS_XPERM_MASK: u16 = 0x0700;
32
33pub(super) const ACCESS_VECTOR_RULE_TYPE_ALLOW: u16 = 0x1;
43pub(super) const ACCESS_VECTOR_RULE_TYPE_AUDITALLOW: u16 = 0x2;
47pub(super) const ACCESS_VECTOR_RULE_TYPE_DONTAUDIT: u16 = 0x4;
51pub(super) const ACCESS_VECTOR_RULE_TYPE_TYPE_TRANSITION: u16 = 0x10;
55#[allow(dead_code)]
59pub(super) const ACCESS_VECTOR_RULE_TYPE_TYPE_MEMBER: u16 = 0x20;
60#[allow(dead_code)]
64pub(super) const ACCESS_VECTOR_RULE_TYPE_TYPE_CHANGE: u16 = 0x40;
65pub(super) const ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM: u16 = 0x100;
70pub(super) const ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM: u16 = 0x200;
75pub(super) const ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM: u16 = 0x400;
80
81pub(super) const XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES: u8 = 1;
87pub(super) const XPERMS_TYPE_IOCTL_PREFIXES: u8 = 2;
91
92#[allow(type_alias_bounds)]
93pub(super) type SimpleArray<PS: ParseStrategy, T> = Array<PS, PS::Output<le::U32>, T>;
94
95impl<PS: ParseStrategy, T: Validate> Validate for SimpleArray<PS, T> {
96 type Error = <T as Validate>::Error;
97
98 fn validate(&self) -> Result<(), Self::Error> {
101 self.data.validate()
102 }
103}
104
105impl Counted for le::U32 {
106 fn count(&self) -> u32 {
107 self.get()
108 }
109}
110
111pub(super) type ConditionalNodes<PS> = Vec<ConditionalNode<PS>>;
112
113impl<PS: ParseStrategy> Validate for ConditionalNodes<PS> {
114 type Error = anyhow::Error;
115
116 fn validate(&self) -> Result<(), Self::Error> {
118 Ok(())
119 }
120}
121
122array_type!(
123 ConditionalNodeItems,
124 PS,
125 PS::Output<ConditionalNodeMetadata>,
126 PS::Slice<ConditionalNodeDatum>
127);
128
129array_type_validate_deref_both!(ConditionalNodeItems);
130
131impl<PS: ParseStrategy> ValidateArray<ConditionalNodeMetadata, ConditionalNodeDatum>
132 for ConditionalNodeItems<PS>
133{
134 type Error = anyhow::Error;
135
136 fn validate_array<'a>(
139 _metadata: &'a ConditionalNodeMetadata,
140 _data: &'a [ConditionalNodeDatum],
141 ) -> Result<(), Self::Error> {
142 Ok(())
143 }
144}
145
146#[derive(Debug, PartialEq)]
147pub(super) struct ConditionalNode<PS: ParseStrategy> {
148 items: ConditionalNodeItems<PS>,
149 true_list: SimpleArray<PS, AccessVectorRules<PS>>,
150 false_list: SimpleArray<PS, AccessVectorRules<PS>>,
151}
152
153impl<PS: ParseStrategy> Parse<PS> for ConditionalNode<PS>
154where
155 ConditionalNodeItems<PS>: Parse<PS>,
156 SimpleArray<PS, AccessVectorRules<PS>>: Parse<PS>,
157{
158 type Error = anyhow::Error;
159
160 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
161 let tail = bytes;
162
163 let (items, tail) = ConditionalNodeItems::parse(tail)
164 .map_err(Into::<anyhow::Error>::into)
165 .context("parsing conditional node items")?;
166
167 let (true_list, tail) = SimpleArray::<PS, AccessVectorRules<PS>>::parse(tail)
168 .map_err(Into::<anyhow::Error>::into)
169 .context("parsing conditional node true list")?;
170
171 let (false_list, tail) = SimpleArray::<PS, AccessVectorRules<PS>>::parse(tail)
172 .map_err(Into::<anyhow::Error>::into)
173 .context("parsing conditional node false list")?;
174
175 Ok((Self { items, true_list, false_list }, tail))
176 }
177}
178
179#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
180#[repr(C, packed)]
181pub(super) struct ConditionalNodeMetadata {
182 state: le::U32,
183 count: le::U32,
184}
185
186impl Counted for ConditionalNodeMetadata {
187 fn count(&self) -> u32 {
188 self.count.get()
189 }
190}
191
192impl Validate for ConditionalNodeMetadata {
193 type Error = anyhow::Error;
194
195 fn validate(&self) -> Result<(), Self::Error> {
197 Ok(())
198 }
199}
200
201#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
202#[repr(C, packed)]
203pub(super) struct ConditionalNodeDatum {
204 node_type: le::U32,
205 boolean: le::U32,
206}
207
208impl Validate for [ConditionalNodeDatum] {
209 type Error = anyhow::Error;
210
211 fn validate(&self) -> Result<(), Self::Error> {
213 Ok(())
214 }
215}
216
217pub(super) type AccessVectorRules<PS> = Vec<AccessVectorRule<PS>>;
226
227impl<PS: ParseStrategy> Validate for AccessVectorRules<PS> {
228 type Error = anyhow::Error;
229
230 fn validate(&self) -> Result<(), Self::Error> {
231 for access_vector_rule in self {
232 access_vector_rule.validate()?;
233 }
234 Ok(())
235 }
236}
237
238#[derive(Debug, PartialEq)]
239pub(super) struct AccessVectorRule<PS: ParseStrategy> {
240 pub metadata: PS::Output<AccessVectorRuleMetadata>,
241 permission_data: PermissionData<PS>,
242}
243
244impl<PS: ParseStrategy> AccessVectorRule<PS> {
245 pub fn is_allow(&self) -> bool {
248 (PS::deref(&self.metadata).access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_ALLOW) != 0
249 }
250
251 pub fn is_auditallow(&self) -> bool {
254 (PS::deref(&self.metadata).access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_AUDITALLOW)
255 != 0
256 }
257
258 pub fn is_dontaudit(&self) -> bool {
261 (PS::deref(&self.metadata).access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_DONTAUDIT) != 0
262 }
263
264 pub fn is_type_transition(&self) -> bool {
267 (PS::deref(&self.metadata).access_vector_rule_type
268 & ACCESS_VECTOR_RULE_TYPE_TYPE_TRANSITION)
269 != 0
270 }
271
272 #[allow(dead_code)]
276 pub fn is_allowxperm(&self) -> bool {
277 (PS::deref(&self.metadata).access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM)
278 != 0
279 }
280
281 #[allow(dead_code)]
285 pub fn is_auditallowxperm(&self) -> bool {
286 (PS::deref(&self.metadata).access_vector_rule_type
287 & ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM)
288 != 0
289 }
290
291 #[allow(dead_code)]
295 pub fn is_dontauditxperm(&self) -> bool {
296 (PS::deref(&self.metadata).access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM)
297 != 0
298 }
299
300 pub fn source_type(&self) -> TypeId {
304 TypeId(NonZeroU32::new(PS::deref(&self.metadata).source_type.into()).unwrap())
305 }
306
307 pub fn target_type(&self) -> TypeId {
311 TypeId(NonZeroU32::new(PS::deref(&self.metadata).target_type.into()).unwrap())
312 }
313
314 pub fn target_class(&self) -> ClassId {
319 ClassId(NonZeroU32::new(PS::deref(&self.metadata).class.into()).unwrap())
320 }
321
322 pub fn access_vector(&self) -> Option<AccessVector> {
328 match &self.permission_data {
329 PermissionData::AccessVector(access_vector_raw) => {
330 Some(AccessVector((*PS::deref(access_vector_raw)).get()))
331 }
332 _ => None,
333 }
334 }
335
336 pub fn new_type(&self) -> Option<TypeId> {
342 match &self.permission_data {
343 PermissionData::NewType(new_type) => {
344 Some(TypeId(NonZeroU32::new(PS::deref(new_type).get().into()).unwrap()))
345 }
346 _ => None,
347 }
348 }
349
350 #[allow(dead_code)]
356 pub fn extended_permissions(&self) -> Option<&ExtendedPermissions> {
357 match &self.permission_data {
358 PermissionData::ExtendedPermissions(xperms) => Some(xperms),
359 _ => None,
360 }
361 }
362}
363
364impl<PS: ParseStrategy> Parse<PS> for AccessVectorRule<PS> {
365 type Error = anyhow::Error;
366
367 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
368 let tail = bytes;
369
370 let num_bytes = tail.len();
371 let (metadata, tail) =
372 PS::parse::<AccessVectorRuleMetadata>(tail).ok_or(ParseError::MissingData {
373 type_name: std::any::type_name::<AccessVectorRuleMetadata>(),
374 type_size: std::mem::size_of::<AccessVectorRuleMetadata>(),
375 num_bytes,
376 })?;
377 let access_vector_rule_type = PS::deref(&metadata).access_vector_rule_type;
378 let num_bytes = tail.len();
379 let (permission_data, tail) =
380 if (access_vector_rule_type & ACCESS_VECTOR_RULE_DATA_IS_XPERM_MASK) != 0 {
381 let (xperms, tail) = ExtendedPermissions::parse(tail)
382 .map_err(Into::<anyhow::Error>::into)
383 .context("parsing extended permissions")?;
384 (PermissionData::ExtendedPermissions(xperms), tail)
385 } else if (access_vector_rule_type & ACCESS_VECTOR_RULE_DATA_IS_TYPE_ID_MASK) != 0 {
386 let (new_type, tail) =
387 PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
388 type_name: "PermissionData::NewType",
389 type_size: std::mem::size_of::<le::U32>(),
390 num_bytes,
391 })?;
392 (PermissionData::NewType(new_type), tail)
393 } else {
394 let (access_vector, tail) =
395 PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
396 type_name: "PermissionData::AccessVector",
397 type_size: std::mem::size_of::<le::U32>(),
398 num_bytes,
399 })?;
400 (PermissionData::AccessVector(access_vector), tail)
401 };
402 Ok((Self { metadata, permission_data }, tail))
403 }
404}
405
406impl<PS: ParseStrategy> Validate for AccessVectorRule<PS> {
407 type Error = anyhow::Error;
408
409 fn validate(&self) -> Result<(), Self::Error> {
410 if PS::deref(&self.metadata).class.get() == 0 {
411 return Err(ValidateError::NonOptionalIdIsZero.into());
412 }
413 if let PermissionData::ExtendedPermissions(xperms) = &self.permission_data {
414 let xperms_type = xperms.xperms_type;
415 if !(xperms_type == XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES
416 || xperms_type == XPERMS_TYPE_IOCTL_PREFIXES)
417 {
418 return Err(
419 ValidateError::InvalidExtendedPermissionsType { type_: xperms_type }.into()
420 );
421 }
422 }
423 Ok(())
424 }
425}
426
427#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
428#[repr(C, packed)]
429pub(super) struct AccessVectorRuleMetadata {
430 source_type: le::U16,
431 target_type: le::U16,
432 class: le::U16,
433 access_vector_rule_type: le::U16,
434}
435
436#[derive(Debug, PartialEq)]
437pub(super) enum PermissionData<PS: ParseStrategy> {
438 AccessVector(PS::Output<le::U32>),
439 NewType(PS::Output<le::U32>),
440 ExtendedPermissions(ExtendedPermissions),
441}
442
443#[derive(Clone, Debug, PartialEq)]
444pub(super) struct ExtendedPermissions {
445 pub(super) xperms_type: u8,
446 pub(super) xperms_optional_prefix: u8,
447 pub(super) xperms_bitmap: XpermsBitmap,
448}
449
450impl<PS: ParseStrategy> Parse<PS> for ExtendedPermissions {
451 type Error = anyhow::Error;
452
453 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
454 let tail = bytes;
455 let num_bytes = tail.len();
456 let (type_, tail) = PS::parse::<u8>(tail).ok_or(ParseError::MissingData {
457 type_name: "ExtendedPermissions::xperms_type",
458 type_size: std::mem::size_of::<u8>(),
459 num_bytes,
460 })?;
461 let xperms_type = *PS::deref(&type_);
462 let num_bytes = tail.len();
463 let (prefix, tail) = PS::parse::<u8>(tail).ok_or(ParseError::MissingData {
464 type_name: "ExtendedPermissions::xperms_optional_prefix",
465 type_size: std::mem::size_of::<u8>(),
466 num_bytes,
467 })?;
468 let xperms_optional_prefix = *PS::deref(&prefix);
469 let num_bytes = tail.len();
470 let (bitmap, tail) = PS::parse::<[le::U32; 8]>(tail).ok_or(ParseError::MissingData {
471 type_name: "ExtendedPermissions::xperms_bitmap",
472 type_size: std::mem::size_of::<[le::U32; 8]>(),
473 num_bytes,
474 })?;
475 Ok((
476 ExtendedPermissions {
477 xperms_type,
478 xperms_optional_prefix,
479 xperms_bitmap: XpermsBitmap(*PS::deref(&bitmap)),
480 },
481 tail,
482 ))
483 }
484}
485
486impl ExtendedPermissions {
487 #[cfg(test)]
488 fn count(&self) -> u64 {
489 let count = self
490 .xperms_bitmap
491 .0
492 .iter()
493 .fold(0, |count, block| (count as u64) + (block.get().count_ones() as u64));
494 match self.xperms_type {
495 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES => count,
496 XPERMS_TYPE_IOCTL_PREFIXES => count * 0x100,
497 _ => unreachable!("invalid xperms_type in validated ExtendedPermissions"),
498 }
499 }
500
501 #[cfg(test)]
502 fn contains(&self, xperm: u16) -> bool {
503 let [postfix, prefix] = xperm.to_le_bytes();
504 if self.xperms_type == XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES
505 && self.xperms_optional_prefix != prefix
506 {
507 return false;
508 }
509 let value = match self.xperms_type {
510 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES => postfix,
511 XPERMS_TYPE_IOCTL_PREFIXES => prefix,
512 _ => unreachable!("invalid xperms_type in validated ExtendedPermissions"),
513 };
514 self.xperms_bitmap.contains(value)
515 }
516}
517
518#[derive(Clone, Debug, PartialEq)]
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, PS, PS::Output<le::U32>, PS::Slice<RoleTransition>);
552
553array_type_validate_deref_both!(RoleTransitions);
554
555impl<PS: ParseStrategy> ValidateArray<le::U32, RoleTransition> for RoleTransitions<PS> {
556 type Error = anyhow::Error;
557
558 fn validate_array<'a>(
560 _metadata: &'a le::U32,
561 _data: &'a [RoleTransition],
562 ) -> Result<(), Self::Error> {
563 _data.validate()
564 }
565}
566
567#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
568#[repr(C, packed)]
569pub(super) struct RoleTransition {
570 role: le::U32,
571 role_type: le::U32,
572 new_role: le::U32,
573 tclass: le::U32,
574}
575
576impl RoleTransition {
577 pub(super) fn current_role(&self) -> RoleId {
578 RoleId(NonZeroU32::new(self.role.get()).unwrap())
579 }
580
581 pub(super) fn type_(&self) -> TypeId {
582 TypeId(NonZeroU32::new(self.role_type.get()).unwrap())
583 }
584
585 pub(super) fn class(&self) -> ClassId {
586 ClassId(NonZeroU32::new(self.tclass.get()).unwrap())
587 }
588
589 pub(super) fn new_role(&self) -> RoleId {
590 RoleId(NonZeroU32::new(self.new_role.get()).unwrap())
591 }
592}
593
594impl Validate for [RoleTransition] {
595 type Error = anyhow::Error;
596
597 fn validate(&self) -> Result<(), Self::Error> {
598 for role_transition in self {
599 if role_transition.tclass.get() == 0 {
600 return Err(ValidateError::NonOptionalIdIsZero.into());
601 }
602 }
603 Ok(())
604 }
605}
606
607array_type!(RoleAllows, PS, PS::Output<le::U32>, PS::Slice<RoleAllow>);
608
609array_type_validate_deref_both!(RoleAllows);
610
611impl<PS: ParseStrategy> ValidateArray<le::U32, RoleAllow> for RoleAllows<PS> {
612 type Error = anyhow::Error;
613
614 fn validate_array<'a>(
616 _metadata: &'a le::U32,
617 _data: &'a [RoleAllow],
618 ) -> Result<(), Self::Error> {
619 Ok(())
620 }
621}
622
623#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
624#[repr(C, packed)]
625pub(super) struct RoleAllow {
626 role: le::U32,
627 new_role: le::U32,
628}
629
630impl RoleAllow {
631 #[allow(dead_code)]
632 pub(super) fn source_role(&self) -> RoleId {
635 RoleId(NonZeroU32::new(self.role.get()).unwrap())
636 }
637
638 #[allow(dead_code)]
639 pub(super) fn new_role(&self) -> RoleId {
642 RoleId(NonZeroU32::new(self.new_role.get()).unwrap())
643 }
644}
645
646impl Validate for [RoleAllow] {
647 type Error = anyhow::Error;
648
649 fn validate(&self) -> Result<(), Self::Error> {
651 Ok(())
652 }
653}
654
655#[derive(Debug, PartialEq)]
656pub(super) enum FilenameTransitionList<PS: ParseStrategy> {
657 PolicyVersionGeq33(SimpleArray<PS, FilenameTransitions<PS>>),
658 PolicyVersionLeq32(SimpleArray<PS, DeprecatedFilenameTransitions<PS>>),
659}
660
661impl<PS: ParseStrategy> Validate for FilenameTransitionList<PS> {
662 type Error = anyhow::Error;
663
664 fn validate(&self) -> Result<(), Self::Error> {
665 match self {
666 Self::PolicyVersionLeq32(list) => list.validate().map_err(Into::<anyhow::Error>::into),
667 Self::PolicyVersionGeq33(list) => list.validate().map_err(Into::<anyhow::Error>::into),
668 }
669 }
670}
671
672pub(super) type FilenameTransitions<PS> = Vec<FilenameTransition<PS>>;
673
674impl<PS: ParseStrategy> Validate for FilenameTransitions<PS> {
675 type Error = anyhow::Error;
676
677 fn validate(&self) -> Result<(), Self::Error> {
679 Ok(())
680 }
681}
682
683#[derive(Debug, PartialEq)]
684pub(super) struct FilenameTransition<PS: ParseStrategy> {
685 filename: SimpleArray<PS, PS::Slice<u8>>,
686 transition_type: PS::Output<le::U32>,
687 transition_class: PS::Output<le::U32>,
688 items: SimpleArray<PS, FilenameTransitionItems<PS>>,
689}
690
691impl<PS: ParseStrategy> FilenameTransition<PS> {
692 pub(super) fn name_bytes(&self) -> &[u8] {
693 PS::deref_slice(&self.filename.data)
694 }
695
696 pub(super) fn target_type(&self) -> TypeId {
697 TypeId(NonZeroU32::new(PS::deref(&self.transition_type).get()).unwrap())
698 }
699
700 pub(super) fn target_class(&self) -> ClassId {
701 ClassId(NonZeroU32::new(PS::deref(&self.transition_class).get()).unwrap())
702 }
703
704 pub(super) fn outputs(&self) -> &[FilenameTransitionItem<PS>] {
705 &self.items.data
706 }
707}
708
709impl<PS: ParseStrategy> Parse<PS> for FilenameTransition<PS>
710where
711 SimpleArray<PS, PS::Slice<u8>>: Parse<PS>,
712 SimpleArray<PS, FilenameTransitionItems<PS>>: Parse<PS>,
713{
714 type Error = anyhow::Error;
715
716 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
717 let tail = bytes;
718
719 let (filename, tail) = SimpleArray::<PS, PS::Slice<u8>>::parse(tail)
720 .map_err(Into::<anyhow::Error>::into)
721 .context("parsing filename for filename transition")?;
722
723 let num_bytes = tail.len();
724 let (transition_type, tail) =
725 PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
726 type_name: "FilenameTransition::transition_type",
727 type_size: std::mem::size_of::<le::U32>(),
728 num_bytes,
729 })?;
730
731 let num_bytes = tail.len();
732 let (transition_class, tail) =
733 PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
734 type_name: "FilenameTransition::transition_class",
735 type_size: std::mem::size_of::<le::U32>(),
736 num_bytes,
737 })?;
738
739 let (items, tail) = SimpleArray::<PS, FilenameTransitionItems<PS>>::parse(tail)
740 .map_err(Into::<anyhow::Error>::into)
741 .context("parsing items for filename transition")?;
742
743 Ok((Self { filename, transition_type, transition_class, items }, tail))
744 }
745}
746
747pub(super) type FilenameTransitionItems<PS> = Vec<FilenameTransitionItem<PS>>;
748
749#[derive(Debug, PartialEq)]
750pub(super) struct FilenameTransitionItem<PS: ParseStrategy> {
751 stypes: ExtensibleBitmap<PS>,
752 out_type: PS::Output<le::U32>,
753}
754
755impl<PS: ParseStrategy> FilenameTransitionItem<PS> {
756 pub(super) fn has_source_type(&self, source_type: TypeId) -> bool {
757 self.stypes.is_set(source_type.0.get() - 1)
758 }
759
760 pub(super) fn out_type(&self) -> TypeId {
761 TypeId(NonZeroU32::new(PS::deref(&self.out_type).get()).unwrap())
762 }
763}
764
765impl<PS: ParseStrategy> Parse<PS> for FilenameTransitionItem<PS>
766where
767 ExtensibleBitmap<PS>: Parse<PS>,
768{
769 type Error = anyhow::Error;
770
771 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
772 let tail = bytes;
773
774 let (stypes, tail) = ExtensibleBitmap::parse(tail)
775 .map_err(Into::<anyhow::Error>::into)
776 .context("parsing stypes extensible bitmap for file transition")?;
777
778 let num_bytes = tail.len();
779 let (out_type, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
780 type_name: "FilenameTransitionItem::out_type",
781 type_size: std::mem::size_of::<le::U32>(),
782 num_bytes,
783 })?;
784
785 Ok((Self { stypes, out_type }, tail))
786 }
787}
788
789pub(super) type DeprecatedFilenameTransitions<PS> = Vec<DeprecatedFilenameTransition<PS>>;
790
791impl<PS: ParseStrategy> Validate for DeprecatedFilenameTransitions<PS> {
792 type Error = anyhow::Error;
793
794 fn validate(&self) -> Result<(), Self::Error> {
796 Ok(())
797 }
798}
799
800#[derive(Debug, PartialEq)]
801pub(super) struct DeprecatedFilenameTransition<PS: ParseStrategy> {
802 filename: SimpleArray<PS, PS::Slice<u8>>,
803 metadata: PS::Output<DeprecatedFilenameTransitionMetadata>,
804}
805
806impl<PS: ParseStrategy> DeprecatedFilenameTransition<PS> {
807 pub(super) fn name_bytes(&self) -> &[u8] {
808 PS::deref_slice(&self.filename.data)
809 }
810
811 pub(super) fn source_type(&self) -> TypeId {
812 TypeId(NonZeroU32::new(PS::deref(&self.metadata).source_type.get()).unwrap())
813 }
814
815 pub(super) fn target_type(&self) -> TypeId {
816 TypeId(NonZeroU32::new(PS::deref(&self.metadata).transition_type.get()).unwrap())
817 }
818
819 pub(super) fn target_class(&self) -> ClassId {
820 ClassId(NonZeroU32::new(PS::deref(&self.metadata).transition_class.get()).unwrap())
821 }
822
823 pub(super) fn out_type(&self) -> TypeId {
824 TypeId(NonZeroU32::new(PS::deref(&self.metadata).out_type.get()).unwrap())
825 }
826}
827
828impl<PS: ParseStrategy> Parse<PS> for DeprecatedFilenameTransition<PS>
829where
830 SimpleArray<PS, PS::Slice<u8>>: Parse<PS>,
831{
832 type Error = anyhow::Error;
833
834 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
835 let tail = bytes;
836
837 let (filename, tail) = SimpleArray::<PS, PS::Slice<u8>>::parse(tail)
838 .map_err(Into::<anyhow::Error>::into)
839 .context("parsing filename for deprecated filename transition")?;
840
841 let num_bytes = tail.len();
842 let (metadata, tail) = PS::parse::<DeprecatedFilenameTransitionMetadata>(tail).ok_or(
843 ParseError::MissingData {
844 type_name: "DeprecatedFilenameTransition::metadata",
845 type_size: std::mem::size_of::<le::U32>(),
846 num_bytes,
847 },
848 )?;
849
850 Ok((Self { filename, metadata }, tail))
851 }
852}
853
854#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
855#[repr(C, packed)]
856pub(super) struct DeprecatedFilenameTransitionMetadata {
857 source_type: le::U32,
858 transition_type: le::U32,
859 transition_class: le::U32,
860 out_type: le::U32,
861}
862
863pub(super) type InitialSids<PS> = Vec<InitialSid<PS>>;
864
865impl<PS: ParseStrategy> Validate for InitialSids<PS> {
866 type Error = anyhow::Error;
867
868 fn validate(&self) -> Result<(), Self::Error> {
870 for initial_sid in crate::InitialSid::all_variants() {
871 self.iter()
872 .find(|initial| initial.id().get() == initial_sid as u32)
873 .ok_or(ValidateError::MissingInitialSid { initial_sid })?;
874 }
875 Ok(())
876 }
877}
878
879#[derive(Debug, PartialEq)]
880pub(super) struct InitialSid<PS: ParseStrategy> {
881 id: PS::Output<le::U32>,
882 context: Context<PS>,
883}
884
885impl<PS: ParseStrategy> InitialSid<PS> {
886 pub(super) fn id(&self) -> le::U32 {
887 *PS::deref(&self.id)
888 }
889
890 pub(super) fn context(&self) -> &Context<PS> {
891 &self.context
892 }
893}
894
895impl<PS: ParseStrategy> Parse<PS> for InitialSid<PS>
896where
897 Context<PS>: Parse<PS>,
898{
899 type Error = anyhow::Error;
900
901 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
902 let tail = bytes;
903
904 let num_bytes = tail.len();
905 let (id, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
906 type_name: "InitialSid::sid",
907 type_size: std::mem::size_of::<le::U32>(),
908 num_bytes,
909 })?;
910
911 let (context, tail) = Context::parse(tail)
912 .map_err(Into::<anyhow::Error>::into)
913 .context("parsing context for initial sid")?;
914
915 Ok((Self { id, context }, tail))
916 }
917}
918
919#[derive(Debug, PartialEq)]
920pub(super) struct Context<PS: ParseStrategy> {
921 metadata: PS::Output<ContextMetadata>,
922 mls_range: MlsRange<PS>,
923}
924
925impl<PS: ParseStrategy> Context<PS> {
926 pub(super) fn user_id(&self) -> UserId {
927 UserId(NonZeroU32::new(PS::deref(&self.metadata).user.get()).unwrap())
928 }
929 pub(super) fn role_id(&self) -> RoleId {
930 RoleId(NonZeroU32::new(PS::deref(&self.metadata).role.get()).unwrap())
931 }
932 pub(super) fn type_id(&self) -> TypeId {
933 TypeId(NonZeroU32::new(PS::deref(&self.metadata).context_type.get()).unwrap())
934 }
935 pub(super) fn low_level(&self) -> &MlsLevel<PS> {
936 self.mls_range.low()
937 }
938 pub(super) fn high_level(&self) -> &Option<MlsLevel<PS>> {
939 self.mls_range.high()
940 }
941}
942
943impl<PS: ParseStrategy> Parse<PS> for Context<PS>
944where
945 MlsRange<PS>: Parse<PS>,
946{
947 type Error = anyhow::Error;
948
949 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
950 let tail = bytes;
951
952 let (metadata, tail) =
953 PS::parse::<ContextMetadata>(tail).context("parsing metadata for context")?;
954
955 let (mls_range, tail) = MlsRange::parse(tail)
956 .map_err(Into::<anyhow::Error>::into)
957 .context("parsing mls range for context")?;
958
959 Ok((Self { metadata, mls_range }, tail))
960 }
961}
962
963#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
964#[repr(C, packed)]
965pub(super) struct ContextMetadata {
966 user: le::U32,
967 role: le::U32,
968 context_type: le::U32,
969}
970
971pub(super) type NamedContextPairs<PS> = Vec<NamedContextPair<PS>>;
972
973impl<PS: ParseStrategy> Validate for NamedContextPairs<PS> {
974 type Error = anyhow::Error;
975
976 fn validate(&self) -> Result<(), Self::Error> {
981 Ok(())
982 }
983}
984
985#[derive(Debug, PartialEq)]
986pub(super) struct NamedContextPair<PS: ParseStrategy> {
987 name: SimpleArray<PS, PS::Slice<u8>>,
988 context1: Context<PS>,
989 context2: Context<PS>,
990}
991
992impl<PS: ParseStrategy> Parse<PS> for NamedContextPair<PS>
993where
994 SimpleArray<PS, PS::Slice<u8>>: Parse<PS>,
995 Context<PS>: Parse<PS>,
996{
997 type Error = anyhow::Error;
998
999 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1000 let tail = bytes;
1001
1002 let (name, tail) = SimpleArray::parse(tail)
1003 .map_err(Into::<anyhow::Error>::into)
1004 .context("parsing filesystem context name")?;
1005
1006 let (context1, tail) = Context::parse(tail)
1007 .map_err(Into::<anyhow::Error>::into)
1008 .context("parsing first context for filesystem context")?;
1009
1010 let (context2, tail) = Context::parse(tail)
1011 .map_err(Into::<anyhow::Error>::into)
1012 .context("parsing second context for filesystem context")?;
1013
1014 Ok((Self { name, context1, context2 }, tail))
1015 }
1016}
1017
1018pub(super) type Ports<PS> = Vec<Port<PS>>;
1019
1020impl<PS: ParseStrategy> Validate for Ports<PS> {
1021 type Error = anyhow::Error;
1022
1023 fn validate(&self) -> Result<(), Self::Error> {
1025 Ok(())
1026 }
1027}
1028
1029#[derive(Debug, PartialEq)]
1030pub(super) struct Port<PS: ParseStrategy> {
1031 metadata: PS::Output<PortMetadata>,
1032 context: Context<PS>,
1033}
1034
1035impl<PS: ParseStrategy> Parse<PS> for Port<PS>
1036where
1037 Context<PS>: Parse<PS>,
1038{
1039 type Error = anyhow::Error;
1040
1041 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1042 let tail = bytes;
1043
1044 let (metadata, tail) =
1045 PS::parse::<PortMetadata>(tail).context("parsing metadata for context")?;
1046
1047 let (context, tail) = Context::parse(tail)
1048 .map_err(Into::<anyhow::Error>::into)
1049 .context("parsing context for port")?;
1050
1051 Ok((Self { metadata, context }, tail))
1052 }
1053}
1054
1055#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1056#[repr(C, packed)]
1057pub(super) struct PortMetadata {
1058 protocol: le::U32,
1059 low_port: le::U32,
1060 high_port: le::U32,
1061}
1062
1063pub(super) type Nodes<PS> = Vec<Node<PS>>;
1064
1065impl<PS: ParseStrategy> Validate for Nodes<PS> {
1066 type Error = anyhow::Error;
1067
1068 fn validate(&self) -> Result<(), Self::Error> {
1070 Ok(())
1071 }
1072}
1073
1074#[derive(Debug, PartialEq)]
1075pub(super) struct Node<PS: ParseStrategy> {
1076 address: PS::Output<le::U32>,
1077 mask: PS::Output<le::U32>,
1078 context: Context<PS>,
1079}
1080
1081impl<PS: ParseStrategy> Parse<PS> for Node<PS>
1082where
1083 Context<PS>: Parse<PS>,
1084{
1085 type Error = anyhow::Error;
1086
1087 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1088 let tail = bytes;
1089
1090 let num_bytes = tail.len();
1091 let (address, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1092 type_name: "Node::address",
1093 type_size: std::mem::size_of::<le::U32>(),
1094 num_bytes,
1095 })?;
1096
1097 let num_bytes = tail.len();
1098 let (mask, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1099 type_name: "Node::mask",
1100 type_size: std::mem::size_of::<le::U32>(),
1101 num_bytes,
1102 })?;
1103
1104 let (context, tail) = Context::parse(tail)
1105 .map_err(Into::<anyhow::Error>::into)
1106 .context("parsing context for node")?;
1107
1108 Ok((Self { address, mask, context }, tail))
1109 }
1110}
1111
1112impl<PS: ParseStrategy> Validate for Node<PS> {
1113 type Error = anyhow::Error;
1114
1115 fn validate(&self) -> Result<(), Self::Error> {
1117 Ok(())
1118 }
1119}
1120
1121pub(super) type FsUses<PS> = Vec<FsUse<PS>>;
1122
1123impl<PS: ParseStrategy> Validate for FsUses<PS> {
1124 type Error = anyhow::Error;
1125
1126 fn validate(&self) -> Result<(), Self::Error> {
1127 for fs_use in self {
1128 fs_use.validate()?;
1129 }
1130 Ok(())
1131 }
1132}
1133
1134#[derive(Debug, PartialEq)]
1135pub(super) struct FsUse<PS: ParseStrategy> {
1136 behavior_and_name: Array<PS, PS::Output<FsUseMetadata>, PS::Slice<u8>>,
1137 context: Context<PS>,
1138}
1139
1140impl<PS: ParseStrategy> FsUse<PS> {
1141 pub fn fs_type(&self) -> &[u8] {
1142 PS::deref_slice(&self.behavior_and_name.data)
1143 }
1144
1145 pub(super) fn behavior(&self) -> FsUseType {
1146 FsUseType::try_from(PS::deref(&self.behavior_and_name.metadata).behavior).unwrap()
1147 }
1148
1149 pub(super) fn context(&self) -> &Context<PS> {
1150 &self.context
1151 }
1152}
1153
1154impl<PS: ParseStrategy> Parse<PS> for FsUse<PS>
1155where
1156 Array<PS, PS::Output<FsUseMetadata>, PS::Slice<u8>>: Parse<PS>,
1157 Context<PS>: Parse<PS>,
1158{
1159 type Error = anyhow::Error;
1160
1161 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1162 let tail = bytes;
1163
1164 let (behavior_and_name, tail) =
1165 Array::<PS, PS::Output<FsUseMetadata>, PS::Slice<u8>>::parse(tail)
1166 .map_err(Into::<anyhow::Error>::into)
1167 .context("parsing fs use metadata")?;
1168
1169 let (context, tail) = Context::parse(tail)
1170 .map_err(Into::<anyhow::Error>::into)
1171 .context("parsing context for fs use")?;
1172
1173 Ok((Self { behavior_and_name, context }, tail))
1174 }
1175}
1176
1177impl<PS: ParseStrategy> Validate for FsUse<PS> {
1178 type Error = anyhow::Error;
1179
1180 fn validate(&self) -> Result<(), Self::Error> {
1181 FsUseType::try_from(PS::deref(&self.behavior_and_name.metadata).behavior)?;
1182
1183 Ok(())
1184 }
1185}
1186
1187#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1188#[repr(C, packed)]
1189pub(super) struct FsUseMetadata {
1190 behavior: le::U32,
1192 name_length: le::U32,
1194}
1195
1196impl Counted for FsUseMetadata {
1197 fn count(&self) -> u32 {
1198 self.name_length.get()
1199 }
1200}
1201
1202#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
1205pub enum FsUseType {
1206 Xattr = 1,
1207 Trans = 2,
1208 Task = 3,
1209}
1210
1211impl TryFrom<le::U32> for FsUseType {
1212 type Error = anyhow::Error;
1213
1214 fn try_from(value: le::U32) -> Result<Self, Self::Error> {
1215 match value.get() {
1216 1 => Ok(FsUseType::Xattr),
1217 2 => Ok(FsUseType::Trans),
1218 3 => Ok(FsUseType::Task),
1219 _ => Err(ValidateError::InvalidFsUseType { value: value.get() }.into()),
1220 }
1221 }
1222}
1223
1224pub(super) type IPv6Nodes<PS> = Vec<IPv6Node<PS>>;
1225
1226impl<PS: ParseStrategy> Validate for IPv6Nodes<PS> {
1227 type Error = anyhow::Error;
1228
1229 fn validate(&self) -> Result<(), Self::Error> {
1231 Ok(())
1232 }
1233}
1234
1235#[derive(Debug, PartialEq)]
1236pub(super) struct IPv6Node<PS: ParseStrategy> {
1237 address: PS::Output<[le::U32; 4]>,
1238 mask: PS::Output<[le::U32; 4]>,
1239 context: Context<PS>,
1240}
1241
1242impl<PS: ParseStrategy> Parse<PS> for IPv6Node<PS>
1243where
1244 Context<PS>: Parse<PS>,
1245{
1246 type Error = anyhow::Error;
1247
1248 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1249 let tail = bytes;
1250
1251 let num_bytes = tail.len();
1252 let (address, tail) = PS::parse::<[le::U32; 4]>(tail).ok_or(ParseError::MissingData {
1253 type_name: "IPv6Node::address",
1254 type_size: std::mem::size_of::<le::U32>(),
1255 num_bytes,
1256 })?;
1257
1258 let num_bytes = tail.len();
1259 let (mask, tail) = PS::parse::<[le::U32; 4]>(tail).ok_or(ParseError::MissingData {
1260 type_name: "IPv6Node::mask",
1261 type_size: std::mem::size_of::<le::U32>(),
1262 num_bytes,
1263 })?;
1264
1265 let (context, tail) = Context::parse(tail)
1266 .map_err(Into::<anyhow::Error>::into)
1267 .context("parsing context for ipv6 node")?;
1268
1269 Ok((Self { address, mask, context }, tail))
1270 }
1271}
1272
1273pub(super) type InfinitiBandPartitionKeys<PS> = Vec<InfinitiBandPartitionKey<PS>>;
1274
1275impl<PS: ParseStrategy> Validate for InfinitiBandPartitionKeys<PS> {
1276 type Error = anyhow::Error;
1277
1278 fn validate(&self) -> Result<(), Self::Error> {
1280 Ok(())
1281 }
1282}
1283
1284#[derive(Debug, PartialEq)]
1285pub(super) struct InfinitiBandPartitionKey<PS: ParseStrategy> {
1286 low: PS::Output<le::U32>,
1287 high: PS::Output<le::U32>,
1288 context: Context<PS>,
1289}
1290
1291impl<PS: ParseStrategy> Parse<PS> for InfinitiBandPartitionKey<PS>
1292where
1293 Context<PS>: Parse<PS>,
1294{
1295 type Error = anyhow::Error;
1296
1297 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1298 let tail = bytes;
1299
1300 let num_bytes = tail.len();
1301 let (low, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1302 type_name: "InfinitiBandPartitionKey::low",
1303 type_size: std::mem::size_of::<le::U32>(),
1304 num_bytes,
1305 })?;
1306
1307 let num_bytes = tail.len();
1308 let (high, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1309 type_name: "InfinitiBandPartitionKey::high",
1310 type_size: std::mem::size_of::<le::U32>(),
1311 num_bytes,
1312 })?;
1313
1314 let (context, tail) = Context::parse(tail)
1315 .map_err(Into::<anyhow::Error>::into)
1316 .context("parsing context for infiniti band partition key")?;
1317
1318 Ok((Self { low, high, context }, tail))
1319 }
1320}
1321
1322impl<PS: ParseStrategy> Validate for InfinitiBandPartitionKey<PS> {
1323 type Error = anyhow::Error;
1324
1325 fn validate(&self) -> Result<(), Self::Error> {
1327 Ok(())
1328 }
1329}
1330
1331pub(super) type InfinitiBandEndPorts<PS> = Vec<InfinitiBandEndPort<PS>>;
1332
1333impl<PS: ParseStrategy> Validate for InfinitiBandEndPorts<PS> {
1334 type Error = anyhow::Error;
1335
1336 fn validate(&self) -> Result<(), Self::Error> {
1338 Ok(())
1339 }
1340}
1341
1342#[derive(Debug, PartialEq)]
1343pub(super) struct InfinitiBandEndPort<PS: ParseStrategy> {
1344 port_and_name: Array<PS, PS::Output<InfinitiBandEndPortMetadata>, PS::Slice<u8>>,
1345 context: Context<PS>,
1346}
1347
1348impl<PS: ParseStrategy> Parse<PS> for InfinitiBandEndPort<PS>
1349where
1350 Array<PS, PS::Output<InfinitiBandEndPortMetadata>, PS::Slice<u8>>: Parse<PS>,
1351 Context<PS>: Parse<PS>,
1352{
1353 type Error = anyhow::Error;
1354
1355 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1356 let tail = bytes;
1357
1358 let (port_and_name, tail) =
1359 Array::<PS, PS::Output<InfinitiBandEndPortMetadata>, PS::Slice<u8>>::parse(tail)
1360 .map_err(Into::<anyhow::Error>::into)
1361 .context("parsing infiniti band end port metadata")?;
1362
1363 let (context, tail) = Context::parse(tail)
1364 .map_err(Into::<anyhow::Error>::into)
1365 .context("parsing context for infiniti band end port")?;
1366
1367 Ok((Self { port_and_name, context }, tail))
1368 }
1369}
1370
1371#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1372#[repr(C, packed)]
1373pub(super) struct InfinitiBandEndPortMetadata {
1374 length: le::U32,
1375 port: le::U32,
1376}
1377
1378impl Counted for InfinitiBandEndPortMetadata {
1379 fn count(&self) -> u32 {
1380 self.length.get()
1381 }
1382}
1383
1384pub(super) type GenericFsContexts<PS> = Vec<GenericFsContext<PS>>;
1385
1386impl<PS: ParseStrategy> Validate for GenericFsContexts<PS> {
1387 type Error = anyhow::Error;
1388
1389 fn validate(&self) -> Result<(), Self::Error> {
1391 Ok(())
1392 }
1393}
1394
1395#[derive(Debug, PartialEq)]
1398pub(super) struct GenericFsContext<PS: ParseStrategy> {
1399 fs_type: SimpleArray<PS, PS::Slice<u8>>,
1401 contexts: SimpleArray<PS, FsContexts<PS>>,
1403}
1404
1405impl<PS: ParseStrategy> GenericFsContext<PS> {
1406 pub(super) fn fs_type(&self) -> &[u8] {
1407 PS::deref_slice(&self.fs_type.data)
1408 }
1409
1410 pub(super) fn contexts(&self) -> &FsContexts<PS> {
1411 &self.contexts.data
1412 }
1413}
1414
1415impl<PS: ParseStrategy> Parse<PS> for GenericFsContext<PS>
1416where
1417 SimpleArray<PS, PS::Slice<u8>>: Parse<PS>,
1418 SimpleArray<PS, FsContexts<PS>>: Parse<PS>,
1419{
1420 type Error = anyhow::Error;
1421
1422 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1423 let tail = bytes;
1424
1425 let (fs_type, tail) = SimpleArray::<PS, PS::Slice<u8>>::parse(tail)
1426 .map_err(Into::<anyhow::Error>::into)
1427 .context("parsing generic filesystem context name")?;
1428
1429 let (contexts, tail) = SimpleArray::<PS, FsContexts<PS>>::parse(tail)
1430 .map_err(Into::<anyhow::Error>::into)
1431 .context("parsing generic filesystem contexts")?;
1432
1433 Ok((Self { fs_type, contexts }, tail))
1434 }
1435}
1436
1437pub(super) type FsContexts<PS> = Vec<FsContext<PS>>;
1438
1439#[derive(Debug, PartialEq)]
1440pub(super) struct FsContext<PS: ParseStrategy> {
1441 partial_path: SimpleArray<PS, PS::Slice<u8>>,
1444 class: PS::Output<le::U32>,
1448 context: Context<PS>,
1450}
1451
1452impl<PS: ParseStrategy> FsContext<PS> {
1453 pub(super) fn partial_path(&self) -> &[u8] {
1454 PS::deref_slice(&self.partial_path.data)
1455 }
1456
1457 pub(super) fn context(&self) -> &Context<PS> {
1458 &self.context
1459 }
1460
1461 pub(super) fn class(&self) -> Option<ClassId> {
1462 NonZeroU32::new((*PS::deref(&self.class)).into()).map(ClassId)
1463 }
1464}
1465
1466impl<PS: ParseStrategy> Parse<PS> for FsContext<PS>
1467where
1468 SimpleArray<PS, PS::Slice<u8>>: Parse<PS>,
1469 Context<PS>: Parse<PS>,
1470{
1471 type Error = anyhow::Error;
1472
1473 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1474 let tail = bytes;
1475
1476 let (partial_path, tail) = SimpleArray::<PS, PS::Slice<u8>>::parse(tail)
1477 .map_err(Into::<anyhow::Error>::into)
1478 .context("parsing filesystem context partial path")?;
1479
1480 let num_bytes = tail.len();
1481 let (class, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1482 type_name: "FsContext::class",
1483 type_size: std::mem::size_of::<le::U32>(),
1484 num_bytes,
1485 })?;
1486
1487 let (context, tail) = Context::parse(tail)
1488 .map_err(Into::<anyhow::Error>::into)
1489 .context("parsing context for filesystem context")?;
1490
1491 Ok((Self { partial_path, class, context }, tail))
1492 }
1493}
1494
1495pub(super) type RangeTransitions<PS> = Vec<RangeTransition<PS>>;
1496
1497impl<PS: ParseStrategy> Validate for RangeTransitions<PS> {
1498 type Error = anyhow::Error;
1499
1500 fn validate(&self) -> Result<(), Self::Error> {
1502 for range_transition in self {
1503 if PS::deref(&range_transition.metadata).target_class.get() == 0 {
1504 return Err(ValidateError::NonOptionalIdIsZero.into());
1505 }
1506 }
1507 Ok(())
1508 }
1509}
1510
1511#[derive(Debug, PartialEq)]
1512pub(super) struct RangeTransition<PS: ParseStrategy> {
1513 metadata: PS::Output<RangeTransitionMetadata>,
1514 mls_range: MlsRange<PS>,
1515}
1516
1517impl<PS: ParseStrategy> RangeTransition<PS> {
1518 pub fn source_type(&self) -> TypeId {
1519 TypeId(NonZeroU32::new(PS::deref(&self.metadata).source_type.get()).unwrap())
1520 }
1521
1522 pub fn target_type(&self) -> TypeId {
1523 TypeId(NonZeroU32::new(PS::deref(&self.metadata).target_type.get()).unwrap())
1524 }
1525
1526 pub fn target_class(&self) -> ClassId {
1527 ClassId(NonZeroU32::new(PS::deref(&self.metadata).target_class.get()).unwrap())
1528 }
1529
1530 pub fn mls_range(&self) -> &MlsRange<PS> {
1531 &self.mls_range
1532 }
1533}
1534
1535impl<PS: ParseStrategy> Parse<PS> for RangeTransition<PS>
1536where
1537 MlsRange<PS>: Parse<PS>,
1538{
1539 type Error = anyhow::Error;
1540
1541 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1542 let tail = bytes;
1543
1544 let (metadata, tail) = PS::parse::<RangeTransitionMetadata>(tail)
1545 .context("parsing range transition metadata")?;
1546
1547 let (mls_range, tail) = MlsRange::parse(tail)
1548 .map_err(Into::<anyhow::Error>::into)
1549 .context("parsing mls range for range transition")?;
1550
1551 Ok((Self { metadata, mls_range }, tail))
1552 }
1553}
1554
1555#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1556#[repr(C, packed)]
1557pub(super) struct RangeTransitionMetadata {
1558 source_type: le::U32,
1559 target_type: le::U32,
1560 target_class: le::U32,
1561}
1562
1563#[cfg(test)]
1564mod tests {
1565 use super::super::{find_class_by_name, parse_policy_by_reference};
1566 use super::*;
1567
1568 #[test]
1569 fn parse_allowxperm_one_ioctl() {
1570 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1571 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1572 let parsed_policy = &policy.0;
1573 Validate::validate(parsed_policy).expect("validate policy");
1574
1575 let class_id = find_class_by_name(parsed_policy.classes(), "class_one_ioctl")
1576 .expect("look up class_one_ioctl")
1577 .id();
1578
1579 let rules: Vec<_> = parsed_policy
1580 .access_vector_rules()
1581 .into_iter()
1582 .filter(|rule| rule.target_class() == class_id)
1583 .collect();
1584
1585 assert_eq!(rules.len(), 1);
1586 assert!(rules[0].is_allowxperm());
1587 if let Some(xperms) = rules[0].extended_permissions() {
1588 assert_eq!(xperms.count(), 1);
1589 assert!(xperms.contains(0xabcd));
1590 } else {
1591 panic!("unexpected permission data type")
1592 }
1593 }
1594
1595 #[test]
1598 fn parse_allowxperm_two_ioctls_same_range() {
1599 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1600 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1601 let parsed_policy = &policy.0;
1602 Validate::validate(parsed_policy).expect("validate policy");
1603
1604 let class_id = find_class_by_name(parsed_policy.classes(), "class_two_ioctls_same_range")
1605 .expect("look up class_two_ioctls_same_range")
1606 .id();
1607
1608 let rules: Vec<_> = parsed_policy
1609 .access_vector_rules()
1610 .into_iter()
1611 .filter(|rule| rule.target_class() == class_id)
1612 .collect();
1613
1614 assert_eq!(rules.len(), 1);
1615 assert!(rules[0].is_allowxperm());
1616 if let Some(xperms) = rules[0].extended_permissions() {
1617 assert_eq!(xperms.count(), 2);
1618 assert!(xperms.contains(0x1234));
1619 assert!(xperms.contains(0x1256));
1620 } else {
1621 panic!("unexpected permission data type")
1622 }
1623 }
1624
1625 #[test]
1628 fn parse_allowxperm_two_ioctls_different_range() {
1629 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1630 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1631 let parsed_policy = &policy.0;
1632 Validate::validate(parsed_policy).expect("validate policy");
1633
1634 let class_id = find_class_by_name(parsed_policy.classes(), "class_two_ioctls_diff_range")
1635 .expect("look up class_two_ioctls_diff_range")
1636 .id();
1637
1638 let rules: Vec<_> = parsed_policy
1639 .access_vector_rules()
1640 .into_iter()
1641 .filter(|rule| rule.target_class() == class_id)
1642 .collect();
1643
1644 assert_eq!(rules.len(), 2);
1645 assert!(rules[0].is_allowxperm());
1646 if let Some(xperms) = rules[0].extended_permissions() {
1647 assert_eq!(xperms.count(), 1);
1648 assert!(xperms.contains(0x5678));
1649 } else {
1650 panic!("unexpected permission data type")
1651 }
1652 assert!(rules[1].is_allowxperm());
1653 if let Some(xperms) = rules[1].extended_permissions() {
1654 assert_eq!(xperms.count(), 1);
1655 assert!(xperms.contains(0x1234));
1656 } else {
1657 panic!("unexpected permission data type")
1658 }
1659 }
1660
1661 #[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_reference(policy_bytes.as_slice()).expect("parse policy");
1665 let parsed_policy = &policy.0;
1666 Validate::validate(parsed_policy).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()
1674 .into_iter()
1675 .filter(|rule| rule.target_class() == class_id)
1676 .collect();
1677
1678 assert_eq!(rules.len(), 1);
1679 assert!(rules[0].is_allowxperm());
1680 if let Some(xperms) = rules[0].extended_permissions() {
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]
1690 fn parse_allowxperm_all_ioctls() {
1691 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1692 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1693 let parsed_policy = &policy.0;
1694 Validate::validate(parsed_policy).expect("validate policy");
1695
1696 let class_id = find_class_by_name(parsed_policy.classes(), "class_all_ioctls")
1697 .expect("look up class_all_ioctls")
1698 .id();
1699
1700 let rules: Vec<_> = parsed_policy
1701 .access_vector_rules()
1702 .into_iter()
1703 .filter(|rule| rule.target_class() == class_id)
1704 .collect();
1705
1706 assert_eq!(rules.len(), 1);
1707 assert!(rules[0].is_allowxperm());
1708 if let Some(xperms) = rules[0].extended_permissions() {
1709 assert_eq!(xperms.count(), 0x10000);
1710 } else {
1711 panic!("unexpected permission data type")
1712 }
1713 }
1714
1715 #[test]
1719 fn parse_allowxperm_overlapping_ranges() {
1720 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1721 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1722 let parsed_policy = &policy.0;
1723 Validate::validate(parsed_policy).expect("validate policy");
1724
1725 let class_id = find_class_by_name(parsed_policy.classes(), "class_overlapping_ranges")
1726 .expect("look up class_overlapping_ranges")
1727 .id();
1728
1729 let rules: Vec<_> = parsed_policy
1730 .access_vector_rules()
1731 .into_iter()
1732 .filter(|rule| rule.target_class() == class_id)
1733 .collect();
1734
1735 assert_eq!(rules.len(), 2);
1736 assert!(rules[0].is_allowxperm());
1737 if let Some(xperms) = rules[0].extended_permissions() {
1738 assert_eq!(xperms.count(), 0x100);
1739 assert!(xperms.contains(0x1000));
1741 assert!(xperms.contains(0x10ab));
1742 } else {
1743 panic!("unexpected permission data type")
1744 }
1745 assert!(rules[1].is_allowxperm());
1746 if let Some(xperms) = rules[1].extended_permissions() {
1747 assert_eq!(xperms.count(), 2);
1748 assert!(xperms.contains(0x1000));
1749 assert!(xperms.contains(0x1001));
1750 } else {
1751 panic!("unexpected permission data type")
1752 }
1753 }
1754
1755 #[test]
1758 fn parse_auditallowxperm() {
1759 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1760 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1761 let parsed_policy = &policy.0;
1762 Validate::validate(parsed_policy).expect("validate policy");
1763
1764 let class_id = find_class_by_name(parsed_policy.classes(), "class_auditallowxperm")
1765 .expect("look up class_auditallowxperm")
1766 .id();
1767
1768 let rules: Vec<_> = parsed_policy
1769 .access_vector_rules()
1770 .into_iter()
1771 .filter(|rule| rule.target_class() == class_id)
1772 .collect();
1773
1774 assert_eq!(rules.len(), 1);
1775 assert!(rules[0].is_auditallowxperm());
1776 if let Some(xperms) = rules[0].extended_permissions() {
1777 assert_eq!(xperms.count(), 1);
1778 assert!(xperms.contains(0x1000));
1779 } else {
1780 panic!("unexpected permission data type")
1781 }
1782 }
1783
1784 #[test]
1792 fn parse_dontauditxperm() {
1793 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1794 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1795 let parsed_policy = &policy.0;
1796 Validate::validate(parsed_policy).expect("validate policy");
1797
1798 let class_id = find_class_by_name(parsed_policy.classes(), "class_dontauditxperm")
1799 .expect("look up class_dontauditxperm")
1800 .id();
1801
1802 let rules: Vec<_> = parsed_policy
1803 .access_vector_rules()
1804 .into_iter()
1805 .filter(|rule| rule.target_class() == class_id)
1806 .collect();
1807
1808 assert_eq!(rules.len(), 1);
1809 assert!(rules[0].is_dontauditxperm());
1810 if let Some(xperms) = rules[0].extended_permissions() {
1811 assert_eq!(xperms.count(), 1);
1812 assert!(xperms.contains(0x1000));
1813 } else {
1814 panic!("unexpected permission data type")
1815 }
1816 }
1817}