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