Skip to main content

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