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