selinux/policy/
arrays.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use super::error::ValidateError;
6use super::extensible_bitmap::ExtensibleBitmap;
7use super::parser::{PolicyCursor, PolicyData, PolicyOffset};
8use super::symbols::{MlsLevel, MlsRange};
9use super::view::{ArrayView, HasMetadata, Walk};
10use super::{
11    AccessVector, Array, ClassId, Counted, Parse, PolicyValidationContext, RoleId, TypeId, UserId,
12    Validate, ValidateArray, array_type, array_type_validate_deref_both,
13};
14
15use anyhow::Context as _;
16use std::num::NonZeroU32;
17use std::ops::Shl;
18use zerocopy::{FromBytes, Immutable, KnownLayout, Unaligned, little_endian as le};
19
20pub(super) const MIN_POLICY_VERSION_FOR_INFINITIBAND_PARTITION_KEY: u32 = 31;
21
22/// Mask for [`AccessVectorRuleMetadata`]'s `access_vector_rule_type` that
23/// indicates that the access vector rule's associated data is a type ID.
24pub(super) const ACCESS_VECTOR_RULE_DATA_IS_TYPE_ID_MASK: u16 = 0x070;
25/// Mask for [`AccessVectorRuleMetadata`]'s `access_vector_rule_type` that
26/// indicates that the access vector rule's associated data is an extended
27/// permission.
28pub(super) const ACCESS_VECTOR_RULE_DATA_IS_XPERM_MASK: u16 = 0x0700;
29
30/// ** Access vector rule types ***
31///
32/// Although these values each have a single bit set, they appear to be
33/// used as enum values rather than as bit masks: i.e., the policy compiler
34/// does not produce access vector rule structures that have more than
35/// one of these types.
36/// Value for [`AccessVectorRuleMetadata`] `access_vector_rule_type` that
37/// indicates that the access vector rule comes from an `allow [source]
38/// [target]:[class] { [permissions] };` policy statement.
39pub(super) const ACCESS_VECTOR_RULE_TYPE_ALLOW: u16 = 0x1;
40/// Value for [`AccessVectorRuleMetadata`] `access_vector_rule_type` that
41/// indicates that the access vector rule comes from an `auditallow [source]
42/// [target]:[class] { [permissions] };` policy statement.
43pub(super) const ACCESS_VECTOR_RULE_TYPE_AUDITALLOW: u16 = 0x2;
44/// Value for [`AccessVectorRuleMetadata`] `access_vector_rule_type` that
45/// indicates that the access vector rule comes from a `dontaudit [source]
46/// [target]:[class] { [permissions] };` policy statement.
47pub(super) const ACCESS_VECTOR_RULE_TYPE_DONTAUDIT: u16 = 0x4;
48/// Value for [`AccessVectorRuleMetadata`] `access_vector_rule_type` that
49/// indicates that the access vector rule comes from a `type_transition
50/// [source] [target]:[class] [new_type];` policy statement.
51pub(super) const ACCESS_VECTOR_RULE_TYPE_TYPE_TRANSITION: u16 = 0x10;
52/// Value for [`AccessVectorRuleMetadata`] `access_vector_rule_type` that
53/// indicates that the access vector rule comes from a `type_member
54/// [source] [target]:[class] [member_type];` policy statement.
55#[allow(dead_code)]
56pub(super) const ACCESS_VECTOR_RULE_TYPE_TYPE_MEMBER: u16 = 0x20;
57/// Value for [`AccessVectorRuleMetadata`] `access_vector_rule_type` that
58/// indicates that the access vector rule comes from a `type_change
59/// [source] [target]:[class] [change_type];` policy statement.
60#[allow(dead_code)]
61pub(super) const ACCESS_VECTOR_RULE_TYPE_TYPE_CHANGE: u16 = 0x40;
62/// Value for [`AccessVectorRuleMetadata`] `access_vector_rule_type`
63/// that indicates that the access vector rule comes from an
64/// `allowxperm [source] [target]:[class] [permission] {
65/// [extended_permissions] };` policy statement.
66pub(super) const ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM: u16 = 0x100;
67/// Value for [`AccessVectorRuleMetadata`] `access_vector_rule_type`
68/// that indicates that the access vector rule comes from an
69/// `auditallowxperm [source] [target]:[class] [permission] {
70/// [extended_permissions] };` policy statement.
71pub(super) const ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM: u16 = 0x200;
72/// Value for [`AccessVectorRuleMetadata`] `access_vector_rule_type`
73/// that indicates that the access vector rule comes from an
74/// `dontauditxperm [source] [target]:[class] [permission] {
75/// [extended_permissions] };` policy statement.
76pub(super) const ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM: u16 = 0x400;
77
78/// ** Extended permissions types ***
79///
80/// Value for [`ExtendedPermissions`] `xperms_type` that indicates
81/// that the xperms set is a proper subset of the 16-bit ioctl
82/// xperms with a given high byte value.
83pub(super) const XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES: u8 = 1;
84/// Value for [`ExtendedPermissions`] `xperms_type` that indicates
85/// that the xperms set consists of all 16-bit ioctl xperms with a
86/// given high byte, for one or more high byte values.
87pub(super) const XPERMS_TYPE_IOCTL_PREFIXES: u8 = 2;
88/// Value for [`ExtendedPermissions`] `xperms_type` that indicates
89/// that the xperms set consists of 16-bit `nlmsg` xperms with a given
90/// high byte value in common. The xperms set may be the full set of
91/// xperms with that high byte value (unlike a set of type
92/// `XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES`).
93pub(super) const XPERMS_TYPE_NLMSG: u8 = 3;
94
95#[allow(type_alias_bounds)]
96pub(super) type SimpleArray<T> = Array<le::U32, T>;
97
98impl<T: Validate> Validate for SimpleArray<T> {
99    type Error = <T as Validate>::Error;
100
101    /// Defers to `self.data` for validation. `self.data` has access to all information, including
102    /// size stored in `self.metadata`.
103    fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
104        self.data.validate(context)
105    }
106}
107
108pub(super) type SimpleArrayView<T> = ArrayView<le::U32, T>;
109
110impl<T: Validate + Parse + Walk> Validate for SimpleArrayView<T> {
111    type Error = anyhow::Error;
112
113    /// Defers to `self.data` for validation. `self.data` has access to all information, including
114    /// size stored in `self.metadata`.
115    fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
116        for item in self.data().iter(&context.data) {
117            item.validate(context)?;
118        }
119        Ok(())
120    }
121}
122
123impl Counted for le::U32 {
124    fn count(&self) -> u32 {
125        self.get()
126    }
127}
128
129pub(super) type ConditionalNodes = Vec<ConditionalNode>;
130
131impl Validate for ConditionalNodes {
132    type Error = anyhow::Error;
133
134    /// TODO: Validate internal consistency between consecutive [`ConditionalNode`] instances.
135    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
136        Ok(())
137    }
138}
139
140array_type!(ConditionalNodeItems, ConditionalNodeMetadata, Vec<ConditionalNodeDatum>);
141
142array_type_validate_deref_both!(ConditionalNodeItems);
143
144impl ValidateArray<ConditionalNodeMetadata, ConditionalNodeDatum> for ConditionalNodeItems {
145    type Error = anyhow::Error;
146
147    /// TODO: Validate internal consistency between [`ConditionalNodeMetadata`] consecutive
148    /// [`ConditionalNodeDatum`].
149    fn validate_array(
150        _context: &mut PolicyValidationContext,
151        _metadata: &ConditionalNodeMetadata,
152        _items: &[ConditionalNodeDatum],
153    ) -> Result<(), Self::Error> {
154        Ok(())
155    }
156}
157
158#[derive(Debug, PartialEq)]
159pub(super) struct ConditionalNode {
160    items: ConditionalNodeItems,
161    true_list: SimpleArray<AccessVectorRules>,
162    false_list: SimpleArray<AccessVectorRules>,
163}
164
165impl Parse for ConditionalNode
166where
167    ConditionalNodeItems: Parse,
168    SimpleArray<AccessVectorRules>: Parse,
169{
170    type Error = anyhow::Error;
171
172    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
173        let tail = bytes;
174
175        let (items, tail) = ConditionalNodeItems::parse(tail)
176            .map_err(Into::<anyhow::Error>::into)
177            .context("parsing conditional node items")?;
178
179        let (true_list, tail) = SimpleArray::<AccessVectorRules>::parse(tail)
180            .map_err(Into::<anyhow::Error>::into)
181            .context("parsing conditional node true list")?;
182
183        let (false_list, tail) = SimpleArray::<AccessVectorRules>::parse(tail)
184            .map_err(Into::<anyhow::Error>::into)
185            .context("parsing conditional node false list")?;
186
187        Ok((Self { items, true_list, false_list }, tail))
188    }
189}
190
191#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
192#[repr(C, packed)]
193pub(super) struct ConditionalNodeMetadata {
194    state: le::U32,
195    count: le::U32,
196}
197
198impl Counted for ConditionalNodeMetadata {
199    fn count(&self) -> u32 {
200        self.count.get()
201    }
202}
203
204impl Validate for ConditionalNodeMetadata {
205    type Error = anyhow::Error;
206
207    /// TODO: Validate [`ConditionalNodeMetadata`] internals.
208    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
209        Ok(())
210    }
211}
212
213#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
214#[repr(C, packed)]
215pub(super) struct ConditionalNodeDatum {
216    node_type: le::U32,
217    boolean: le::U32,
218}
219
220impl Validate for [ConditionalNodeDatum] {
221    type Error = anyhow::Error;
222
223    /// TODO: Validate sequence of [`ConditionalNodeDatum`].
224    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
225        Ok(())
226    }
227}
228
229/// The list of access control rules defined by policy statements of the
230/// following kinds:
231/// - `allow`, `dontaudit`, `auditallow`, and `neverallow`, which specify
232///   an access vector describing a permission set.
233/// - `allowxperm`, `auditallowxperm`, `dontaudit`, which specify a set
234///   of extended permissions.
235/// - `type_transition`, `type_change`, and `type_member', which include
236///   a type id describing a permitted new type.
237pub(super) type AccessVectorRules = Vec<AccessVectorRule>;
238
239impl Validate for AccessVectorRules {
240    type Error = anyhow::Error;
241
242    fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
243        for access_vector_rule in self {
244            access_vector_rule.validate(context)?;
245        }
246        Ok(())
247    }
248}
249
250#[derive(Debug, PartialEq)]
251pub(super) struct AccessVectorRule {
252    metadata: AccessVectorRuleMetadata,
253    permission_data: PermissionData,
254}
255
256impl AccessVectorRule {
257    /// An access vector that corresponds to the `[access_vector]` in an
258    /// `allow [source] [target]:[class] [access_vector]` policy statement,
259    /// or similarly for an `auditallow` or `dontaudit` policy statement.
260    /// Return value is `None` if this access vector rule corresponds to a
261    /// different kind of policy statement.
262    pub fn access_vector(&self) -> Option<AccessVector> {
263        match &self.permission_data {
264            PermissionData::AccessVector(access_vector_raw) => {
265                Some(AccessVector(access_vector_raw.get()))
266            }
267            _ => None,
268        }
269    }
270
271    /// A numeric type id that corresponds to the `[new_type]` in a
272    /// `type_transition [source] [target]:[class] [new_type];` policy statement,
273    /// or similarly for a `type_member` or `type_change` policy statement.
274    /// Return value is `None` if this access vector rule corresponds to a
275    /// different kind of policy statement.
276    pub fn new_type(&self) -> Option<TypeId> {
277        match &self.permission_data {
278            PermissionData::NewType(new_type) => {
279                Some(TypeId(NonZeroU32::new(new_type.get().into()).unwrap()))
280            }
281            _ => None,
282        }
283    }
284
285    /// A set of extended permissions that corresponds to the `[xperms]` in an
286    /// `allowxperm [source][target]:[class] [permission] [xperms]` policy
287    /// statement, or similarly for an `auditallowxperm` or `dontauditxperm`
288    /// policy statement. Return value is `None` if this access vector rule
289    /// corresponds to a different kind of policy statement.
290    pub fn extended_permissions(&self) -> Option<&ExtendedPermissions> {
291        match &self.permission_data {
292            PermissionData::ExtendedPermissions(xperms) => Some(xperms),
293            _ => None,
294        }
295    }
296}
297
298impl Walk for AccessVectorRule {
299    fn walk(policy_data: &PolicyData, offset: PolicyOffset) -> PolicyOffset {
300        const METADATA_SIZE: u32 = std::mem::size_of::<AccessVectorRuleMetadata>() as u32;
301        let bytes = &policy_data[offset as usize..(offset + METADATA_SIZE) as usize];
302        let metadata = AccessVectorRuleMetadata::read_from_bytes(bytes).unwrap();
303        let permission_data_size = metadata.permission_data_size() as u32;
304        offset + METADATA_SIZE + permission_data_size
305    }
306}
307
308impl HasMetadata for AccessVectorRule {
309    type Metadata = AccessVectorRuleMetadata;
310}
311
312impl Parse for AccessVectorRule {
313    type Error = anyhow::Error;
314
315    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
316        let tail = bytes;
317
318        let (metadata, tail) = PolicyCursor::parse::<AccessVectorRuleMetadata>(tail)?;
319        let access_vector_rule_type = metadata.access_vector_rule_type;
320        let (permission_data, tail) =
321            if (access_vector_rule_type & ACCESS_VECTOR_RULE_DATA_IS_XPERM_MASK) != 0 {
322                let (xperms, tail) = ExtendedPermissions::parse(tail)
323                    .map_err(Into::<anyhow::Error>::into)
324                    .context("parsing extended permissions")?;
325                (PermissionData::ExtendedPermissions(xperms), tail)
326            } else if (access_vector_rule_type & ACCESS_VECTOR_RULE_DATA_IS_TYPE_ID_MASK) != 0 {
327                let (new_type, tail) = PolicyCursor::parse::<le::U32>(tail)?;
328                (PermissionData::NewType(new_type), tail)
329            } else {
330                let (access_vector, tail) = PolicyCursor::parse::<le::U32>(tail)?;
331                (PermissionData::AccessVector(access_vector), tail)
332            };
333        Ok((Self { metadata, permission_data }, tail))
334    }
335}
336
337impl Validate for AccessVectorRule {
338    type Error = anyhow::Error;
339
340    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
341        if self.metadata.class.get() == 0 {
342            return Err(ValidateError::NonOptionalIdIsZero.into());
343        }
344        if let PermissionData::ExtendedPermissions(xperms) = &self.permission_data {
345            let xperms_type = xperms.xperms_type;
346            if !(xperms_type == XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES
347                || xperms_type == XPERMS_TYPE_IOCTL_PREFIXES
348                || xperms_type == XPERMS_TYPE_NLMSG)
349            {
350                return Err(
351                    ValidateError::InvalidExtendedPermissionsType { type_: xperms_type }.into()
352                );
353            }
354        }
355        Ok(())
356    }
357}
358
359#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, Eq, PartialEq, Unaligned, Hash)]
360#[repr(C, packed)]
361pub(super) struct AccessVectorRuleMetadata {
362    source_type: le::U16,
363    target_type: le::U16,
364    class: le::U16,
365    access_vector_rule_type: le::U16,
366}
367
368impl AccessVectorRuleMetadata {
369    pub fn for_query(source: TypeId, target: TypeId, class: ClassId, rule_type: u16) -> Self {
370        let source_type = le::U16::new(source.0.get() as u16);
371        let target_type = le::U16::new(target.0.get() as u16);
372        let class = le::U16::new(class.0.get() as u16);
373        let access_vector_rule_type = le::U16::new(rule_type);
374        Self { source_type, target_type, class, access_vector_rule_type }
375    }
376
377    fn permission_data_size(&self) -> usize {
378        if (self.access_vector_rule_type & ACCESS_VECTOR_RULE_DATA_IS_XPERM_MASK) != 0 {
379            std::mem::size_of::<ExtendedPermissions>()
380        } else if (self.access_vector_rule_type & ACCESS_VECTOR_RULE_DATA_IS_TYPE_ID_MASK) != 0 {
381            std::mem::size_of::<le::U32>()
382        } else {
383            std::mem::size_of::<le::U32>()
384        }
385    }
386}
387
388#[derive(Debug, PartialEq)]
389pub(super) enum PermissionData {
390    AccessVector(le::U32),
391    NewType(le::U32),
392    ExtendedPermissions(ExtendedPermissions),
393}
394
395#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
396#[repr(C, packed)]
397pub(super) struct ExtendedPermissions {
398    pub(super) xperms_type: u8,
399    // xperms_optional_prefix is meaningful when xperms_type is
400    // XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES or XPERMS_TYPE_NLMSG and
401    // meaningless when xperms_type is XPERMS_TYPE_IOCTL_PREFIXES.
402    pub(super) xperms_optional_prefix: u8,
403    pub(super) xperms_bitmap: XpermsBitmap,
404}
405
406impl ExtendedPermissions {
407    #[cfg(test)]
408    fn count(&self) -> u64 {
409        let count = self
410            .xperms_bitmap
411            .0
412            .iter()
413            .fold(0, |count, block| (count as u64) + (block.get().count_ones() as u64));
414        match self.xperms_type {
415            XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES | XPERMS_TYPE_NLMSG => count,
416            XPERMS_TYPE_IOCTL_PREFIXES => count * 0x100,
417            _ => unreachable!("invalid xperms_type in validated ExtendedPermissions"),
418        }
419    }
420
421    #[cfg(test)]
422    fn contains(&self, xperm: u16) -> bool {
423        let [postfix, prefix] = xperm.to_le_bytes();
424        if (self.xperms_type == XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES
425            || self.xperms_type == XPERMS_TYPE_NLMSG)
426            && self.xperms_optional_prefix != prefix
427        {
428            return false;
429        }
430        let value = match self.xperms_type {
431            XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES | XPERMS_TYPE_NLMSG => postfix,
432            XPERMS_TYPE_IOCTL_PREFIXES => prefix,
433            _ => unreachable!("invalid xperms_type in validated ExtendedPermissions"),
434        };
435        self.xperms_bitmap.contains(value)
436    }
437}
438
439// A bitmap representing a subset of `{0x0,...,0xff}`.
440#[derive(Clone, Copy, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
441#[repr(C, packed)]
442pub struct XpermsBitmap([le::U32; 8]);
443
444impl XpermsBitmap {
445    const BITMAP_BLOCKS: usize = 8;
446    pub const ALL: Self = Self([le::U32::MAX_VALUE; Self::BITMAP_BLOCKS]);
447    pub const NONE: Self = Self([le::U32::ZERO; Self::BITMAP_BLOCKS]);
448
449    #[cfg(test)]
450    pub fn new(elements: [le::U32; 8]) -> Self {
451        Self(elements)
452    }
453
454    pub fn contains(&self, value: u8) -> bool {
455        let block_index = (value as usize) / 32;
456        let bit_index = ((value as usize) % 32) as u32;
457        self.0[block_index] & le::U32::new(1).shl(bit_index) != 0
458    }
459}
460
461impl std::ops::BitOrAssign<&Self> for XpermsBitmap {
462    fn bitor_assign(&mut self, rhs: &Self) {
463        (0..Self::BITMAP_BLOCKS).for_each(|i| self.0[i] |= rhs.0[i])
464    }
465}
466
467impl std::ops::SubAssign<&Self> for XpermsBitmap {
468    fn sub_assign(&mut self, rhs: &Self) {
469        (0..Self::BITMAP_BLOCKS).for_each(|i| self.0[i] = self.0[i] ^ (self.0[i] & rhs.0[i]))
470    }
471}
472
473array_type!(RoleTransitions, le::U32, Vec<RoleTransition>);
474
475array_type_validate_deref_both!(RoleTransitions);
476
477impl ValidateArray<le::U32, RoleTransition> for RoleTransitions {
478    type Error = anyhow::Error;
479
480    /// [`RoleTransitions`] have no additional metadata (beyond length encoding).
481    fn validate_array(
482        context: &mut PolicyValidationContext,
483        _metadata: &le::U32,
484        items: &[RoleTransition],
485    ) -> Result<(), Self::Error> {
486        items.validate(context)
487    }
488}
489
490#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
491#[repr(C, packed)]
492pub(super) struct RoleTransition {
493    role: le::U32,
494    role_type: le::U32,
495    new_role: le::U32,
496    tclass: le::U32,
497}
498
499impl RoleTransition {
500    pub(super) fn current_role(&self) -> RoleId {
501        RoleId(NonZeroU32::new(self.role.get()).unwrap())
502    }
503
504    pub(super) fn type_(&self) -> TypeId {
505        TypeId(NonZeroU32::new(self.role_type.get()).unwrap())
506    }
507
508    pub(super) fn class(&self) -> ClassId {
509        ClassId(NonZeroU32::new(self.tclass.get()).unwrap())
510    }
511
512    pub(super) fn new_role(&self) -> RoleId {
513        RoleId(NonZeroU32::new(self.new_role.get()).unwrap())
514    }
515}
516
517impl Validate for [RoleTransition] {
518    type Error = anyhow::Error;
519
520    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
521        for role_transition in self {
522            NonZeroU32::new(role_transition.role.get())
523                .ok_or(ValidateError::NonOptionalIdIsZero)?;
524            NonZeroU32::new(role_transition.role_type.get())
525                .ok_or(ValidateError::NonOptionalIdIsZero)?;
526            NonZeroU32::new(role_transition.tclass.get())
527                .ok_or(ValidateError::NonOptionalIdIsZero)?;
528            NonZeroU32::new(role_transition.new_role.get())
529                .ok_or(ValidateError::NonOptionalIdIsZero)?;
530        }
531        Ok(())
532    }
533}
534
535array_type!(RoleAllows, le::U32, Vec<RoleAllow>);
536
537array_type_validate_deref_both!(RoleAllows);
538
539impl ValidateArray<le::U32, RoleAllow> for RoleAllows {
540    type Error = anyhow::Error;
541
542    /// [`RoleAllows`] have no additional metadata (beyond length encoding).
543    fn validate_array(
544        context: &mut PolicyValidationContext,
545        _metadata: &le::U32,
546        items: &[RoleAllow],
547    ) -> Result<(), Self::Error> {
548        items.validate(context)
549    }
550}
551
552#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
553#[repr(C, packed)]
554pub(super) struct RoleAllow {
555    role: le::U32,
556    new_role: le::U32,
557}
558
559impl RoleAllow {
560    pub(super) fn source_role(&self) -> RoleId {
561        RoleId(NonZeroU32::new(self.role.get()).unwrap())
562    }
563
564    pub(super) fn new_role(&self) -> RoleId {
565        RoleId(NonZeroU32::new(self.new_role.get()).unwrap())
566    }
567}
568
569impl Validate for [RoleAllow] {
570    type Error = anyhow::Error;
571
572    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
573        for rule in self {
574            NonZeroU32::new(rule.role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
575            NonZeroU32::new(rule.new_role.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
576        }
577        Ok(())
578    }
579}
580
581#[derive(Debug, PartialEq)]
582pub(super) enum FilenameTransitionList {
583    PolicyVersionGeq33(SimpleArray<FilenameTransitions>),
584    PolicyVersionLeq32(SimpleArray<DeprecatedFilenameTransitions>),
585}
586
587impl Validate for FilenameTransitionList {
588    type Error = anyhow::Error;
589
590    fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
591        match self {
592            Self::PolicyVersionLeq32(list) => {
593                list.validate(context).map_err(Into::<anyhow::Error>::into)
594            }
595            Self::PolicyVersionGeq33(list) => {
596                list.validate(context).map_err(Into::<anyhow::Error>::into)
597            }
598        }
599    }
600}
601
602pub(super) type FilenameTransitions = Vec<FilenameTransition>;
603
604impl Validate for FilenameTransitions {
605    type Error = anyhow::Error;
606
607    /// TODO: Validate sequence of [`FilenameTransition`] objects.
608    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
609        Ok(())
610    }
611}
612
613#[derive(Debug, PartialEq)]
614pub(super) struct FilenameTransition {
615    filename: SimpleArray<Vec<u8>>,
616    transition_type: le::U32,
617    transition_class: le::U32,
618    items: SimpleArray<FilenameTransitionItems>,
619}
620
621impl FilenameTransition {
622    pub(super) fn name_bytes(&self) -> &[u8] {
623        &self.filename.data
624    }
625
626    pub(super) fn target_type(&self) -> TypeId {
627        TypeId(NonZeroU32::new(self.transition_type.get()).unwrap())
628    }
629
630    pub(super) fn target_class(&self) -> ClassId {
631        ClassId(NonZeroU32::new(self.transition_class.get()).unwrap())
632    }
633
634    pub(super) fn outputs(&self) -> &[FilenameTransitionItem] {
635        &self.items.data
636    }
637}
638
639impl Parse for FilenameTransition
640where
641    SimpleArray<Vec<u8>>: Parse,
642    SimpleArray<FilenameTransitionItems>: Parse,
643{
644    type Error = anyhow::Error;
645
646    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
647        let tail = bytes;
648
649        let (filename, tail) = SimpleArray::<Vec<u8>>::parse(tail)
650            .map_err(Into::<anyhow::Error>::into)
651            .context("parsing filename for filename transition")?;
652
653        let (transition_type, tail) = PolicyCursor::parse::<le::U32>(tail)?;
654
655        let (transition_class, tail) = PolicyCursor::parse::<le::U32>(tail)?;
656
657        let (items, tail) = SimpleArray::<FilenameTransitionItems>::parse(tail)
658            .map_err(Into::<anyhow::Error>::into)
659            .context("parsing items for filename transition")?;
660
661        Ok((Self { filename, transition_type, transition_class, items }, tail))
662    }
663}
664
665pub(super) type FilenameTransitionItems = Vec<FilenameTransitionItem>;
666
667#[derive(Debug, PartialEq)]
668pub(super) struct FilenameTransitionItem {
669    stypes: ExtensibleBitmap,
670    out_type: le::U32,
671}
672
673impl FilenameTransitionItem {
674    pub(super) fn has_source_type(&self, source_type: TypeId) -> bool {
675        self.stypes.is_set(source_type.0.get() - 1)
676    }
677
678    pub(super) fn out_type(&self) -> TypeId {
679        TypeId(NonZeroU32::new(self.out_type.get()).unwrap())
680    }
681}
682
683impl Parse for FilenameTransitionItem
684where
685    ExtensibleBitmap: Parse,
686{
687    type Error = anyhow::Error;
688
689    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
690        let tail = bytes;
691
692        let (stypes, tail) = ExtensibleBitmap::parse(tail)
693            .map_err(Into::<anyhow::Error>::into)
694            .context("parsing stypes extensible bitmap for file transition")?;
695
696        let (out_type, tail) = PolicyCursor::parse::<le::U32>(tail)?;
697
698        Ok((Self { stypes, out_type }, tail))
699    }
700}
701
702pub(super) type DeprecatedFilenameTransitions = Vec<DeprecatedFilenameTransition>;
703
704impl Validate for DeprecatedFilenameTransitions {
705    type Error = anyhow::Error;
706
707    /// TODO: Validate sequence of [`DeprecatedFilenameTransition`] objects.
708    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
709        Ok(())
710    }
711}
712
713#[derive(Debug, PartialEq)]
714pub(super) struct DeprecatedFilenameTransition {
715    filename: SimpleArray<Vec<u8>>,
716    metadata: DeprecatedFilenameTransitionMetadata,
717}
718
719impl DeprecatedFilenameTransition {
720    pub(super) fn name_bytes(&self) -> &[u8] {
721        &self.filename.data
722    }
723
724    pub(super) fn source_type(&self) -> TypeId {
725        TypeId(NonZeroU32::new(self.metadata.source_type.get()).unwrap())
726    }
727
728    pub(super) fn target_type(&self) -> TypeId {
729        TypeId(NonZeroU32::new(self.metadata.transition_type.get()).unwrap())
730    }
731
732    pub(super) fn target_class(&self) -> ClassId {
733        ClassId(NonZeroU32::new(self.metadata.transition_class.get()).unwrap())
734    }
735
736    pub(super) fn out_type(&self) -> TypeId {
737        TypeId(NonZeroU32::new(self.metadata.out_type.get()).unwrap())
738    }
739}
740
741impl Parse for DeprecatedFilenameTransition
742where
743    SimpleArray<Vec<u8>>: Parse,
744{
745    type Error = anyhow::Error;
746
747    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
748        let tail = bytes;
749
750        let (filename, tail) = SimpleArray::<Vec<u8>>::parse(tail)
751            .map_err(Into::<anyhow::Error>::into)
752            .context("parsing filename for deprecated filename transition")?;
753
754        let (metadata, tail) = PolicyCursor::parse::<DeprecatedFilenameTransitionMetadata>(tail)?;
755
756        Ok((Self { filename, metadata }, tail))
757    }
758}
759
760#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
761#[repr(C, packed)]
762pub(super) struct DeprecatedFilenameTransitionMetadata {
763    source_type: le::U32,
764    transition_type: le::U32,
765    transition_class: le::U32,
766    out_type: le::U32,
767}
768
769pub(super) type InitialSids = Vec<InitialSid>;
770
771impl Validate for InitialSids {
772    type Error = anyhow::Error;
773
774    /// TODO: Validate consistency of sequence of [`InitialSid`] objects.
775    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
776        for initial_sid in crate::InitialSid::all_variants() {
777            self.iter()
778                .find(|initial| initial.id().get() == *initial_sid as u32)
779                .ok_or(ValidateError::MissingInitialSid { initial_sid: *initial_sid })?;
780        }
781        Ok(())
782    }
783}
784
785#[derive(Debug, PartialEq)]
786pub(super) struct InitialSid {
787    id: le::U32,
788    context: Context,
789}
790
791impl InitialSid {
792    pub(super) fn id(&self) -> le::U32 {
793        self.id
794    }
795
796    pub(super) fn context(&self) -> &Context {
797        &self.context
798    }
799}
800
801impl Parse for InitialSid
802where
803    Context: Parse,
804{
805    type Error = anyhow::Error;
806
807    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
808        let tail = bytes;
809
810        let (id, tail) = PolicyCursor::parse::<le::U32>(tail)?;
811
812        let (context, tail) = Context::parse(tail)
813            .map_err(Into::<anyhow::Error>::into)
814            .context("parsing context for initial sid")?;
815
816        Ok((Self { id, context }, tail))
817    }
818}
819
820#[derive(Debug, PartialEq)]
821pub(super) struct Context {
822    metadata: ContextMetadata,
823    mls_range: MlsRange,
824}
825
826impl Context {
827    pub(super) fn user_id(&self) -> UserId {
828        UserId(NonZeroU32::new(self.metadata.user.get()).unwrap())
829    }
830    pub(super) fn role_id(&self) -> RoleId {
831        RoleId(NonZeroU32::new(self.metadata.role.get()).unwrap())
832    }
833    pub(super) fn type_id(&self) -> TypeId {
834        TypeId(NonZeroU32::new(self.metadata.context_type.get()).unwrap())
835    }
836    pub(super) fn low_level(&self) -> &MlsLevel {
837        self.mls_range.low()
838    }
839    pub(super) fn high_level(&self) -> &Option<MlsLevel> {
840        self.mls_range.high()
841    }
842}
843
844impl Parse for Context
845where
846    MlsRange: Parse,
847{
848    type Error = anyhow::Error;
849
850    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
851        let tail = bytes;
852
853        let (metadata, tail) =
854            PolicyCursor::parse::<ContextMetadata>(tail).context("parsing metadata for context")?;
855
856        let (mls_range, tail) = MlsRange::parse(tail)
857            .map_err(Into::<anyhow::Error>::into)
858            .context("parsing mls range for context")?;
859
860        Ok((Self { metadata, mls_range }, tail))
861    }
862}
863
864#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
865#[repr(C, packed)]
866pub(super) struct ContextMetadata {
867    user: le::U32,
868    role: le::U32,
869    context_type: le::U32,
870}
871
872pub(super) type NamedContextPairs = Vec<NamedContextPair>;
873
874impl Validate for NamedContextPairs {
875    type Error = anyhow::Error;
876
877    /// TODO: Validate consistency of sequence of [`NamedContextPairs`] objects.
878    ///
879    /// TODO: Is different validation required for `filesystems` and `network_interfaces`? If so,
880    /// create wrapper types with different [`Validate`] implementations.
881    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
882        Ok(())
883    }
884}
885
886#[derive(Debug, PartialEq)]
887pub(super) struct NamedContextPair {
888    name: SimpleArray<Vec<u8>>,
889    context1: Context,
890    context2: Context,
891}
892
893impl Parse for NamedContextPair
894where
895    SimpleArray<Vec<u8>>: Parse,
896    Context: Parse,
897{
898    type Error = anyhow::Error;
899
900    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
901        let tail = bytes;
902
903        let (name, tail) = SimpleArray::parse(tail)
904            .map_err(Into::<anyhow::Error>::into)
905            .context("parsing filesystem context name")?;
906
907        let (context1, tail) = Context::parse(tail)
908            .map_err(Into::<anyhow::Error>::into)
909            .context("parsing first context for filesystem context")?;
910
911        let (context2, tail) = Context::parse(tail)
912            .map_err(Into::<anyhow::Error>::into)
913            .context("parsing second context for filesystem context")?;
914
915        Ok((Self { name, context1, context2 }, tail))
916    }
917}
918
919pub(super) type Ports = Vec<Port>;
920
921impl Validate for Ports {
922    type Error = anyhow::Error;
923
924    /// TODO: Validate consistency of sequence of [`Ports`] objects.
925    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
926        Ok(())
927    }
928}
929
930#[derive(Debug, PartialEq)]
931pub(super) struct Port {
932    metadata: PortMetadata,
933    context: Context,
934}
935
936impl Parse for Port
937where
938    Context: Parse,
939{
940    type Error = anyhow::Error;
941
942    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
943        let tail = bytes;
944
945        let (metadata, tail) =
946            PolicyCursor::parse::<PortMetadata>(tail).context("parsing metadata for context")?;
947
948        let (context, tail) = Context::parse(tail)
949            .map_err(Into::<anyhow::Error>::into)
950            .context("parsing context for port")?;
951
952        Ok((Self { metadata, context }, tail))
953    }
954}
955
956#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
957#[repr(C, packed)]
958pub(super) struct PortMetadata {
959    protocol: le::U32,
960    low_port: le::U32,
961    high_port: le::U32,
962}
963
964pub(super) type Nodes = Vec<Node>;
965
966impl Validate for Nodes {
967    type Error = anyhow::Error;
968
969    /// TODO: Validate consistency of sequence of [`Node`] objects.
970    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
971        Ok(())
972    }
973}
974
975#[derive(Debug, PartialEq)]
976pub(super) struct Node {
977    address: le::U32,
978    mask: le::U32,
979    context: Context,
980}
981
982impl Parse for Node
983where
984    Context: Parse,
985{
986    type Error = anyhow::Error;
987
988    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
989        let tail = bytes;
990
991        let (address, tail) = PolicyCursor::parse::<le::U32>(tail)?;
992
993        let (mask, tail) = PolicyCursor::parse::<le::U32>(tail)?;
994
995        let (context, tail) = Context::parse(tail)
996            .map_err(Into::<anyhow::Error>::into)
997            .context("parsing context for node")?;
998
999        Ok((Self { address, mask, context }, tail))
1000    }
1001}
1002
1003impl Validate for Node {
1004    type Error = anyhow::Error;
1005
1006    /// TODO: Validate consistency between fields of [`Node`].
1007    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
1008        Ok(())
1009    }
1010}
1011
1012pub(super) type FsUses = Vec<FsUse>;
1013
1014impl Validate for FsUses {
1015    type Error = anyhow::Error;
1016
1017    fn validate(&self, context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
1018        for fs_use in self {
1019            fs_use.validate(context)?;
1020        }
1021        Ok(())
1022    }
1023}
1024
1025#[derive(Debug, PartialEq)]
1026pub(super) struct FsUse {
1027    behavior_and_name: Array<FsUseMetadata, Vec<u8>>,
1028    context: Context,
1029}
1030
1031impl FsUse {
1032    pub fn fs_type(&self) -> &[u8] {
1033        &self.behavior_and_name.data
1034    }
1035
1036    pub(super) fn behavior(&self) -> FsUseType {
1037        FsUseType::try_from(self.behavior_and_name.metadata.behavior).unwrap()
1038    }
1039
1040    pub(super) fn context(&self) -> &Context {
1041        &self.context
1042    }
1043}
1044
1045impl Parse for FsUse
1046where
1047    Array<FsUseMetadata, Vec<u8>>: Parse,
1048    Context: Parse,
1049{
1050    type Error = anyhow::Error;
1051
1052    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
1053        let tail = bytes;
1054
1055        let (behavior_and_name, tail) = Array::<FsUseMetadata, Vec<u8>>::parse(tail)
1056            .map_err(Into::<anyhow::Error>::into)
1057            .context("parsing fs use metadata")?;
1058
1059        let (context, tail) = Context::parse(tail)
1060            .map_err(Into::<anyhow::Error>::into)
1061            .context("parsing context for fs use")?;
1062
1063        Ok((Self { behavior_and_name, context }, tail))
1064    }
1065}
1066
1067impl Validate for FsUse {
1068    type Error = anyhow::Error;
1069
1070    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
1071        FsUseType::try_from(self.behavior_and_name.metadata.behavior)?;
1072
1073        Ok(())
1074    }
1075}
1076
1077#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1078#[repr(C, packed)]
1079pub(super) struct FsUseMetadata {
1080    /// The type of `fs_use` statement.
1081    behavior: le::U32,
1082    /// The length of the name in the name_and_behavior field of FsUse.
1083    name_length: le::U32,
1084}
1085
1086impl Counted for FsUseMetadata {
1087    fn count(&self) -> u32 {
1088        self.name_length.get()
1089    }
1090}
1091
1092/// Discriminates among the different kinds of "fs_use_*" labeling statements in the policy; see
1093/// https://selinuxproject.org/page/FileStatements.
1094#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
1095pub enum FsUseType {
1096    Xattr = 1,
1097    Trans = 2,
1098    Task = 3,
1099}
1100
1101impl TryFrom<le::U32> for FsUseType {
1102    type Error = anyhow::Error;
1103
1104    fn try_from(value: le::U32) -> Result<Self, Self::Error> {
1105        match value.get() {
1106            1 => Ok(FsUseType::Xattr),
1107            2 => Ok(FsUseType::Trans),
1108            3 => Ok(FsUseType::Task),
1109            _ => Err(ValidateError::InvalidFsUseType { value: value.get() }.into()),
1110        }
1111    }
1112}
1113
1114pub(super) type IPv6Nodes = Vec<IPv6Node>;
1115
1116impl Validate for IPv6Nodes {
1117    type Error = anyhow::Error;
1118
1119    /// TODO: Validate consistency of sequence of [`IPv6Node`] objects.
1120    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
1121        Ok(())
1122    }
1123}
1124
1125#[derive(Debug, PartialEq)]
1126pub(super) struct IPv6Node {
1127    address: [le::U32; 4],
1128    mask: [le::U32; 4],
1129    context: Context,
1130}
1131
1132impl Parse for IPv6Node
1133where
1134    Context: Parse,
1135{
1136    type Error = anyhow::Error;
1137
1138    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
1139        let tail = bytes;
1140
1141        let (address, tail) = PolicyCursor::parse::<[le::U32; 4]>(tail)?;
1142
1143        let (mask, tail) = PolicyCursor::parse::<[le::U32; 4]>(tail)?;
1144
1145        let (context, tail) = Context::parse(tail)
1146            .map_err(Into::<anyhow::Error>::into)
1147            .context("parsing context for ipv6 node")?;
1148
1149        Ok((Self { address, mask, context }, tail))
1150    }
1151}
1152
1153pub(super) type InfinitiBandPartitionKeys = Vec<InfinitiBandPartitionKey>;
1154
1155impl Validate for InfinitiBandPartitionKeys {
1156    type Error = anyhow::Error;
1157
1158    /// TODO: Validate consistency of sequence of [`InfinitiBandPartitionKey`] objects.
1159    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
1160        Ok(())
1161    }
1162}
1163
1164#[derive(Debug, PartialEq)]
1165pub(super) struct InfinitiBandPartitionKey {
1166    low: le::U32,
1167    high: le::U32,
1168    context: Context,
1169}
1170
1171impl Parse for InfinitiBandPartitionKey
1172where
1173    Context: Parse,
1174{
1175    type Error = anyhow::Error;
1176
1177    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
1178        let tail = bytes;
1179
1180        let (low, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1181
1182        let (high, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1183
1184        let (context, tail) = Context::parse(tail)
1185            .map_err(Into::<anyhow::Error>::into)
1186            .context("parsing context for infiniti band partition key")?;
1187
1188        Ok((Self { low, high, context }, tail))
1189    }
1190}
1191
1192impl Validate for InfinitiBandPartitionKey {
1193    type Error = anyhow::Error;
1194
1195    /// TODO: Validate consistency between fields of [`InfinitiBandPartitionKey`].
1196    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
1197        Ok(())
1198    }
1199}
1200
1201pub(super) type InfinitiBandEndPorts = Vec<InfinitiBandEndPort>;
1202
1203impl Validate for InfinitiBandEndPorts {
1204    type Error = anyhow::Error;
1205
1206    /// TODO: Validate sequence of [`InfinitiBandEndPort`] objects.
1207    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
1208        Ok(())
1209    }
1210}
1211
1212#[derive(Debug, PartialEq)]
1213pub(super) struct InfinitiBandEndPort {
1214    port_and_name: Array<InfinitiBandEndPortMetadata, Vec<u8>>,
1215    context: Context,
1216}
1217
1218impl Parse for InfinitiBandEndPort
1219where
1220    Array<InfinitiBandEndPortMetadata, Vec<u8>>: Parse,
1221    Context: Parse,
1222{
1223    type Error = anyhow::Error;
1224
1225    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
1226        let tail = bytes;
1227
1228        let (port_and_name, tail) = Array::<InfinitiBandEndPortMetadata, Vec<u8>>::parse(tail)
1229            .map_err(Into::<anyhow::Error>::into)
1230            .context("parsing infiniti band end port metadata")?;
1231
1232        let (context, tail) = Context::parse(tail)
1233            .map_err(Into::<anyhow::Error>::into)
1234            .context("parsing context for infiniti band end port")?;
1235
1236        Ok((Self { port_and_name, context }, tail))
1237    }
1238}
1239
1240#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1241#[repr(C, packed)]
1242pub(super) struct InfinitiBandEndPortMetadata {
1243    length: le::U32,
1244    port: le::U32,
1245}
1246
1247impl Counted for InfinitiBandEndPortMetadata {
1248    fn count(&self) -> u32 {
1249        self.length.get()
1250    }
1251}
1252
1253pub(super) type GenericFsContexts = Vec<GenericFsContext>;
1254
1255impl Validate for GenericFsContexts {
1256    type Error = anyhow::Error;
1257
1258    /// TODO: Validate sequence of  [`GenericFsContext`] objects.
1259    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
1260        Ok(())
1261    }
1262}
1263
1264/// Information parsed parsed from `genfscon [fs_type] [partial_path] [fs_context]` statements
1265/// about a specific filesystem type.
1266#[derive(Debug, PartialEq)]
1267pub(super) struct GenericFsContext {
1268    /// The filesystem type.
1269    fs_type: SimpleArray<Vec<u8>>,
1270    /// The set of contexts defined for this filesystem.
1271    contexts: SimpleArray<FsContexts>,
1272}
1273
1274impl GenericFsContext {
1275    pub(super) fn fs_type(&self) -> &[u8] {
1276        &self.fs_type.data
1277    }
1278
1279    pub(super) fn contexts(&self) -> &FsContexts {
1280        &self.contexts.data
1281    }
1282}
1283
1284impl Parse for GenericFsContext
1285where
1286    SimpleArray<Vec<u8>>: Parse,
1287    SimpleArray<FsContexts>: Parse,
1288{
1289    type Error = anyhow::Error;
1290
1291    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
1292        let tail = bytes;
1293
1294        let (fs_type, tail) = SimpleArray::<Vec<u8>>::parse(tail)
1295            .map_err(Into::<anyhow::Error>::into)
1296            .context("parsing generic filesystem context name")?;
1297
1298        let (contexts, tail) = SimpleArray::<FsContexts>::parse(tail)
1299            .map_err(Into::<anyhow::Error>::into)
1300            .context("parsing generic filesystem contexts")?;
1301
1302        Ok((Self { fs_type, contexts }, tail))
1303    }
1304}
1305
1306pub(super) type FsContexts = Vec<FsContext>;
1307
1308#[derive(Debug, PartialEq)]
1309pub(super) struct FsContext {
1310    /// The partial path, relative to the root of the filesystem. The partial path can only be set for
1311    /// virtual filesystems, like `proc/`. Otherwise, this must be `/`
1312    partial_path: SimpleArray<Vec<u8>>,
1313    /// Optional. When provided, the context will only be applied to files of this type. Allowed files
1314    /// types are: blk_file, chr_file, dir, fifo_file, lnk_file, sock_file, file. When set to 0, the
1315    /// context applies to all file types.
1316    class: le::U32,
1317    /// The security context allocated to the filesystem.
1318    context: Context,
1319}
1320
1321impl FsContext {
1322    pub(super) fn partial_path(&self) -> &[u8] {
1323        &self.partial_path.data
1324    }
1325
1326    pub(super) fn context(&self) -> &Context {
1327        &self.context
1328    }
1329
1330    pub(super) fn class(&self) -> Option<ClassId> {
1331        NonZeroU32::new(self.class.into()).map(ClassId)
1332    }
1333}
1334
1335impl Parse for FsContext
1336where
1337    SimpleArray<Vec<u8>>: Parse,
1338    Context: Parse,
1339{
1340    type Error = anyhow::Error;
1341
1342    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
1343        let tail = bytes;
1344
1345        let (partial_path, tail) = SimpleArray::<Vec<u8>>::parse(tail)
1346            .map_err(Into::<anyhow::Error>::into)
1347            .context("parsing filesystem context partial path")?;
1348
1349        let (class, tail) = PolicyCursor::parse::<le::U32>(tail)?;
1350
1351        let (context, tail) = Context::parse(tail)
1352            .map_err(Into::<anyhow::Error>::into)
1353            .context("parsing context for filesystem context")?;
1354
1355        Ok((Self { partial_path, class, context }, tail))
1356    }
1357}
1358
1359pub(super) type RangeTransitions = Vec<RangeTransition>;
1360
1361impl Validate for RangeTransitions {
1362    type Error = anyhow::Error;
1363
1364    /// TODO: Validate sequence of [`RangeTransition`] objects.
1365    fn validate(&self, _context: &mut PolicyValidationContext) -> Result<(), Self::Error> {
1366        for range_transition in self {
1367            if range_transition.metadata.target_class.get() == 0 {
1368                return Err(ValidateError::NonOptionalIdIsZero.into());
1369            }
1370        }
1371        Ok(())
1372    }
1373}
1374
1375#[derive(Debug, PartialEq)]
1376pub(super) struct RangeTransition {
1377    metadata: RangeTransitionMetadata,
1378    mls_range: MlsRange,
1379}
1380
1381impl RangeTransition {
1382    pub fn source_type(&self) -> TypeId {
1383        TypeId(NonZeroU32::new(self.metadata.source_type.get()).unwrap())
1384    }
1385
1386    pub fn target_type(&self) -> TypeId {
1387        TypeId(NonZeroU32::new(self.metadata.target_type.get()).unwrap())
1388    }
1389
1390    pub fn target_class(&self) -> ClassId {
1391        ClassId(NonZeroU32::new(self.metadata.target_class.get()).unwrap())
1392    }
1393
1394    pub fn mls_range(&self) -> &MlsRange {
1395        &self.mls_range
1396    }
1397}
1398
1399impl Parse for RangeTransition
1400where
1401    MlsRange: Parse,
1402{
1403    type Error = anyhow::Error;
1404
1405    fn parse(bytes: PolicyCursor) -> Result<(Self, PolicyCursor), Self::Error> {
1406        let tail = bytes;
1407
1408        let (metadata, tail) = PolicyCursor::parse::<RangeTransitionMetadata>(tail)
1409            .context("parsing range transition metadata")?;
1410
1411        let (mls_range, tail) = MlsRange::parse(tail)
1412            .map_err(Into::<anyhow::Error>::into)
1413            .context("parsing mls range for range transition")?;
1414
1415        Ok((Self { metadata, mls_range }, tail))
1416    }
1417}
1418
1419#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1420#[repr(C, packed)]
1421pub(super) struct RangeTransitionMetadata {
1422    source_type: le::U32,
1423    target_type: le::U32,
1424    target_class: le::U32,
1425}
1426
1427#[cfg(test)]
1428pub(super) mod testing {
1429    use super::AccessVectorRule;
1430    use std::cmp::Ordering;
1431
1432    pub(in super::super) fn access_vector_rule_ordering(
1433        left: &AccessVectorRule,
1434        right: &AccessVectorRule,
1435    ) -> Ordering {
1436        (
1437            left.metadata.source_type,
1438            left.metadata.target_type,
1439            left.metadata.class,
1440            left.metadata.access_vector_rule_type,
1441        )
1442            .cmp(&(
1443                right.metadata.source_type,
1444                right.metadata.target_type,
1445                right.metadata.class,
1446                right.metadata.access_vector_rule_type,
1447            ))
1448    }
1449}
1450
1451#[cfg(test)]
1452mod tests {
1453    use super::super::{ClassId, find_class_by_name, parse_policy_by_value};
1454    use super::{
1455        ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM, ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM,
1456        ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES,
1457        XPERMS_TYPE_IOCTL_PREFIXES, XPERMS_TYPE_NLMSG,
1458    };
1459    use std::num::NonZeroU32;
1460
1461    impl super::AccessVectorRuleMetadata {
1462        /// Returns whether this access vector rule comes from an
1463        /// `allowxperm [source] [target]:[class] [permission] {
1464        /// [extended_permissions] };` policy statement.
1465        pub fn is_allowxperm(&self) -> bool {
1466            (self.access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM) != 0
1467        }
1468
1469        /// Returns whether this access vector rule comes from an
1470        /// `auditallowxperm [source] [target]:[class] [permission] {
1471        /// [extended_permissions] };` policy statement.
1472        pub fn is_auditallowxperm(&self) -> bool {
1473            (self.access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM) != 0
1474        }
1475
1476        /// Returns whether this access vector rule comes from a
1477        /// `dontauditxperm [source] [target]:[class] [permission] {
1478        /// [extended_permissions] };` policy statement.
1479        pub fn is_dontauditxperm(&self) -> bool {
1480            (self.access_vector_rule_type & ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM) != 0
1481        }
1482
1483        /// Returns the target class id in this access vector rule. This id
1484        /// corresponds to the [`super::symbols::Class`] `id()` of some class in the
1485        /// same policy. Although the index is returned as a 32-bit value, the field
1486        /// itself is 16-bit
1487        pub fn target_class(&self) -> ClassId {
1488            ClassId(NonZeroU32::new(self.class.into()).unwrap())
1489        }
1490    }
1491
1492    #[test]
1493    fn parse_allowxperm_one_ioctl() {
1494        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1495        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1496        let parsed_policy = &policy.0;
1497        parsed_policy.validate().expect("validate policy");
1498
1499        let class_id = find_class_by_name(parsed_policy.classes(), "class_one_ioctl")
1500            .expect("look up class_one_ioctl")
1501            .id();
1502
1503        let rules: Vec<_> = parsed_policy
1504            .access_vector_rules_for_test()
1505            .filter(|rule| rule.metadata.target_class() == class_id)
1506            .collect();
1507
1508        assert_eq!(rules.len(), 1);
1509        assert!(rules[0].metadata.is_allowxperm());
1510        if let Some(xperms) = rules[0].extended_permissions() {
1511            assert_eq!(xperms.count(), 1);
1512            assert!(xperms.contains(0xabcd));
1513        } else {
1514            panic!("unexpected permission data type")
1515        }
1516    }
1517
1518    // `ioctl` extended permissions that are declared in the same rule, and have the same
1519    // high byte, are stored in the same `AccessVectorRule` in the compiled policy.
1520    #[test]
1521    fn parse_allowxperm_two_ioctls_same_range() {
1522        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1523        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1524        let parsed_policy = &policy.0;
1525        parsed_policy.validate().expect("validate policy");
1526
1527        let class_id = find_class_by_name(parsed_policy.classes(), "class_two_ioctls_same_range")
1528            .expect("look up class_two_ioctls_same_range")
1529            .id();
1530
1531        let rules: Vec<_> = parsed_policy
1532            .access_vector_rules_for_test()
1533            .filter(|rule| rule.metadata.target_class() == class_id)
1534            .collect();
1535
1536        assert_eq!(rules.len(), 1);
1537        assert!(rules[0].metadata.is_allowxperm());
1538        if let Some(xperms) = rules[0].extended_permissions() {
1539            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1540            assert_eq!(xperms.xperms_optional_prefix, 0x12);
1541            assert_eq!(xperms.count(), 2);
1542            assert!(xperms.contains(0x1234));
1543            assert!(xperms.contains(0x1256));
1544        } else {
1545            panic!("unexpected permission data type")
1546        }
1547    }
1548
1549    // `ioctl` extended permissions that are declared in different rules, but that have the same
1550    // high byte, are stored in the same `AccessVectorRule` in the compiled policy.
1551    #[test]
1552    fn parse_allowxperm_two_ioctls_same_range_diff_rules() {
1553        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1554        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1555        let parsed_policy = &policy.0;
1556        parsed_policy.validate().expect("validate policy");
1557
1558        let class_id =
1559            find_class_by_name(parsed_policy.classes(), "class_four_ioctls_same_range_diff_rules")
1560                .expect("look up class_four_ioctls_same_range_diff_rules")
1561                .id();
1562
1563        let rules: Vec<_> = parsed_policy
1564            .access_vector_rules_for_test()
1565            .filter(|rule| rule.metadata.target_class() == class_id)
1566            .collect();
1567
1568        assert_eq!(rules.len(), 1);
1569        assert!(rules[0].metadata.is_allowxperm());
1570        if let Some(xperms) = rules[0].extended_permissions() {
1571            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1572            assert_eq!(xperms.xperms_optional_prefix, 0x30);
1573            assert_eq!(xperms.count(), 4);
1574            assert!(xperms.contains(0x3008));
1575            assert!(xperms.contains(0x3009));
1576            assert!(xperms.contains(0x3011));
1577            assert!(xperms.contains(0x3013));
1578        } else {
1579            panic!("unexpected permission data type")
1580        }
1581    }
1582
1583    // `ioctl` extended permissions that are declared in the same rule, and have different
1584    // high bytes, are stored in different `AccessVectorRule`s in the compiled policy.
1585    #[test]
1586    fn parse_allowxperm_two_ioctls_different_range() {
1587        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1588        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1589        let parsed_policy = &policy.0;
1590        parsed_policy.validate().expect("validate policy");
1591
1592        let class_id = find_class_by_name(parsed_policy.classes(), "class_two_ioctls_diff_range")
1593            .expect("look up class_two_ioctls_diff_range")
1594            .id();
1595
1596        let rules: Vec<_> = parsed_policy
1597            .access_vector_rules_for_test()
1598            .filter(|rule| rule.metadata.target_class() == class_id)
1599            .collect();
1600
1601        assert_eq!(rules.len(), 2);
1602        assert!(rules[0].metadata.is_allowxperm());
1603        if let Some(xperms) = rules[0].extended_permissions() {
1604            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1605            assert_eq!(xperms.xperms_optional_prefix, 0x56);
1606            assert_eq!(xperms.count(), 1);
1607            assert!(xperms.contains(0x5678));
1608        } else {
1609            panic!("unexpected permission data type")
1610        }
1611        assert!(rules[1].metadata.is_allowxperm());
1612        if let Some(xperms) = rules[1].extended_permissions() {
1613            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1614            assert_eq!(xperms.xperms_optional_prefix, 0x12);
1615            assert_eq!(xperms.count(), 1);
1616            assert!(xperms.contains(0x1234));
1617        } else {
1618            panic!("unexpected permission data type")
1619        }
1620    }
1621
1622    // If a set of `ioctl` extended permissions consists of all xperms with a given high byte,
1623    // then it is represented by one `AccessVectorRule`.
1624    #[test]
1625    fn parse_allowxperm_one_driver_range() {
1626        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1627        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1628        let parsed_policy = &policy.0;
1629        parsed_policy.validate().expect("validate policy");
1630
1631        let class_id = find_class_by_name(parsed_policy.classes(), "class_one_driver_range")
1632            .expect("look up class_one_driver_range")
1633            .id();
1634
1635        let rules: Vec<_> = parsed_policy
1636            .access_vector_rules_for_test()
1637            .filter(|rule| rule.metadata.target_class() == class_id)
1638            .collect();
1639
1640        assert_eq!(rules.len(), 1);
1641        assert!(rules[0].metadata.is_allowxperm());
1642        if let Some(xperms) = rules[0].extended_permissions() {
1643            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1644            assert_eq!(xperms.count(), 0x100);
1645            assert!(xperms.contains(0x1000));
1646            assert!(xperms.contains(0x10ab));
1647        } else {
1648            panic!("unexpected permission data type")
1649        }
1650    }
1651
1652    // If a rule grants `ioctl` extended permissions to a wide range that does not fall cleanly on
1653    // divisible-by-256 boundaries, it gets represented in the policy as three `AccessVectorRule`s:
1654    // two for the smaller subranges at the ends and one for the large subrange in the middle.
1655    #[test]
1656    fn parse_allowxperm_most_ioctls() {
1657        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1658        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1659        let parsed_policy = &policy.0;
1660        parsed_policy.validate().expect("validate policy");
1661
1662        let class_id = find_class_by_name(parsed_policy.classes(), "class_most_ioctls")
1663            .expect("look up class_most_ioctls")
1664            .id();
1665
1666        let rules: Vec<_> = parsed_policy
1667            .access_vector_rules_for_test()
1668            .filter(|rule| rule.metadata.target_class() == class_id)
1669            .collect();
1670
1671        assert_eq!(rules.len(), 3);
1672        assert!(rules[0].metadata.is_allowxperm());
1673        if let Some(xperms) = rules[0].extended_permissions() {
1674            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1675            assert_eq!(xperms.xperms_optional_prefix, 0xff);
1676            assert_eq!(xperms.count(), 0xfe);
1677            for xperm in 0xff00..0xfffd {
1678                assert!(xperms.contains(xperm));
1679            }
1680        } else {
1681            panic!("unexpected permission data type")
1682        }
1683        if let Some(xperms) = rules[1].extended_permissions() {
1684            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1685            assert_eq!(xperms.xperms_optional_prefix, 0x00);
1686            assert_eq!(xperms.count(), 0xfe);
1687            for xperm in 0x0002..0x0100 {
1688                assert!(xperms.contains(xperm));
1689            }
1690        } else {
1691            panic!("unexpected permission data type")
1692        }
1693        if let Some(xperms) = rules[2].extended_permissions() {
1694            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1695            assert_eq!(xperms.count(), 0xfe00);
1696            for xperm in 0x0100..0xff00 {
1697                assert!(xperms.contains(xperm));
1698            }
1699        } else {
1700            panic!("unexpected permission data type")
1701        }
1702    }
1703
1704    // If a rule grants `ioctl` extended permissions to two wide ranges that do not fall cleanly on
1705    // divisible-by-256 boundaries, they get represented in the policy as five `AccessVectorRule`s:
1706    // four for the smaller subranges at the ends and one for the two large subranges.
1707    #[test]
1708    fn parse_allowxperm_most_ioctls_with_hole() {
1709        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1710        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1711        let parsed_policy = &policy.0;
1712        parsed_policy.validate().expect("validate policy");
1713
1714        let class_id = find_class_by_name(parsed_policy.classes(), "class_most_ioctls_with_hole")
1715            .expect("look up class_most_ioctls_with_hole")
1716            .id();
1717
1718        let rules: Vec<_> = parsed_policy
1719            .access_vector_rules_for_test()
1720            .filter(|rule| rule.metadata.target_class() == class_id)
1721            .collect();
1722
1723        assert_eq!(rules.len(), 5);
1724        assert!(rules[0].metadata.is_allowxperm());
1725        if let Some(xperms) = rules[0].extended_permissions() {
1726            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1727            assert_eq!(xperms.xperms_optional_prefix, 0xff);
1728            assert_eq!(xperms.count(), 0xfe);
1729            for xperm in 0xff00..0xfffd {
1730                assert!(xperms.contains(xperm));
1731            }
1732        } else {
1733            panic!("unexpected permission data type")
1734        }
1735        if let Some(xperms) = rules[1].extended_permissions() {
1736            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1737            assert_eq!(xperms.xperms_optional_prefix, 0x40);
1738            assert_eq!(xperms.count(), 0xfe);
1739            for xperm in 0x4002..0x4100 {
1740                assert!(xperms.contains(xperm));
1741            }
1742        } else {
1743            panic!("unexpected permission data type")
1744        }
1745        assert!(rules[0].metadata.is_allowxperm());
1746        if let Some(xperms) = rules[2].extended_permissions() {
1747            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1748            assert_eq!(xperms.xperms_optional_prefix, 0x2f);
1749            assert_eq!(xperms.count(), 0xfe);
1750            for xperm in 0x2f00..0x2ffd {
1751                assert!(xperms.contains(xperm));
1752            }
1753        } else {
1754            panic!("unexpected permission data type")
1755        }
1756        if let Some(xperms) = rules[3].extended_permissions() {
1757            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
1758            assert_eq!(xperms.xperms_optional_prefix, 0x00);
1759            assert_eq!(xperms.count(), 0xfe);
1760            for xperm in 0x0002..0x0100 {
1761                assert!(xperms.contains(xperm));
1762            }
1763        } else {
1764            panic!("unexpected permission data type")
1765        }
1766        if let Some(xperms) = rules[4].extended_permissions() {
1767            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1768            assert_eq!(xperms.count(), 0xec00);
1769            for xperm in 0x0100..0x2f00 {
1770                assert!(xperms.contains(xperm));
1771            }
1772            for xperm in 0x4100..0xff00 {
1773                assert!(xperms.contains(xperm));
1774            }
1775        } else {
1776            panic!("unexpected permission data type")
1777        }
1778    }
1779
1780    // If a set of `ioctl` extended permissions contains all 16-bit xperms, then it is
1781    // then it is represented by one `AccessVectorRule`. (More generally, the representation
1782    // is a single `AccessVectorRule` as long as the set either fully includes or fully
1783    // excludes each 8-bit prefix range.)
1784    #[test]
1785    fn parse_allowxperm_all_ioctls() {
1786        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1787        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1788        let parsed_policy = &policy.0;
1789        parsed_policy.validate().expect("validate policy");
1790
1791        let class_id = find_class_by_name(parsed_policy.classes(), "class_all_ioctls")
1792            .expect("look up class_all_ioctls")
1793            .id();
1794
1795        let rules: Vec<_> = parsed_policy
1796            .access_vector_rules_for_test()
1797            .filter(|rule| rule.metadata.target_class() == class_id)
1798            .collect();
1799
1800        assert_eq!(rules.len(), 1);
1801        assert!(rules[0].metadata.is_allowxperm());
1802        if let Some(xperms) = rules[0].extended_permissions() {
1803            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIXES);
1804            assert_eq!(xperms.count(), 0x10000);
1805        } else {
1806            panic!("unexpected permission data type")
1807        }
1808    }
1809
1810    #[test]
1811    fn parse_allowxperm_one_nlmsg() {
1812        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1813        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1814        let parsed_policy = &policy.0;
1815        parsed_policy.validate().expect("validate policy");
1816
1817        let class_id = find_class_by_name(parsed_policy.classes(), "class_one_nlmsg")
1818            .expect("look up class_one_nlmsg")
1819            .id();
1820
1821        let rules: Vec<_> = parsed_policy
1822            .access_vector_rules_for_test()
1823            .filter(|rule| rule.metadata.target_class() == class_id)
1824            .collect();
1825
1826        assert_eq!(rules.len(), 1);
1827        assert!(rules[0].metadata.is_allowxperm());
1828        if let Some(xperms) = rules[0].extended_permissions() {
1829            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1830            assert_eq!(xperms.xperms_optional_prefix, 0x00);
1831            assert_eq!(xperms.count(), 1);
1832            assert!(xperms.contains(0x12));
1833        } else {
1834            panic!("unexpected permission data type")
1835        }
1836    }
1837
1838    // `nlmsg` extended permissions that are declared in the same rule, and have the same
1839    // high byte, are stored in the same `AccessVectorRule` in the compiled policy.
1840    #[test]
1841    fn parse_allowxperm_two_nlmsg_same_range() {
1842        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1843        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1844        let parsed_policy = &policy.0;
1845        parsed_policy.validate().expect("validate policy");
1846
1847        let class_id = find_class_by_name(parsed_policy.classes(), "class_two_nlmsg_same_range")
1848            .expect("look up class_two_nlmsg_same_range")
1849            .id();
1850
1851        let rules: Vec<_> = parsed_policy
1852            .access_vector_rules_for_test()
1853            .filter(|rule| rule.metadata.target_class() == class_id)
1854            .collect();
1855
1856        assert_eq!(rules.len(), 1);
1857        assert!(rules[0].metadata.is_allowxperm());
1858        if let Some(xperms) = rules[0].extended_permissions() {
1859            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1860            assert_eq!(xperms.xperms_optional_prefix, 0x00);
1861            assert_eq!(xperms.count(), 2);
1862            assert!(xperms.contains(0x12));
1863            assert!(xperms.contains(0x24));
1864        } else {
1865            panic!("unexpected permission data type")
1866        }
1867    }
1868
1869    // `nlmsg` extended permissions that are declared in the same rule, and have different
1870    // high bytes, are stored in different `AccessVectorRule`s in the compiled policy.
1871    #[test]
1872    fn parse_allowxperm_two_nlmsg_different_range() {
1873        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1874        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1875        let parsed_policy = &policy.0;
1876        parsed_policy.validate().expect("validate policy");
1877
1878        let class_id = find_class_by_name(parsed_policy.classes(), "class_two_nlmsg_diff_range")
1879            .expect("look up class_two_nlmsg_diff_range")
1880            .id();
1881
1882        let rules: Vec<_> = parsed_policy
1883            .access_vector_rules_for_test()
1884            .filter(|rule| rule.metadata.target_class() == class_id)
1885            .collect();
1886
1887        assert_eq!(rules.len(), 2);
1888        assert!(rules[0].metadata.is_allowxperm());
1889        if let Some(xperms) = rules[0].extended_permissions() {
1890            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1891            assert_eq!(xperms.xperms_optional_prefix, 0x10);
1892            assert_eq!(xperms.count(), 1);
1893            assert!(xperms.contains(0x1024));
1894        } else {
1895            panic!("unexpected permission data type")
1896        }
1897        assert!(rules[1].metadata.is_allowxperm());
1898        if let Some(xperms) = rules[1].extended_permissions() {
1899            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1900            assert_eq!(xperms.xperms_optional_prefix, 0x00);
1901            assert_eq!(xperms.count(), 1);
1902            assert!(xperms.contains(0x12));
1903        } else {
1904            panic!("unexpected permission data type")
1905        }
1906    }
1907
1908    // The set of `nlmsg` extended permissions with a given high byte is represented by
1909    // a single `AccessVectorRule` in the compiled policy.
1910    #[test]
1911    fn parse_allowxperm_one_nlmsg_range() {
1912        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1913        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1914        let parsed_policy = &policy.0;
1915        parsed_policy.validate().expect("validate policy");
1916
1917        let class_id = find_class_by_name(parsed_policy.classes(), "class_one_nlmsg_range")
1918            .expect("look up class_one_nlmsg_range")
1919            .id();
1920
1921        let rules: Vec<_> = parsed_policy
1922            .access_vector_rules_for_test()
1923            .filter(|rule| rule.metadata.target_class() == class_id)
1924            .collect();
1925
1926        assert_eq!(rules.len(), 1);
1927        assert!(rules[0].metadata.is_allowxperm());
1928        if let Some(xperms) = rules[0].extended_permissions() {
1929            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1930            assert_eq!(xperms.xperms_optional_prefix, 0x00);
1931            assert_eq!(xperms.count(), 0x100);
1932            for i in 0x0..0xff {
1933                assert!(xperms.contains(i), "{i}");
1934            }
1935        } else {
1936            panic!("unexpected permission data type")
1937        }
1938    }
1939
1940    // A set of `nlmsg` extended permissions consisting of all 16-bit integers with one
1941    // of 2 given prefix bytes is represented by 2 `AccessVectorRule`s in the compiled policy.
1942    //
1943    // The policy compiler allows `nlmsg` extended permission sets of this form, but they
1944    // are not expected to appear in policies.
1945    #[test]
1946    fn parse_allowxperm_two_nlmsg_ranges() {
1947        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1948        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1949        let parsed_policy = &policy.0;
1950        parsed_policy.validate().expect("validate policy");
1951
1952        let class_id = find_class_by_name(parsed_policy.classes(), "class_two_nlmsg_ranges")
1953            .expect("look up class_two_nlmsg_ranges")
1954            .id();
1955
1956        let rules: Vec<_> = parsed_policy
1957            .access_vector_rules_for_test()
1958            .filter(|rule| rule.metadata.target_class() == class_id)
1959            .collect();
1960
1961        assert_eq!(rules.len(), 2);
1962        assert!(rules[0].metadata.is_allowxperm());
1963        if let Some(xperms) = rules[0].extended_permissions() {
1964            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1965            assert_eq!(xperms.xperms_optional_prefix, 0x01);
1966            assert_eq!(xperms.count(), 0x100);
1967            for i in 0x0100..0x01ff {
1968                assert!(xperms.contains(i), "{i}");
1969            }
1970        } else {
1971            panic!("unexpected permission data type")
1972        }
1973        if let Some(xperms) = rules[1].extended_permissions() {
1974            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
1975            assert_eq!(xperms.xperms_optional_prefix, 0x00);
1976            assert_eq!(xperms.count(), 0x100);
1977            for i in 0x0..0xff {
1978                assert!(xperms.contains(i), "{i}");
1979            }
1980        } else {
1981            panic!("unexpected permission data type")
1982        }
1983    }
1984
1985    // A set of `nlmsg` extended permissions consisting of all 16-bit integers with one
1986    // of 3 non-consecutive prefix bytes is represented by 3 `AccessVectorRule`s in the
1987    // compiled policy.
1988    //
1989    // The policy compiler allows `nlmsg` extended permission sets of this form, but they
1990    // are not expected to appear in policies.
1991    #[test]
1992    fn parse_allowxperm_three_separate_nlmsg_ranges() {
1993        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1994        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1995        let parsed_policy = &policy.0;
1996        parsed_policy.validate().expect("validate policy");
1997
1998        let class_id =
1999            find_class_by_name(parsed_policy.classes(), "class_three_separate_nlmsg_ranges")
2000                .expect("look up class_three_separate_nlmsg_ranges")
2001                .id();
2002
2003        let rules: Vec<_> = parsed_policy
2004            .access_vector_rules_for_test()
2005            .filter(|rule| rule.metadata.target_class() == class_id)
2006            .collect();
2007
2008        assert_eq!(rules.len(), 3);
2009        assert!(rules[0].metadata.is_allowxperm());
2010        if let Some(xperms) = rules[0].extended_permissions() {
2011            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2012            assert_eq!(xperms.xperms_optional_prefix, 0x20);
2013            assert_eq!(xperms.count(), 0x100);
2014            for i in 0x2000..0x20ff {
2015                assert!(xperms.contains(i), "{i}");
2016            }
2017        } else {
2018            panic!("unexpected permission data type")
2019        }
2020        if let Some(xperms) = rules[1].extended_permissions() {
2021            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2022            assert_eq!(xperms.xperms_optional_prefix, 0x10);
2023            assert_eq!(xperms.count(), 0x100);
2024            for i in 0x1000..0x10ff {
2025                assert!(xperms.contains(i), "{i}");
2026            }
2027        } else {
2028            panic!("unexpected permission data type")
2029        }
2030        if let Some(xperms) = rules[2].extended_permissions() {
2031            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2032            assert_eq!(xperms.xperms_optional_prefix, 0x00);
2033            assert_eq!(xperms.count(), 0x100);
2034            for i in 0x0..0xff {
2035                assert!(xperms.contains(i), "{i}");
2036            }
2037        } else {
2038            panic!("unexpected permission data type")
2039        }
2040    }
2041
2042    // A set of `nlmsg` extended permissions consisting of all 16-bit integers with one
2043    // of 3 (or more) consecutive prefix bytes is represented by 2 `AccessVectorRule`s in the
2044    // compiled policy, one for the smallest prefix byte and one for the largest.
2045    //
2046    // The policy compiler allows `nlmsg` extended permission sets of this form, but they
2047    // are not expected to appear in policies.
2048    #[test]
2049    fn parse_allowxperm_three_contiguous_nlmsg_ranges() {
2050        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
2051        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2052        let parsed_policy = &policy.0;
2053        parsed_policy.validate().expect("validate policy");
2054
2055        let class_id =
2056            find_class_by_name(parsed_policy.classes(), "class_three_contiguous_nlmsg_ranges")
2057                .expect("look up class_three_contiguous_nlmsg_ranges")
2058                .id();
2059
2060        let rules: Vec<_> = parsed_policy
2061            .access_vector_rules_for_test()
2062            .filter(|rule| rule.metadata.target_class() == class_id)
2063            .collect();
2064
2065        assert_eq!(rules.len(), 2);
2066        assert!(rules[0].metadata.is_allowxperm());
2067        if let Some(xperms) = rules[0].extended_permissions() {
2068            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2069            assert_eq!(xperms.xperms_optional_prefix, 0x02);
2070            assert_eq!(xperms.count(), 0x100);
2071            for i in 0x0200..0x02ff {
2072                assert!(xperms.contains(i), "{i}");
2073            }
2074        } else {
2075            panic!("unexpected permission data type")
2076        }
2077        if let Some(xperms) = rules[1].extended_permissions() {
2078            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2079            assert_eq!(xperms.xperms_optional_prefix, 0x00);
2080            assert_eq!(xperms.count(), 0x100);
2081            for i in 0x0..0xff {
2082                assert!(xperms.contains(i), "{i}");
2083            }
2084        } else {
2085            panic!("unexpected permission data type")
2086        }
2087    }
2088
2089    // The representation of extended permissions for `auditallowxperm` rules is
2090    // the same as for `allowxperm` rules.
2091    #[test]
2092    fn parse_auditallowxperm() {
2093        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
2094        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2095        let parsed_policy = &policy.0;
2096        parsed_policy.validate().expect("validate policy");
2097
2098        let class_id = find_class_by_name(parsed_policy.classes(), "class_auditallowxperm")
2099            .expect("look up class_auditallowxperm")
2100            .id();
2101
2102        let rules: Vec<_> = parsed_policy
2103            .access_vector_rules_for_test()
2104            .filter(|rule| rule.metadata.target_class() == class_id)
2105            .collect();
2106
2107        assert_eq!(rules.len(), 2);
2108        assert!(rules[0].metadata.is_auditallowxperm());
2109        if let Some(xperms) = rules[0].extended_permissions() {
2110            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2111            assert_eq!(xperms.xperms_optional_prefix, 0x00);
2112            assert_eq!(xperms.count(), 1);
2113            assert!(xperms.contains(0x10));
2114        } else {
2115            panic!("unexpected permission data type")
2116        }
2117        if let Some(xperms) = rules[1].extended_permissions() {
2118            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
2119            assert_eq!(xperms.xperms_optional_prefix, 0x10);
2120            assert_eq!(xperms.count(), 1);
2121            assert!(xperms.contains(0x1000));
2122        } else {
2123            panic!("unexpected permission data type")
2124        }
2125    }
2126
2127    // The representation of extended permissions for `dontauditxperm` rules is
2128    // the same as for `allowxperm` rules. In particular, the `AccessVectorRule`
2129    // contains the same set of extended permissions that appears in the text
2130    // policy. (This differs from the representation of the access vector in
2131    // `AccessVectorRule`s for `dontaudit` rules, where the `AccessVectorRule`
2132    // contains the complement of the access vector that appears in the text
2133    // policy.)
2134    #[test]
2135    fn parse_dontauditxperm() {
2136        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
2137        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2138        let parsed_policy = &policy.0;
2139        parsed_policy.validate().expect("validate policy");
2140
2141        let class_id = find_class_by_name(parsed_policy.classes(), "class_dontauditxperm")
2142            .expect("look up class_dontauditxperm")
2143            .id();
2144
2145        let rules: Vec<_> = parsed_policy
2146            .access_vector_rules_for_test()
2147            .filter(|rule| rule.metadata.target_class() == class_id)
2148            .collect();
2149
2150        assert_eq!(rules.len(), 2);
2151        assert!(rules[0].metadata.is_dontauditxperm());
2152        if let Some(xperms) = rules[0].extended_permissions() {
2153            assert_eq!(xperms.xperms_type, XPERMS_TYPE_NLMSG);
2154            assert_eq!(xperms.xperms_optional_prefix, 0x00);
2155            assert_eq!(xperms.count(), 1);
2156            assert!(xperms.contains(0x11));
2157        } else {
2158            panic!("unexpected permission data type")
2159        }
2160        if let Some(xperms) = rules[1].extended_permissions() {
2161            assert_eq!(xperms.xperms_type, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES);
2162            assert_eq!(xperms.xperms_optional_prefix, 0x10);
2163            assert_eq!(xperms.count(), 1);
2164            assert!(xperms.contains(0x1000));
2165        } else {
2166            panic!("unexpected permission data type")
2167        }
2168    }
2169
2170    // If an allowxperm rule and an auditallowxperm rule specify exactly the same permissions, they
2171    // are not coalesced into a single `AccessVectorRule` in the policy; two rules appear in the
2172    // policy.
2173    #[test]
2174    fn parse_auditallowxperm_not_coalesced() {
2175        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
2176        let policy = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
2177        let parsed_policy = &policy.0;
2178        parsed_policy.validate().expect("validate policy");
2179
2180        let class_id =
2181            find_class_by_name(parsed_policy.classes(), "class_auditallowxperm_not_coalesced")
2182                .expect("class_auditallowxperm_not_coalesced")
2183                .id();
2184
2185        let rules: Vec<_> = parsed_policy
2186            .access_vector_rules_for_test()
2187            .filter(|rule| rule.metadata.target_class() == class_id)
2188            .collect();
2189
2190        assert_eq!(rules.len(), 2);
2191        assert!(rules[0].metadata.is_allowxperm());
2192        assert!(!rules[0].metadata.is_auditallowxperm());
2193        if let Some(xperms) = rules[0].extended_permissions() {
2194            assert_eq!(xperms.count(), 1);
2195            assert!(xperms.contains(0xabcd));
2196        } else {
2197            panic!("unexpected permission data type")
2198        }
2199        assert!(!rules[1].metadata.is_allowxperm());
2200        assert!(rules[1].metadata.is_auditallowxperm());
2201        if let Some(xperms) = rules[1].extended_permissions() {
2202            assert_eq!(xperms.count(), 1);
2203            assert!(xperms.contains(0xabcd));
2204        } else {
2205            panic!("unexpected permission data type")
2206        }
2207    }
2208}