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