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 pub fn is_allowxperm(&self) -> bool {
276 (PS::deref(&self.metadata).access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM)
277 != 0
278 }
279
280 pub fn is_auditallowxperm(&self) -> bool {
284 (PS::deref(&self.metadata).access_vector_rule_type
285 & ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM)
286 != 0
287 }
288
289 pub fn is_dontauditxperm(&self) -> bool {
293 (PS::deref(&self.metadata).access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM)
294 != 0
295 }
296
297 pub fn source_type(&self) -> TypeId {
301 TypeId(NonZeroU32::new(PS::deref(&self.metadata).source_type.into()).unwrap())
302 }
303
304 pub fn target_type(&self) -> TypeId {
308 TypeId(NonZeroU32::new(PS::deref(&self.metadata).target_type.into()).unwrap())
309 }
310
311 pub fn target_class(&self) -> ClassId {
316 ClassId(NonZeroU32::new(PS::deref(&self.metadata).class.into()).unwrap())
317 }
318
319 pub fn access_vector(&self) -> Option<AccessVector> {
325 match &self.permission_data {
326 PermissionData::AccessVector(access_vector_raw) => {
327 Some(AccessVector((*PS::deref(access_vector_raw)).get()))
328 }
329 _ => None,
330 }
331 }
332
333 pub fn new_type(&self) -> Option<TypeId> {
339 match &self.permission_data {
340 PermissionData::NewType(new_type) => {
341 Some(TypeId(NonZeroU32::new(PS::deref(new_type).get().into()).unwrap()))
342 }
343 _ => None,
344 }
345 }
346
347 pub fn extended_permissions(&self) -> Option<&ExtendedPermissions> {
353 match &self.permission_data {
354 PermissionData::ExtendedPermissions(xperms) => Some(xperms),
355 _ => None,
356 }
357 }
358}
359
360impl<PS: ParseStrategy> Parse<PS> for AccessVectorRule<PS> {
361 type Error = anyhow::Error;
362
363 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
364 let tail = bytes;
365
366 let num_bytes = tail.len();
367 let (metadata, tail) =
368 PS::parse::<AccessVectorRuleMetadata>(tail).ok_or_else(|| ParseError::MissingData {
369 type_name: std::any::type_name::<AccessVectorRuleMetadata>(),
370 type_size: std::mem::size_of::<AccessVectorRuleMetadata>(),
371 num_bytes,
372 })?;
373 let access_vector_rule_type = PS::deref(&metadata).access_vector_rule_type;
374 let num_bytes = tail.len();
375 let (permission_data, tail) =
376 if (access_vector_rule_type & ACCESS_VECTOR_RULE_DATA_IS_XPERM_MASK) != 0 {
377 let (xperms, tail) = ExtendedPermissions::parse(tail)
378 .map_err(Into::<anyhow::Error>::into)
379 .context("parsing extended permissions")?;
380 (PermissionData::ExtendedPermissions(xperms), tail)
381 } else if (access_vector_rule_type & ACCESS_VECTOR_RULE_DATA_IS_TYPE_ID_MASK) != 0 {
382 let (new_type, tail) =
383 PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
384 type_name: "PermissionData::NewType",
385 type_size: std::mem::size_of::<le::U32>(),
386 num_bytes,
387 })?;
388 (PermissionData::NewType(new_type), tail)
389 } else {
390 let (access_vector, tail) =
391 PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
392 type_name: "PermissionData::AccessVector",
393 type_size: std::mem::size_of::<le::U32>(),
394 num_bytes,
395 })?;
396 (PermissionData::AccessVector(access_vector), tail)
397 };
398 Ok((Self { metadata, permission_data }, tail))
399 }
400}
401
402impl<PS: ParseStrategy> Validate for AccessVectorRule<PS> {
403 type Error = anyhow::Error;
404
405 fn validate(&self) -> Result<(), Self::Error> {
406 if PS::deref(&self.metadata).class.get() == 0 {
407 return Err(ValidateError::NonOptionalIdIsZero.into());
408 }
409 if let PermissionData::ExtendedPermissions(xperms) = &self.permission_data {
410 let xperms_type = xperms.xperms_type;
411 if !(xperms_type == XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES
412 || xperms_type == XPERMS_TYPE_IOCTL_PREFIXES)
413 {
414 return Err(
415 ValidateError::InvalidExtendedPermissionsType { type_: xperms_type }.into()
416 );
417 }
418 }
419 Ok(())
420 }
421}
422
423#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
424#[repr(C, packed)]
425pub(super) struct AccessVectorRuleMetadata {
426 source_type: le::U16,
427 target_type: le::U16,
428 class: le::U16,
429 access_vector_rule_type: le::U16,
430}
431
432#[derive(Debug, PartialEq)]
433pub(super) enum PermissionData<PS: ParseStrategy> {
434 AccessVector(PS::Output<le::U32>),
435 NewType(PS::Output<le::U32>),
436 ExtendedPermissions(ExtendedPermissions),
437}
438
439#[derive(Clone, Debug, PartialEq)]
440pub(super) struct ExtendedPermissions {
441 pub(super) xperms_type: u8,
442 pub(super) xperms_optional_prefix: u8,
443 pub(super) xperms_bitmap: XpermsBitmap,
444}
445
446impl<PS: ParseStrategy> Parse<PS> for ExtendedPermissions {
447 type Error = anyhow::Error;
448
449 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
450 let tail = bytes;
451 let num_bytes = tail.len();
452 let (type_, tail) = PS::parse::<u8>(tail).ok_or(ParseError::MissingData {
453 type_name: "ExtendedPermissions::xperms_type",
454 type_size: std::mem::size_of::<u8>(),
455 num_bytes,
456 })?;
457 let xperms_type = *PS::deref(&type_);
458 let num_bytes = tail.len();
459 let (prefix, tail) = PS::parse::<u8>(tail).ok_or(ParseError::MissingData {
460 type_name: "ExtendedPermissions::xperms_optional_prefix",
461 type_size: std::mem::size_of::<u8>(),
462 num_bytes,
463 })?;
464 let xperms_optional_prefix = *PS::deref(&prefix);
465 let num_bytes = tail.len();
466 let (bitmap, tail) = PS::parse::<[le::U32; 8]>(tail).ok_or(ParseError::MissingData {
467 type_name: "ExtendedPermissions::xperms_bitmap",
468 type_size: std::mem::size_of::<[le::U32; 8]>(),
469 num_bytes,
470 })?;
471 Ok((
472 ExtendedPermissions {
473 xperms_type,
474 xperms_optional_prefix,
475 xperms_bitmap: XpermsBitmap(*PS::deref(&bitmap)),
476 },
477 tail,
478 ))
479 }
480}
481
482impl ExtendedPermissions {
483 #[cfg(test)]
484 fn count(&self) -> u64 {
485 let count = self
486 .xperms_bitmap
487 .0
488 .iter()
489 .fold(0, |count, block| (count as u64) + (block.get().count_ones() as u64));
490 match self.xperms_type {
491 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES => count,
492 XPERMS_TYPE_IOCTL_PREFIXES => count * 0x100,
493 _ => unreachable!("invalid xperms_type in validated ExtendedPermissions"),
494 }
495 }
496
497 #[cfg(test)]
498 fn contains(&self, xperm: u16) -> bool {
499 let [postfix, prefix] = xperm.to_le_bytes();
500 if self.xperms_type == XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES
501 && self.xperms_optional_prefix != prefix
502 {
503 return false;
504 }
505 let value = match self.xperms_type {
506 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES => postfix,
507 XPERMS_TYPE_IOCTL_PREFIXES => prefix,
508 _ => unreachable!("invalid xperms_type in validated ExtendedPermissions"),
509 };
510 self.xperms_bitmap.contains(value)
511 }
512}
513
514#[derive(Clone, Debug, PartialEq)]
516pub struct XpermsBitmap([le::U32; 8]);
517
518impl XpermsBitmap {
519 const BITMAP_BLOCKS: usize = 8;
520 pub const ALL: Self = Self([le::U32::MAX_VALUE; Self::BITMAP_BLOCKS]);
521 pub const NONE: Self = Self([le::U32::ZERO; Self::BITMAP_BLOCKS]);
522
523 #[cfg(test)]
524 pub fn new(elements: [le::U32; 8]) -> Self {
525 Self(elements)
526 }
527
528 pub fn contains(&self, value: u8) -> bool {
529 let block_index = (value as usize) / 32;
530 let bit_index = ((value as usize) % 32) as u32;
531 self.0[block_index] & le::U32::new(1).shl(bit_index) != 0
532 }
533}
534
535impl std::ops::BitOrAssign<&Self> for XpermsBitmap {
536 fn bitor_assign(&mut self, rhs: &Self) {
537 (0..Self::BITMAP_BLOCKS).for_each(|i| self.0[i] |= rhs.0[i])
538 }
539}
540
541impl std::ops::SubAssign<&Self> for XpermsBitmap {
542 fn sub_assign(&mut self, rhs: &Self) {
543 (0..Self::BITMAP_BLOCKS).for_each(|i| self.0[i] = self.0[i] ^ (self.0[i] & rhs.0[i]))
544 }
545}
546
547array_type!(RoleTransitions, PS, PS::Output<le::U32>, PS::Slice<RoleTransition>);
548
549array_type_validate_deref_both!(RoleTransitions);
550
551impl<PS: ParseStrategy> ValidateArray<le::U32, RoleTransition> for RoleTransitions<PS> {
552 type Error = anyhow::Error;
553
554 fn validate_array<'a>(
556 _metadata: &'a le::U32,
557 _data: &'a [RoleTransition],
558 ) -> Result<(), Self::Error> {
559 _data.validate()
560 }
561}
562
563#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
564#[repr(C, packed)]
565pub(super) struct RoleTransition {
566 role: le::U32,
567 role_type: le::U32,
568 new_role: le::U32,
569 tclass: le::U32,
570}
571
572impl RoleTransition {
573 pub(super) fn current_role(&self) -> RoleId {
574 RoleId(NonZeroU32::new(self.role.get()).unwrap())
575 }
576
577 pub(super) fn type_(&self) -> TypeId {
578 TypeId(NonZeroU32::new(self.role_type.get()).unwrap())
579 }
580
581 pub(super) fn class(&self) -> ClassId {
582 ClassId(NonZeroU32::new(self.tclass.get()).unwrap())
583 }
584
585 pub(super) fn new_role(&self) -> RoleId {
586 RoleId(NonZeroU32::new(self.new_role.get()).unwrap())
587 }
588}
589
590impl Validate for [RoleTransition] {
591 type Error = anyhow::Error;
592
593 fn validate(&self) -> Result<(), Self::Error> {
594 for role_transition in self {
595 NonZeroU32::new(role_transition.role.get())
596 .ok_or(ValidateError::NonOptionalIdIsZero)?;
597 NonZeroU32::new(role_transition.role_type.get())
598 .ok_or(ValidateError::NonOptionalIdIsZero)?;
599 NonZeroU32::new(role_transition.tclass.get())
600 .ok_or(ValidateError::NonOptionalIdIsZero)?;
601 NonZeroU32::new(role_transition.new_role.get())
602 .ok_or(ValidateError::NonOptionalIdIsZero)?;
603 }
604 Ok(())
605 }
606}
607
608array_type!(RoleAllows, PS, PS::Output<le::U32>, PS::Slice<RoleAllow>);
609
610array_type_validate_deref_both!(RoleAllows);
611
612impl<PS: ParseStrategy> ValidateArray<le::U32, RoleAllow> for RoleAllows<PS> {
613 type Error = anyhow::Error;
614
615 fn validate_array<'a>(
617 _metadata: &'a le::U32,
618 _data: &'a [RoleAllow],
619 ) -> Result<(), Self::Error> {
620 Ok(())
621 }
622}
623
624#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
625#[repr(C, packed)]
626pub(super) struct RoleAllow {
627 role: le::U32,
628 new_role: le::U32,
629}
630
631impl RoleAllow {
632 pub(super) fn source_role(&self) -> RoleId {
633 RoleId(NonZeroU32::new(self.role.get()).unwrap())
634 }
635
636 pub(super) fn new_role(&self) -> RoleId {
637 RoleId(NonZeroU32::new(self.new_role.get()).unwrap())
638 }
639}
640
641impl Validate for [RoleAllow] {
642 type Error = anyhow::Error;
643
644 fn validate(&self) -> Result<(), Self::Error> {
645 for rule in self {
646 NonZeroU32::new(rule.role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
647 NonZeroU32::new(rule.new_role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
648 }
649 Ok(())
650 }
651}
652
653#[derive(Debug, PartialEq)]
654pub(super) enum FilenameTransitionList<PS: ParseStrategy> {
655 PolicyVersionGeq33(SimpleArray<PS, FilenameTransitions<PS>>),
656 PolicyVersionLeq32(SimpleArray<PS, DeprecatedFilenameTransitions<PS>>),
657}
658
659impl<PS: ParseStrategy> Validate for FilenameTransitionList<PS> {
660 type Error = anyhow::Error;
661
662 fn validate(&self) -> Result<(), Self::Error> {
663 match self {
664 Self::PolicyVersionLeq32(list) => list.validate().map_err(Into::<anyhow::Error>::into),
665 Self::PolicyVersionGeq33(list) => list.validate().map_err(Into::<anyhow::Error>::into),
666 }
667 }
668}
669
670pub(super) type FilenameTransitions<PS> = Vec<FilenameTransition<PS>>;
671
672impl<PS: ParseStrategy> Validate for FilenameTransitions<PS> {
673 type Error = anyhow::Error;
674
675 fn validate(&self) -> Result<(), Self::Error> {
677 Ok(())
678 }
679}
680
681#[derive(Debug, PartialEq)]
682pub(super) struct FilenameTransition<PS: ParseStrategy> {
683 filename: SimpleArray<PS, PS::Slice<u8>>,
684 transition_type: PS::Output<le::U32>,
685 transition_class: PS::Output<le::U32>,
686 items: SimpleArray<PS, FilenameTransitionItems<PS>>,
687}
688
689impl<PS: ParseStrategy> FilenameTransition<PS> {
690 pub(super) fn name_bytes(&self) -> &[u8] {
691 PS::deref_slice(&self.filename.data)
692 }
693
694 pub(super) fn target_type(&self) -> TypeId {
695 TypeId(NonZeroU32::new(PS::deref(&self.transition_type).get()).unwrap())
696 }
697
698 pub(super) fn target_class(&self) -> ClassId {
699 ClassId(NonZeroU32::new(PS::deref(&self.transition_class).get()).unwrap())
700 }
701
702 pub(super) fn outputs(&self) -> &[FilenameTransitionItem<PS>] {
703 &self.items.data
704 }
705}
706
707impl<PS: ParseStrategy> Parse<PS> for FilenameTransition<PS>
708where
709 SimpleArray<PS, PS::Slice<u8>>: Parse<PS>,
710 SimpleArray<PS, FilenameTransitionItems<PS>>: Parse<PS>,
711{
712 type Error = anyhow::Error;
713
714 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
715 let tail = bytes;
716
717 let (filename, tail) = SimpleArray::<PS, PS::Slice<u8>>::parse(tail)
718 .map_err(Into::<anyhow::Error>::into)
719 .context("parsing filename for filename transition")?;
720
721 let num_bytes = tail.len();
722 let (transition_type, tail) =
723 PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
724 type_name: "FilenameTransition::transition_type",
725 type_size: std::mem::size_of::<le::U32>(),
726 num_bytes,
727 })?;
728
729 let num_bytes = tail.len();
730 let (transition_class, tail) =
731 PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
732 type_name: "FilenameTransition::transition_class",
733 type_size: std::mem::size_of::<le::U32>(),
734 num_bytes,
735 })?;
736
737 let (items, tail) = SimpleArray::<PS, FilenameTransitionItems<PS>>::parse(tail)
738 .map_err(Into::<anyhow::Error>::into)
739 .context("parsing items for filename transition")?;
740
741 Ok((Self { filename, transition_type, transition_class, items }, tail))
742 }
743}
744
745pub(super) type FilenameTransitionItems<PS> = Vec<FilenameTransitionItem<PS>>;
746
747#[derive(Debug, PartialEq)]
748pub(super) struct FilenameTransitionItem<PS: ParseStrategy> {
749 stypes: ExtensibleBitmap<PS>,
750 out_type: PS::Output<le::U32>,
751}
752
753impl<PS: ParseStrategy> FilenameTransitionItem<PS> {
754 pub(super) fn has_source_type(&self, source_type: TypeId) -> bool {
755 self.stypes.is_set(source_type.0.get() - 1)
756 }
757
758 pub(super) fn out_type(&self) -> TypeId {
759 TypeId(NonZeroU32::new(PS::deref(&self.out_type).get()).unwrap())
760 }
761}
762
763impl<PS: ParseStrategy> Parse<PS> for FilenameTransitionItem<PS>
764where
765 ExtensibleBitmap<PS>: Parse<PS>,
766{
767 type Error = anyhow::Error;
768
769 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
770 let tail = bytes;
771
772 let (stypes, tail) = ExtensibleBitmap::parse(tail)
773 .map_err(Into::<anyhow::Error>::into)
774 .context("parsing stypes extensible bitmap for file transition")?;
775
776 let num_bytes = tail.len();
777 let (out_type, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
778 type_name: "FilenameTransitionItem::out_type",
779 type_size: std::mem::size_of::<le::U32>(),
780 num_bytes,
781 })?;
782
783 Ok((Self { stypes, out_type }, tail))
784 }
785}
786
787pub(super) type DeprecatedFilenameTransitions<PS> = Vec<DeprecatedFilenameTransition<PS>>;
788
789impl<PS: ParseStrategy> Validate for DeprecatedFilenameTransitions<PS> {
790 type Error = anyhow::Error;
791
792 fn validate(&self) -> Result<(), Self::Error> {
794 Ok(())
795 }
796}
797
798#[derive(Debug, PartialEq)]
799pub(super) struct DeprecatedFilenameTransition<PS: ParseStrategy> {
800 filename: SimpleArray<PS, PS::Slice<u8>>,
801 metadata: PS::Output<DeprecatedFilenameTransitionMetadata>,
802}
803
804impl<PS: ParseStrategy> DeprecatedFilenameTransition<PS> {
805 pub(super) fn name_bytes(&self) -> &[u8] {
806 PS::deref_slice(&self.filename.data)
807 }
808
809 pub(super) fn source_type(&self) -> TypeId {
810 TypeId(NonZeroU32::new(PS::deref(&self.metadata).source_type.get()).unwrap())
811 }
812
813 pub(super) fn target_type(&self) -> TypeId {
814 TypeId(NonZeroU32::new(PS::deref(&self.metadata).transition_type.get()).unwrap())
815 }
816
817 pub(super) fn target_class(&self) -> ClassId {
818 ClassId(NonZeroU32::new(PS::deref(&self.metadata).transition_class.get()).unwrap())
819 }
820
821 pub(super) fn out_type(&self) -> TypeId {
822 TypeId(NonZeroU32::new(PS::deref(&self.metadata).out_type.get()).unwrap())
823 }
824}
825
826impl<PS: ParseStrategy> Parse<PS> for DeprecatedFilenameTransition<PS>
827where
828 SimpleArray<PS, PS::Slice<u8>>: Parse<PS>,
829{
830 type Error = anyhow::Error;
831
832 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
833 let tail = bytes;
834
835 let (filename, tail) = SimpleArray::<PS, PS::Slice<u8>>::parse(tail)
836 .map_err(Into::<anyhow::Error>::into)
837 .context("parsing filename for deprecated filename transition")?;
838
839 let num_bytes = tail.len();
840 let (metadata, tail) = PS::parse::<DeprecatedFilenameTransitionMetadata>(tail).ok_or({
841 ParseError::MissingData {
842 type_name: "DeprecatedFilenameTransition::metadata",
843 type_size: std::mem::size_of::<le::U32>(),
844 num_bytes,
845 }
846 })?;
847
848 Ok((Self { filename, metadata }, tail))
849 }
850}
851
852#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
853#[repr(C, packed)]
854pub(super) struct DeprecatedFilenameTransitionMetadata {
855 source_type: le::U32,
856 transition_type: le::U32,
857 transition_class: le::U32,
858 out_type: le::U32,
859}
860
861pub(super) type InitialSids<PS> = Vec<InitialSid<PS>>;
862
863impl<PS: ParseStrategy> Validate for InitialSids<PS> {
864 type Error = anyhow::Error;
865
866 fn validate(&self) -> Result<(), Self::Error> {
868 for initial_sid in crate::InitialSid::all_variants() {
869 self.iter()
870 .find(|initial| initial.id().get() == *initial_sid as u32)
871 .ok_or(ValidateError::MissingInitialSid { initial_sid: *initial_sid })?;
872 }
873 Ok(())
874 }
875}
876
877#[derive(Debug, PartialEq)]
878pub(super) struct InitialSid<PS: ParseStrategy> {
879 id: PS::Output<le::U32>,
880 context: Context<PS>,
881}
882
883impl<PS: ParseStrategy> InitialSid<PS> {
884 pub(super) fn id(&self) -> le::U32 {
885 *PS::deref(&self.id)
886 }
887
888 pub(super) fn context(&self) -> &Context<PS> {
889 &self.context
890 }
891}
892
893impl<PS: ParseStrategy> Parse<PS> for InitialSid<PS>
894where
895 Context<PS>: Parse<PS>,
896{
897 type Error = anyhow::Error;
898
899 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
900 let tail = bytes;
901
902 let num_bytes = tail.len();
903 let (id, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
904 type_name: "InitialSid::sid",
905 type_size: std::mem::size_of::<le::U32>(),
906 num_bytes,
907 })?;
908
909 let (context, tail) = Context::parse(tail)
910 .map_err(Into::<anyhow::Error>::into)
911 .context("parsing context for initial sid")?;
912
913 Ok((Self { id, context }, tail))
914 }
915}
916
917#[derive(Debug, PartialEq)]
918pub(super) struct Context<PS: ParseStrategy> {
919 metadata: PS::Output<ContextMetadata>,
920 mls_range: MlsRange<PS>,
921}
922
923impl<PS: ParseStrategy> Context<PS> {
924 pub(super) fn user_id(&self) -> UserId {
925 UserId(NonZeroU32::new(PS::deref(&self.metadata).user.get()).unwrap())
926 }
927 pub(super) fn role_id(&self) -> RoleId {
928 RoleId(NonZeroU32::new(PS::deref(&self.metadata).role.get()).unwrap())
929 }
930 pub(super) fn type_id(&self) -> TypeId {
931 TypeId(NonZeroU32::new(PS::deref(&self.metadata).context_type.get()).unwrap())
932 }
933 pub(super) fn low_level(&self) -> &MlsLevel<PS> {
934 self.mls_range.low()
935 }
936 pub(super) fn high_level(&self) -> &Option<MlsLevel<PS>> {
937 self.mls_range.high()
938 }
939}
940
941impl<PS: ParseStrategy> Parse<PS> for Context<PS>
942where
943 MlsRange<PS>: Parse<PS>,
944{
945 type Error = anyhow::Error;
946
947 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
948 let tail = bytes;
949
950 let (metadata, tail) =
951 PS::parse::<ContextMetadata>(tail).context("parsing metadata for context")?;
952
953 let (mls_range, tail) = MlsRange::parse(tail)
954 .map_err(Into::<anyhow::Error>::into)
955 .context("parsing mls range for context")?;
956
957 Ok((Self { metadata, mls_range }, tail))
958 }
959}
960
961#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
962#[repr(C, packed)]
963pub(super) struct ContextMetadata {
964 user: le::U32,
965 role: le::U32,
966 context_type: le::U32,
967}
968
969pub(super) type NamedContextPairs<PS> = Vec<NamedContextPair<PS>>;
970
971impl<PS: ParseStrategy> Validate for NamedContextPairs<PS> {
972 type Error = anyhow::Error;
973
974 fn validate(&self) -> Result<(), Self::Error> {
979 Ok(())
980 }
981}
982
983#[derive(Debug, PartialEq)]
984pub(super) struct NamedContextPair<PS: ParseStrategy> {
985 name: SimpleArray<PS, PS::Slice<u8>>,
986 context1: Context<PS>,
987 context2: Context<PS>,
988}
989
990impl<PS: ParseStrategy> Parse<PS> for NamedContextPair<PS>
991where
992 SimpleArray<PS, PS::Slice<u8>>: Parse<PS>,
993 Context<PS>: Parse<PS>,
994{
995 type Error = anyhow::Error;
996
997 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
998 let tail = bytes;
999
1000 let (name, tail) = SimpleArray::parse(tail)
1001 .map_err(Into::<anyhow::Error>::into)
1002 .context("parsing filesystem context name")?;
1003
1004 let (context1, tail) = Context::parse(tail)
1005 .map_err(Into::<anyhow::Error>::into)
1006 .context("parsing first context for filesystem context")?;
1007
1008 let (context2, tail) = Context::parse(tail)
1009 .map_err(Into::<anyhow::Error>::into)
1010 .context("parsing second context for filesystem context")?;
1011
1012 Ok((Self { name, context1, context2 }, tail))
1013 }
1014}
1015
1016pub(super) type Ports<PS> = Vec<Port<PS>>;
1017
1018impl<PS: ParseStrategy> Validate for Ports<PS> {
1019 type Error = anyhow::Error;
1020
1021 fn validate(&self) -> Result<(), Self::Error> {
1023 Ok(())
1024 }
1025}
1026
1027#[derive(Debug, PartialEq)]
1028pub(super) struct Port<PS: ParseStrategy> {
1029 metadata: PS::Output<PortMetadata>,
1030 context: Context<PS>,
1031}
1032
1033impl<PS: ParseStrategy> Parse<PS> for Port<PS>
1034where
1035 Context<PS>: Parse<PS>,
1036{
1037 type Error = anyhow::Error;
1038
1039 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1040 let tail = bytes;
1041
1042 let (metadata, tail) =
1043 PS::parse::<PortMetadata>(tail).context("parsing metadata for context")?;
1044
1045 let (context, tail) = Context::parse(tail)
1046 .map_err(Into::<anyhow::Error>::into)
1047 .context("parsing context for port")?;
1048
1049 Ok((Self { metadata, context }, tail))
1050 }
1051}
1052
1053#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1054#[repr(C, packed)]
1055pub(super) struct PortMetadata {
1056 protocol: le::U32,
1057 low_port: le::U32,
1058 high_port: le::U32,
1059}
1060
1061pub(super) type Nodes<PS> = Vec<Node<PS>>;
1062
1063impl<PS: ParseStrategy> Validate for Nodes<PS> {
1064 type Error = anyhow::Error;
1065
1066 fn validate(&self) -> Result<(), Self::Error> {
1068 Ok(())
1069 }
1070}
1071
1072#[derive(Debug, PartialEq)]
1073pub(super) struct Node<PS: ParseStrategy> {
1074 address: PS::Output<le::U32>,
1075 mask: PS::Output<le::U32>,
1076 context: Context<PS>,
1077}
1078
1079impl<PS: ParseStrategy> Parse<PS> for Node<PS>
1080where
1081 Context<PS>: Parse<PS>,
1082{
1083 type Error = anyhow::Error;
1084
1085 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1086 let tail = bytes;
1087
1088 let num_bytes = tail.len();
1089 let (address, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1090 type_name: "Node::address",
1091 type_size: std::mem::size_of::<le::U32>(),
1092 num_bytes,
1093 })?;
1094
1095 let num_bytes = tail.len();
1096 let (mask, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1097 type_name: "Node::mask",
1098 type_size: std::mem::size_of::<le::U32>(),
1099 num_bytes,
1100 })?;
1101
1102 let (context, tail) = Context::parse(tail)
1103 .map_err(Into::<anyhow::Error>::into)
1104 .context("parsing context for node")?;
1105
1106 Ok((Self { address, mask, context }, tail))
1107 }
1108}
1109
1110impl<PS: ParseStrategy> Validate for Node<PS> {
1111 type Error = anyhow::Error;
1112
1113 fn validate(&self) -> Result<(), Self::Error> {
1115 Ok(())
1116 }
1117}
1118
1119pub(super) type FsUses<PS> = Vec<FsUse<PS>>;
1120
1121impl<PS: ParseStrategy> Validate for FsUses<PS> {
1122 type Error = anyhow::Error;
1123
1124 fn validate(&self) -> Result<(), Self::Error> {
1125 for fs_use in self {
1126 fs_use.validate()?;
1127 }
1128 Ok(())
1129 }
1130}
1131
1132#[derive(Debug, PartialEq)]
1133pub(super) struct FsUse<PS: ParseStrategy> {
1134 behavior_and_name: Array<PS, PS::Output<FsUseMetadata>, PS::Slice<u8>>,
1135 context: Context<PS>,
1136}
1137
1138impl<PS: ParseStrategy> FsUse<PS> {
1139 pub fn fs_type(&self) -> &[u8] {
1140 PS::deref_slice(&self.behavior_and_name.data)
1141 }
1142
1143 pub(super) fn behavior(&self) -> FsUseType {
1144 FsUseType::try_from(PS::deref(&self.behavior_and_name.metadata).behavior).unwrap()
1145 }
1146
1147 pub(super) fn context(&self) -> &Context<PS> {
1148 &self.context
1149 }
1150}
1151
1152impl<PS: ParseStrategy> Parse<PS> for FsUse<PS>
1153where
1154 Array<PS, PS::Output<FsUseMetadata>, PS::Slice<u8>>: Parse<PS>,
1155 Context<PS>: Parse<PS>,
1156{
1157 type Error = anyhow::Error;
1158
1159 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1160 let tail = bytes;
1161
1162 let (behavior_and_name, tail) =
1163 Array::<PS, PS::Output<FsUseMetadata>, PS::Slice<u8>>::parse(tail)
1164 .map_err(Into::<anyhow::Error>::into)
1165 .context("parsing fs use metadata")?;
1166
1167 let (context, tail) = Context::parse(tail)
1168 .map_err(Into::<anyhow::Error>::into)
1169 .context("parsing context for fs use")?;
1170
1171 Ok((Self { behavior_and_name, context }, tail))
1172 }
1173}
1174
1175impl<PS: ParseStrategy> Validate for FsUse<PS> {
1176 type Error = anyhow::Error;
1177
1178 fn validate(&self) -> Result<(), Self::Error> {
1179 FsUseType::try_from(PS::deref(&self.behavior_and_name.metadata).behavior)?;
1180
1181 Ok(())
1182 }
1183}
1184
1185#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1186#[repr(C, packed)]
1187pub(super) struct FsUseMetadata {
1188 behavior: le::U32,
1190 name_length: le::U32,
1192}
1193
1194impl Counted for FsUseMetadata {
1195 fn count(&self) -> u32 {
1196 self.name_length.get()
1197 }
1198}
1199
1200#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
1203pub enum FsUseType {
1204 Xattr = 1,
1205 Trans = 2,
1206 Task = 3,
1207}
1208
1209impl TryFrom<le::U32> for FsUseType {
1210 type Error = anyhow::Error;
1211
1212 fn try_from(value: le::U32) -> Result<Self, Self::Error> {
1213 match value.get() {
1214 1 => Ok(FsUseType::Xattr),
1215 2 => Ok(FsUseType::Trans),
1216 3 => Ok(FsUseType::Task),
1217 _ => Err(ValidateError::InvalidFsUseType { value: value.get() }.into()),
1218 }
1219 }
1220}
1221
1222pub(super) type IPv6Nodes<PS> = Vec<IPv6Node<PS>>;
1223
1224impl<PS: ParseStrategy> Validate for IPv6Nodes<PS> {
1225 type Error = anyhow::Error;
1226
1227 fn validate(&self) -> Result<(), Self::Error> {
1229 Ok(())
1230 }
1231}
1232
1233#[derive(Debug, PartialEq)]
1234pub(super) struct IPv6Node<PS: ParseStrategy> {
1235 address: PS::Output<[le::U32; 4]>,
1236 mask: PS::Output<[le::U32; 4]>,
1237 context: Context<PS>,
1238}
1239
1240impl<PS: ParseStrategy> Parse<PS> for IPv6Node<PS>
1241where
1242 Context<PS>: Parse<PS>,
1243{
1244 type Error = anyhow::Error;
1245
1246 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1247 let tail = bytes;
1248
1249 let num_bytes = tail.len();
1250 let (address, tail) = PS::parse::<[le::U32; 4]>(tail).ok_or(ParseError::MissingData {
1251 type_name: "IPv6Node::address",
1252 type_size: std::mem::size_of::<le::U32>(),
1253 num_bytes,
1254 })?;
1255
1256 let num_bytes = tail.len();
1257 let (mask, tail) = PS::parse::<[le::U32; 4]>(tail).ok_or(ParseError::MissingData {
1258 type_name: "IPv6Node::mask",
1259 type_size: std::mem::size_of::<le::U32>(),
1260 num_bytes,
1261 })?;
1262
1263 let (context, tail) = Context::parse(tail)
1264 .map_err(Into::<anyhow::Error>::into)
1265 .context("parsing context for ipv6 node")?;
1266
1267 Ok((Self { address, mask, context }, tail))
1268 }
1269}
1270
1271pub(super) type InfinitiBandPartitionKeys<PS> = Vec<InfinitiBandPartitionKey<PS>>;
1272
1273impl<PS: ParseStrategy> Validate for InfinitiBandPartitionKeys<PS> {
1274 type Error = anyhow::Error;
1275
1276 fn validate(&self) -> Result<(), Self::Error> {
1278 Ok(())
1279 }
1280}
1281
1282#[derive(Debug, PartialEq)]
1283pub(super) struct InfinitiBandPartitionKey<PS: ParseStrategy> {
1284 low: PS::Output<le::U32>,
1285 high: PS::Output<le::U32>,
1286 context: Context<PS>,
1287}
1288
1289impl<PS: ParseStrategy> Parse<PS> for InfinitiBandPartitionKey<PS>
1290where
1291 Context<PS>: Parse<PS>,
1292{
1293 type Error = anyhow::Error;
1294
1295 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1296 let tail = bytes;
1297
1298 let num_bytes = tail.len();
1299 let (low, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1300 type_name: "InfinitiBandPartitionKey::low",
1301 type_size: std::mem::size_of::<le::U32>(),
1302 num_bytes,
1303 })?;
1304
1305 let num_bytes = tail.len();
1306 let (high, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1307 type_name: "InfinitiBandPartitionKey::high",
1308 type_size: std::mem::size_of::<le::U32>(),
1309 num_bytes,
1310 })?;
1311
1312 let (context, tail) = Context::parse(tail)
1313 .map_err(Into::<anyhow::Error>::into)
1314 .context("parsing context for infiniti band partition key")?;
1315
1316 Ok((Self { low, high, context }, tail))
1317 }
1318}
1319
1320impl<PS: ParseStrategy> Validate for InfinitiBandPartitionKey<PS> {
1321 type Error = anyhow::Error;
1322
1323 fn validate(&self) -> Result<(), Self::Error> {
1325 Ok(())
1326 }
1327}
1328
1329pub(super) type InfinitiBandEndPorts<PS> = Vec<InfinitiBandEndPort<PS>>;
1330
1331impl<PS: ParseStrategy> Validate for InfinitiBandEndPorts<PS> {
1332 type Error = anyhow::Error;
1333
1334 fn validate(&self) -> Result<(), Self::Error> {
1336 Ok(())
1337 }
1338}
1339
1340#[derive(Debug, PartialEq)]
1341pub(super) struct InfinitiBandEndPort<PS: ParseStrategy> {
1342 port_and_name: Array<PS, PS::Output<InfinitiBandEndPortMetadata>, PS::Slice<u8>>,
1343 context: Context<PS>,
1344}
1345
1346impl<PS: ParseStrategy> Parse<PS> for InfinitiBandEndPort<PS>
1347where
1348 Array<PS, PS::Output<InfinitiBandEndPortMetadata>, PS::Slice<u8>>: Parse<PS>,
1349 Context<PS>: Parse<PS>,
1350{
1351 type Error = anyhow::Error;
1352
1353 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1354 let tail = bytes;
1355
1356 let (port_and_name, tail) =
1357 Array::<PS, PS::Output<InfinitiBandEndPortMetadata>, PS::Slice<u8>>::parse(tail)
1358 .map_err(Into::<anyhow::Error>::into)
1359 .context("parsing infiniti band end port metadata")?;
1360
1361 let (context, tail) = Context::parse(tail)
1362 .map_err(Into::<anyhow::Error>::into)
1363 .context("parsing context for infiniti band end port")?;
1364
1365 Ok((Self { port_and_name, context }, tail))
1366 }
1367}
1368
1369#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1370#[repr(C, packed)]
1371pub(super) struct InfinitiBandEndPortMetadata {
1372 length: le::U32,
1373 port: le::U32,
1374}
1375
1376impl Counted for InfinitiBandEndPortMetadata {
1377 fn count(&self) -> u32 {
1378 self.length.get()
1379 }
1380}
1381
1382pub(super) type GenericFsContexts<PS> = Vec<GenericFsContext<PS>>;
1383
1384impl<PS: ParseStrategy> Validate for GenericFsContexts<PS> {
1385 type Error = anyhow::Error;
1386
1387 fn validate(&self) -> Result<(), Self::Error> {
1389 Ok(())
1390 }
1391}
1392
1393#[derive(Debug, PartialEq)]
1396pub(super) struct GenericFsContext<PS: ParseStrategy> {
1397 fs_type: SimpleArray<PS, PS::Slice<u8>>,
1399 contexts: SimpleArray<PS, FsContexts<PS>>,
1401}
1402
1403impl<PS: ParseStrategy> GenericFsContext<PS> {
1404 pub(super) fn fs_type(&self) -> &[u8] {
1405 PS::deref_slice(&self.fs_type.data)
1406 }
1407
1408 pub(super) fn contexts(&self) -> &FsContexts<PS> {
1409 &self.contexts.data
1410 }
1411}
1412
1413impl<PS: ParseStrategy> Parse<PS> for GenericFsContext<PS>
1414where
1415 SimpleArray<PS, PS::Slice<u8>>: Parse<PS>,
1416 SimpleArray<PS, FsContexts<PS>>: Parse<PS>,
1417{
1418 type Error = anyhow::Error;
1419
1420 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1421 let tail = bytes;
1422
1423 let (fs_type, tail) = SimpleArray::<PS, PS::Slice<u8>>::parse(tail)
1424 .map_err(Into::<anyhow::Error>::into)
1425 .context("parsing generic filesystem context name")?;
1426
1427 let (contexts, tail) = SimpleArray::<PS, FsContexts<PS>>::parse(tail)
1428 .map_err(Into::<anyhow::Error>::into)
1429 .context("parsing generic filesystem contexts")?;
1430
1431 Ok((Self { fs_type, contexts }, tail))
1432 }
1433}
1434
1435pub(super) type FsContexts<PS> = Vec<FsContext<PS>>;
1436
1437#[derive(Debug, PartialEq)]
1438pub(super) struct FsContext<PS: ParseStrategy> {
1439 partial_path: SimpleArray<PS, PS::Slice<u8>>,
1442 class: PS::Output<le::U32>,
1446 context: Context<PS>,
1448}
1449
1450impl<PS: ParseStrategy> FsContext<PS> {
1451 pub(super) fn partial_path(&self) -> &[u8] {
1452 PS::deref_slice(&self.partial_path.data)
1453 }
1454
1455 pub(super) fn context(&self) -> &Context<PS> {
1456 &self.context
1457 }
1458
1459 pub(super) fn class(&self) -> Option<ClassId> {
1460 NonZeroU32::new((*PS::deref(&self.class)).into()).map(ClassId)
1461 }
1462}
1463
1464impl<PS: ParseStrategy> Parse<PS> for FsContext<PS>
1465where
1466 SimpleArray<PS, PS::Slice<u8>>: Parse<PS>,
1467 Context<PS>: Parse<PS>,
1468{
1469 type Error = anyhow::Error;
1470
1471 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1472 let tail = bytes;
1473
1474 let (partial_path, tail) = SimpleArray::<PS, PS::Slice<u8>>::parse(tail)
1475 .map_err(Into::<anyhow::Error>::into)
1476 .context("parsing filesystem context partial path")?;
1477
1478 let num_bytes = tail.len();
1479 let (class, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1480 type_name: "FsContext::class",
1481 type_size: std::mem::size_of::<le::U32>(),
1482 num_bytes,
1483 })?;
1484
1485 let (context, tail) = Context::parse(tail)
1486 .map_err(Into::<anyhow::Error>::into)
1487 .context("parsing context for filesystem context")?;
1488
1489 Ok((Self { partial_path, class, context }, tail))
1490 }
1491}
1492
1493pub(super) type RangeTransitions<PS> = Vec<RangeTransition<PS>>;
1494
1495impl<PS: ParseStrategy> Validate for RangeTransitions<PS> {
1496 type Error = anyhow::Error;
1497
1498 fn validate(&self) -> Result<(), Self::Error> {
1500 for range_transition in self {
1501 if PS::deref(&range_transition.metadata).target_class.get() == 0 {
1502 return Err(ValidateError::NonOptionalIdIsZero.into());
1503 }
1504 }
1505 Ok(())
1506 }
1507}
1508
1509#[derive(Debug, PartialEq)]
1510pub(super) struct RangeTransition<PS: ParseStrategy> {
1511 metadata: PS::Output<RangeTransitionMetadata>,
1512 mls_range: MlsRange<PS>,
1513}
1514
1515impl<PS: ParseStrategy> RangeTransition<PS> {
1516 pub fn source_type(&self) -> TypeId {
1517 TypeId(NonZeroU32::new(PS::deref(&self.metadata).source_type.get()).unwrap())
1518 }
1519
1520 pub fn target_type(&self) -> TypeId {
1521 TypeId(NonZeroU32::new(PS::deref(&self.metadata).target_type.get()).unwrap())
1522 }
1523
1524 pub fn target_class(&self) -> ClassId {
1525 ClassId(NonZeroU32::new(PS::deref(&self.metadata).target_class.get()).unwrap())
1526 }
1527
1528 pub fn mls_range(&self) -> &MlsRange<PS> {
1529 &self.mls_range
1530 }
1531}
1532
1533impl<PS: ParseStrategy> Parse<PS> for RangeTransition<PS>
1534where
1535 MlsRange<PS>: Parse<PS>,
1536{
1537 type Error = anyhow::Error;
1538
1539 fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1540 let tail = bytes;
1541
1542 let (metadata, tail) = PS::parse::<RangeTransitionMetadata>(tail)
1543 .context("parsing range transition metadata")?;
1544
1545 let (mls_range, tail) = MlsRange::parse(tail)
1546 .map_err(Into::<anyhow::Error>::into)
1547 .context("parsing mls range for range transition")?;
1548
1549 Ok((Self { metadata, mls_range }, tail))
1550 }
1551}
1552
1553#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1554#[repr(C, packed)]
1555pub(super) struct RangeTransitionMetadata {
1556 source_type: le::U32,
1557 target_type: le::U32,
1558 target_class: le::U32,
1559}
1560
1561#[cfg(test)]
1562mod tests {
1563 use super::super::{find_class_by_name, parse_policy_by_reference};
1564 use super::*;
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_reference(policy_bytes.as_slice()).expect("parse policy");
1570 let parsed_policy = &policy.0;
1571 Validate::validate(parsed_policy).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()
1579 .into_iter()
1580 .filter(|rule| rule.target_class() == class_id)
1581 .collect();
1582
1583 assert_eq!(rules.len(), 1);
1584 assert!(rules[0].is_allowxperm());
1585 if let Some(xperms) = rules[0].extended_permissions() {
1586 assert_eq!(xperms.count(), 1);
1587 assert!(xperms.contains(0xabcd));
1588 } else {
1589 panic!("unexpected permission data type")
1590 }
1591 }
1592
1593 #[test]
1596 fn parse_allowxperm_two_ioctls_same_range() {
1597 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1598 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1599 let parsed_policy = &policy.0;
1600 Validate::validate(parsed_policy).expect("validate policy");
1601
1602 let class_id = find_class_by_name(parsed_policy.classes(), "class_two_ioctls_same_range")
1603 .expect("look up class_two_ioctls_same_range")
1604 .id();
1605
1606 let rules: Vec<_> = parsed_policy
1607 .access_vector_rules()
1608 .into_iter()
1609 .filter(|rule| rule.target_class() == class_id)
1610 .collect();
1611
1612 assert_eq!(rules.len(), 1);
1613 assert!(rules[0].is_allowxperm());
1614 if let Some(xperms) = rules[0].extended_permissions() {
1615 assert_eq!(xperms.count(), 2);
1616 assert!(xperms.contains(0x1234));
1617 assert!(xperms.contains(0x1256));
1618 } else {
1619 panic!("unexpected permission data type")
1620 }
1621 }
1622
1623 #[test]
1626 fn parse_allowxperm_two_ioctls_different_range() {
1627 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1628 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1629 let parsed_policy = &policy.0;
1630 Validate::validate(parsed_policy).expect("validate policy");
1631
1632 let class_id = find_class_by_name(parsed_policy.classes(), "class_two_ioctls_diff_range")
1633 .expect("look up class_two_ioctls_diff_range")
1634 .id();
1635
1636 let rules: Vec<_> = parsed_policy
1637 .access_vector_rules()
1638 .into_iter()
1639 .filter(|rule| rule.target_class() == class_id)
1640 .collect();
1641
1642 assert_eq!(rules.len(), 2);
1643 assert!(rules[0].is_allowxperm());
1644 if let Some(xperms) = rules[0].extended_permissions() {
1645 assert_eq!(xperms.count(), 1);
1646 assert!(xperms.contains(0x5678));
1647 } else {
1648 panic!("unexpected permission data type")
1649 }
1650 assert!(rules[1].is_allowxperm());
1651 if let Some(xperms) = rules[1].extended_permissions() {
1652 assert_eq!(xperms.count(), 1);
1653 assert!(xperms.contains(0x1234));
1654 } else {
1655 panic!("unexpected permission data type")
1656 }
1657 }
1658
1659 #[test]
1660 fn parse_allowxperm_one_driver_range() {
1661 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1662 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1663 let parsed_policy = &policy.0;
1664 Validate::validate(parsed_policy).expect("validate policy");
1665
1666 let class_id = find_class_by_name(parsed_policy.classes(), "class_one_driver_range")
1667 .expect("look up class_one_driver_range")
1668 .id();
1669
1670 let rules: Vec<_> = parsed_policy
1671 .access_vector_rules()
1672 .into_iter()
1673 .filter(|rule| rule.target_class() == class_id)
1674 .collect();
1675
1676 assert_eq!(rules.len(), 1);
1677 assert!(rules[0].is_allowxperm());
1678 if let Some(xperms) = rules[0].extended_permissions() {
1679 assert_eq!(xperms.count(), 0x100);
1680 assert!(xperms.contains(0x1000));
1681 assert!(xperms.contains(0x10ab));
1682 } else {
1683 panic!("unexpected permission data type")
1684 }
1685 }
1686
1687 #[test]
1688 fn parse_allowxperm_all_ioctls() {
1689 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1690 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1691 let parsed_policy = &policy.0;
1692 Validate::validate(parsed_policy).expect("validate policy");
1693
1694 let class_id = find_class_by_name(parsed_policy.classes(), "class_all_ioctls")
1695 .expect("look up class_all_ioctls")
1696 .id();
1697
1698 let rules: Vec<_> = parsed_policy
1699 .access_vector_rules()
1700 .into_iter()
1701 .filter(|rule| rule.target_class() == class_id)
1702 .collect();
1703
1704 assert_eq!(rules.len(), 1);
1705 assert!(rules[0].is_allowxperm());
1706 if let Some(xperms) = rules[0].extended_permissions() {
1707 assert_eq!(xperms.count(), 0x10000);
1708 } else {
1709 panic!("unexpected permission data type")
1710 }
1711 }
1712
1713 #[test]
1717 fn parse_allowxperm_overlapping_ranges() {
1718 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1719 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1720 let parsed_policy = &policy.0;
1721 Validate::validate(parsed_policy).expect("validate policy");
1722
1723 let class_id = find_class_by_name(parsed_policy.classes(), "class_overlapping_ranges")
1724 .expect("look up class_overlapping_ranges")
1725 .id();
1726
1727 let rules: Vec<_> = parsed_policy
1728 .access_vector_rules()
1729 .into_iter()
1730 .filter(|rule| rule.target_class() == class_id)
1731 .collect();
1732
1733 assert_eq!(rules.len(), 2);
1734 assert!(rules[0].is_allowxperm());
1735 if let Some(xperms) = rules[0].extended_permissions() {
1736 assert_eq!(xperms.count(), 0x100);
1737 assert!(xperms.contains(0x1000));
1739 assert!(xperms.contains(0x10ab));
1740 } else {
1741 panic!("unexpected permission data type")
1742 }
1743 assert!(rules[1].is_allowxperm());
1744 if let Some(xperms) = rules[1].extended_permissions() {
1745 assert_eq!(xperms.count(), 2);
1746 assert!(xperms.contains(0x1000));
1747 assert!(xperms.contains(0x1001));
1748 } else {
1749 panic!("unexpected permission data type")
1750 }
1751 }
1752
1753 #[test]
1756 fn parse_auditallowxperm() {
1757 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1758 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1759 let parsed_policy = &policy.0;
1760 Validate::validate(parsed_policy).expect("validate policy");
1761
1762 let class_id = find_class_by_name(parsed_policy.classes(), "class_auditallowxperm")
1763 .expect("look up class_auditallowxperm")
1764 .id();
1765
1766 let rules: Vec<_> = parsed_policy
1767 .access_vector_rules()
1768 .into_iter()
1769 .filter(|rule| rule.target_class() == class_id)
1770 .collect();
1771
1772 assert_eq!(rules.len(), 1);
1773 assert!(rules[0].is_auditallowxperm());
1774 if let Some(xperms) = rules[0].extended_permissions() {
1775 assert_eq!(xperms.count(), 1);
1776 assert!(xperms.contains(0x1000));
1777 } else {
1778 panic!("unexpected permission data type")
1779 }
1780 }
1781
1782 #[test]
1790 fn parse_dontauditxperm() {
1791 let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1792 let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1793 let parsed_policy = &policy.0;
1794 Validate::validate(parsed_policy).expect("validate policy");
1795
1796 let class_id = find_class_by_name(parsed_policy.classes(), "class_dontauditxperm")
1797 .expect("look up class_dontauditxperm")
1798 .id();
1799
1800 let rules: Vec<_> = parsed_policy
1801 .access_vector_rules()
1802 .into_iter()
1803 .filter(|rule| rule.target_class() == class_id)
1804 .collect();
1805
1806 assert_eq!(rules.len(), 1);
1807 assert!(rules[0].is_dontauditxperm());
1808 if let Some(xperms) = rules[0].extended_permissions() {
1809 assert_eq!(xperms.count(), 1);
1810 assert!(xperms.contains(0x1000));
1811 } else {
1812 panic!("unexpected permission data type")
1813 }
1814 }
1815}