selinux/policy/
mod.rs

1// Copyright 2023 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
5pub mod arrays;
6pub mod error;
7pub mod index;
8pub mod metadata;
9pub mod parsed_policy;
10pub mod parser;
11
12mod constraints;
13mod extensible_bitmap;
14mod security_context;
15mod symbols;
16
17pub use arrays::{FsUseType, XpermsBitmap};
18pub use index::FsUseLabelAndType;
19pub use security_context::{SecurityContext, SecurityContextError};
20
21use crate as sc;
22use anyhow::Context as _;
23use error::ParseError;
24use index::PolicyIndex;
25use metadata::HandleUnknown;
26use parsed_policy::ParsedPolicy;
27use parser::{ByRef, ByValue, ParseStrategy};
28use std::fmt::{Debug, Display, LowerHex};
29use std::marker::PhantomData;
30use std::num::{NonZeroU32, NonZeroU64};
31use std::ops::Deref;
32use std::str::FromStr;
33use symbols::{find_class_by_name, find_common_symbol_by_name_bytes};
34use zerocopy::{
35    little_endian as le, FromBytes, Immutable, KnownLayout, Ref, SplitByteSlice, Unaligned,
36};
37
38/// Maximum SELinux policy version supported by this implementation.
39pub const SUPPORTED_POLICY_VERSION: u32 = 33;
40
41/// Identifies a user within a policy.
42#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
43pub struct UserId(NonZeroU32);
44
45/// Identifies a role within a policy.
46#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
47pub struct RoleId(NonZeroU32);
48
49/// Identifies a type within a policy.
50#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
51pub struct TypeId(NonZeroU32);
52
53/// Identifies a sensitivity level within a policy.
54#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
55pub struct SensitivityId(NonZeroU32);
56
57/// Identifies a security category within a policy.
58#[derive(Copy, Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
59pub struct CategoryId(NonZeroU32);
60
61/// Identifies a class within a policy. Note that `ClassId`s may be created for arbitrary Ids
62/// supplied by userspace, so implementation should never assume that a `ClassId` must be valid.
63#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
64pub struct ClassId(NonZeroU32);
65
66impl ClassId {
67    /// Returns a `ClassId` with the specified `id`.
68    pub fn new(id: NonZeroU32) -> Self {
69        Self(id)
70    }
71}
72
73impl Into<u32> for ClassId {
74    fn into(self) -> u32 {
75        self.0.into()
76    }
77}
78
79/// Identifies a permission within a class.
80#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
81pub struct ClassPermissionId(NonZeroU32);
82
83impl Display for ClassPermissionId {
84    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        write!(f, "{}", self.0)
86    }
87}
88
89/// Encapsulates the result of a permissions calculation, between
90/// source & target domains, for a specific class. Decisions describe
91/// which permissions are allowed, and whether permissions should be
92/// audit-logged when allowed, and when denied.
93#[derive(Debug, Clone, PartialEq)]
94pub struct AccessDecision {
95    pub allow: AccessVector,
96    pub auditallow: AccessVector,
97    pub auditdeny: AccessVector,
98    pub flags: u32,
99
100    /// If this field is set then denials should be audit-logged with "todo_deny" as the reason, with
101    /// the `bug` number included in the audit message.
102    pub todo_bug: Option<NonZeroU64>,
103}
104
105impl Default for AccessDecision {
106    fn default() -> Self {
107        Self::allow(AccessVector::NONE)
108    }
109}
110
111impl AccessDecision {
112    /// Returns an [`AccessDecision`] with the specified permissions to `allow`, and default audit
113    /// behaviour.
114    pub(super) const fn allow(allow: AccessVector) -> Self {
115        Self {
116            allow,
117            auditallow: AccessVector::NONE,
118            auditdeny: AccessVector::ALL,
119            flags: 0,
120            todo_bug: None,
121        }
122    }
123}
124
125/// [`AccessDecision::flags`] value indicating that the policy marks the source domain permissive.
126pub(super) const SELINUX_AVD_FLAGS_PERMISSIVE: u32 = 1;
127
128/// The set of permissions that may be granted to sources accessing targets of a particular class,
129/// as defined in an SELinux policy.
130#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
131pub struct AccessVector(u32);
132
133impl AccessVector {
134    pub const NONE: AccessVector = AccessVector(0);
135    pub const ALL: AccessVector = AccessVector(std::u32::MAX);
136
137    pub(super) fn from_class_permission_id(id: ClassPermissionId) -> Self {
138        Self((1 as u32) << (id.0.get() - 1))
139    }
140}
141
142impl FromStr for AccessVector {
143    type Err = <u32 as FromStr>::Err;
144
145    fn from_str(value: &str) -> Result<Self, Self::Err> {
146        // Access Vector values are always serialized to/from hexadecimal.
147        Ok(AccessVector(u32::from_str_radix(value, 16)?))
148    }
149}
150
151impl LowerHex for AccessVector {
152    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153        LowerHex::fmt(&self.0, f)
154    }
155}
156
157impl std::ops::BitAnd for AccessVector {
158    type Output = Self;
159
160    fn bitand(self, rhs: Self) -> Self::Output {
161        AccessVector(self.0 & rhs.0)
162    }
163}
164
165impl std::ops::BitOr for AccessVector {
166    type Output = Self;
167
168    fn bitor(self, rhs: Self) -> Self::Output {
169        AccessVector(self.0 | rhs.0)
170    }
171}
172
173impl std::ops::BitAndAssign for AccessVector {
174    fn bitand_assign(&mut self, rhs: Self) {
175        self.0 &= rhs.0
176    }
177}
178
179impl std::ops::BitOrAssign for AccessVector {
180    fn bitor_assign(&mut self, rhs: Self) {
181        self.0 |= rhs.0
182    }
183}
184
185impl std::ops::SubAssign for AccessVector {
186    fn sub_assign(&mut self, rhs: Self) {
187        self.0 = self.0 ^ (self.0 & rhs.0);
188    }
189}
190
191impl std::ops::Sub for AccessVector {
192    type Output = Self;
193
194    fn sub(self, rhs: Self) -> Self::Output {
195        AccessVector(self.0 ^ (self.0 & rhs.0))
196    }
197}
198
199/// Encapsulates the result of an ioctl extended permissions calculation, between source & target
200/// domains, for a specific class, and for a specific ioctl prefix byte. Decisions describe which
201/// 16-bit ioctls are allowed, and whether ioctl permissions should be audit-logged when allowed,
202/// and when denied.
203///
204/// In the language of
205/// https://www.kernel.org/doc/html/latest/userspace-api/ioctl/ioctl-decoding.html, an
206/// `IoctlAccessDecision` provides allow, audit-allow, and audit-deny decisions for the 256 possible
207/// function codes for a particular driver code.
208#[derive(Debug, Clone, PartialEq)]
209pub struct IoctlAccessDecision {
210    pub allow: XpermsBitmap,
211    pub auditallow: XpermsBitmap,
212    pub auditdeny: XpermsBitmap,
213}
214
215impl IoctlAccessDecision {
216    pub const DENY_ALL: Self = Self {
217        allow: XpermsBitmap::NONE,
218        auditallow: XpermsBitmap::NONE,
219        auditdeny: XpermsBitmap::ALL,
220    };
221    pub const ALLOW_ALL: Self = Self {
222        allow: XpermsBitmap::ALL,
223        auditallow: XpermsBitmap::NONE,
224        auditdeny: XpermsBitmap::ALL,
225    };
226}
227
228/// Parses `binary_policy` by value; that is, copies underlying binary data out in addition to
229/// building up parser output structures. This function returns
230/// `(unvalidated_parser_output, binary_policy)` on success, or an error if parsing failed. Note
231/// that the second component of the success case contains precisely the same bytes as the input.
232/// This function depends on a uniformity of interface between the "by value" and "by reference"
233/// strategies, but also requires an `unvalidated_parser_output` type that is independent of the
234/// `binary_policy` lifetime. Taken together, these requirements demand the "move-in + move-out"
235/// interface for `binary_policy`.
236///
237/// If the caller does not need access to the binary policy when parsing fails, but does need to
238/// retain both the parsed output and the binary policy when parsing succeeds, the code will look
239/// something like:
240///
241/// ```rust,ignore
242/// let (unvalidated_policy, binary_policy) = parse_policy_by_value(binary_policy)?;
243/// ```
244///
245/// If the caller does need access to the binary policy when parsing fails and needs to retain both
246/// parsed output and the binary policy when parsing succeeds, the code will look something like:
247///
248/// ```rust,ignore
249/// let (unvalidated_policy, _) = parse_policy_by_value(binary_policy.clone())?;
250/// ```
251///
252/// If the caller does not need to retain both the parsed output and the binary policy, then
253/// [`parse_policy_by_reference`] should be used instead.
254pub fn parse_policy_by_value(
255    binary_policy: Vec<u8>,
256) -> Result<(Unvalidated<ByValue<Vec<u8>>>, Vec<u8>), anyhow::Error> {
257    let (parsed_policy, binary_policy) =
258        ParsedPolicy::parse(ByValue::new(binary_policy)).context("parsing policy")?;
259    Ok((Unvalidated(parsed_policy), binary_policy))
260}
261
262/// Parses `binary_policy` by reference; that is, constructs parser output structures that contain
263/// _references_ to data in `binary_policy`. This function returns `unvalidated_parser_output` on
264/// success, or an error if parsing failed.
265///
266/// If the caller does needs to retain both the parsed output and the binary policy, then
267/// [`parse_policy_by_value`] should be used instead.
268pub fn parse_policy_by_reference<'a>(
269    binary_policy: &'a [u8],
270) -> Result<Unvalidated<ByRef<&'a [u8]>>, anyhow::Error> {
271    let (parsed_policy, _) =
272        ParsedPolicy::parse(ByRef::new(binary_policy)).context("parsing policy")?;
273    Ok(Unvalidated(parsed_policy))
274}
275
276/// Information on a Class. This struct is used for sharing Class information outside this crate.
277pub struct ClassInfo<'a> {
278    /// The name of the class.
279    pub class_name: &'a [u8],
280    /// The class identifier.
281    pub class_id: ClassId,
282}
283
284#[derive(Debug)]
285pub struct Policy<PS: ParseStrategy>(PolicyIndex<PS>);
286
287impl<PS: ParseStrategy> Policy<PS> {
288    /// The policy version stored in the underlying binary policy.
289    pub fn policy_version(&self) -> u32 {
290        self.0.parsed_policy().policy_version()
291    }
292
293    /// The way "unknown" policy decisions should be handed according to the underlying binary
294    /// policy.
295    pub fn handle_unknown(&self) -> HandleUnknown {
296        self.0.parsed_policy().handle_unknown()
297    }
298
299    pub fn conditional_booleans<'a>(&'a self) -> Vec<(&'a [u8], bool)> {
300        self.0
301            .parsed_policy()
302            .conditional_booleans()
303            .iter()
304            .map(|boolean| (PS::deref_slice(&boolean.data), PS::deref(&boolean.metadata).active()))
305            .collect()
306    }
307
308    /// The set of class names and their respective class identifiers.
309    pub fn classes<'a>(&'a self) -> Vec<ClassInfo<'a>> {
310        self.0
311            .parsed_policy()
312            .classes()
313            .iter()
314            .map(|class| ClassInfo { class_name: class.name_bytes(), class_id: class.id() })
315            .collect()
316    }
317
318    /// Returns the parsed `Type` corresponding to the specified `name` (including aliases).
319    pub(super) fn type_id_by_name(&self, name: &str) -> Option<TypeId> {
320        self.0.parsed_policy().type_by_name(name).map(|x| x.id())
321    }
322
323    /// Returns the set of permissions for the given class, including both the
324    /// explicitly owned permissions and the inherited ones from common symbols.
325    /// Each permission is a tuple of the permission identifier (in the scope of
326    /// the given class) and the permission name.
327    pub fn find_class_permissions_by_name(
328        &self,
329        class_name: &str,
330    ) -> Result<Vec<(ClassPermissionId, Vec<u8>)>, ()> {
331        let class = find_class_by_name(self.0.parsed_policy().classes(), class_name).ok_or(())?;
332        let owned_permissions = class.permissions();
333
334        let mut result: Vec<_> = owned_permissions
335            .iter()
336            .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
337            .collect();
338
339        // common_name_bytes() is empty when the class doesn't inherit from a CommonSymbol.
340        if class.common_name_bytes().is_empty() {
341            return Ok(result);
342        }
343
344        let common_symbol_permissions = find_common_symbol_by_name_bytes(
345            self.0.parsed_policy().common_symbols(),
346            class.common_name_bytes(),
347        )
348        .ok_or(())?
349        .permissions();
350
351        result.append(
352            &mut common_symbol_permissions
353                .iter()
354                .map(|permission| (permission.id(), permission.name_bytes().to_vec()))
355                .collect(),
356        );
357
358        Ok(result)
359    }
360
361    /// If there is an fs_use statement for the given filesystem type, returns the associated
362    /// [`SecurityContext`] and [`FsUseType`].
363    pub fn fs_use_label_and_type(
364        &self,
365        fs_type: sc::NullessByteStr<'_>,
366    ) -> Option<FsUseLabelAndType> {
367        self.0.fs_use_label_and_type(fs_type)
368    }
369
370    /// If there is a genfscon statement for the given filesystem type, returns the associated
371    /// [`SecurityContext`].
372    pub fn genfscon_label_for_fs_and_path(
373        &self,
374        fs_type: sc::NullessByteStr<'_>,
375        node_path: sc::NullessByteStr<'_>,
376        class_id: Option<ClassId>,
377    ) -> Option<SecurityContext> {
378        self.0.genfscon_label_for_fs_and_path(fs_type, node_path, class_id)
379    }
380
381    /// Returns the [`SecurityContext`] defined by this policy for the specified
382    /// well-known (or "initial") Id.
383    pub fn initial_context(&self, id: sc::InitialSid) -> security_context::SecurityContext {
384        self.0.initial_context(id)
385    }
386
387    /// Returns a [`SecurityContext`] with fields parsed from the supplied Security Context string.
388    pub fn parse_security_context(
389        &self,
390        security_context: sc::NullessByteStr<'_>,
391    ) -> Result<security_context::SecurityContext, security_context::SecurityContextError> {
392        security_context::SecurityContext::parse(&self.0, security_context)
393    }
394
395    /// Validates a [`SecurityContext`] against this policy's constraints.
396    pub fn validate_security_context(
397        &self,
398        security_context: &SecurityContext,
399    ) -> Result<(), SecurityContextError> {
400        security_context.validate(&self.0)
401    }
402
403    /// Returns a byte string describing the supplied [`SecurityContext`].
404    pub fn serialize_security_context(&self, security_context: &SecurityContext) -> Vec<u8> {
405        security_context.serialize(&self.0)
406    }
407
408    /// Returns the security context that should be applied to a newly created SELinux
409    /// object according to `source` and `target` security contexts, as well as the new object's
410    /// `class`.
411    ///
412    /// If no filename-transition rule matches the supplied arguments then
413    /// `None` is returned, and the caller should fall-back to filename-independent labeling
414    /// via [`compute_create_context()`]
415    pub fn compute_create_context_with_name(
416        &self,
417        source: &SecurityContext,
418        target: &SecurityContext,
419        class: impl Into<sc::ObjectClass>,
420        name: sc::NullessByteStr<'_>,
421    ) -> Option<SecurityContext> {
422        self.0.compute_create_context_with_name(source, target, class.into(), name)
423    }
424
425    /// Returns the security context that should be applied to a newly created SELinux
426    /// object according to `source` and `target` security contexts, as well as the new object's
427    /// `class`.
428    ///
429    /// Computation follows the "create" algorithm for labeling newly created objects:
430    /// - user is taken from the `source` by default, or `target` if specified by policy.
431    /// - role, type and range are taken from the matching transition rules, if any.
432    /// - role, type and range fall-back to the `source` or `target` values according to policy.
433    ///
434    /// If no transitions apply, and the policy does not explicitly specify defaults then the
435    /// role, type and range values have defaults chosen based on the `class`:
436    /// - For "process", and socket-like classes, role, type and range are taken from the `source`.
437    /// - Otherwise role is "object_r", type is taken from `target` and range is set to the
438    ///   low level of the `source` range.
439    ///
440    /// Returns an error if the Security Context for such an object is not valid under this
441    /// [`Policy`] (e.g. if the type is not permitted for the chosen role, etc).
442    pub fn compute_create_context(
443        &self,
444        source: &SecurityContext,
445        target: &SecurityContext,
446        class: impl Into<sc::ObjectClass>,
447    ) -> SecurityContext {
448        self.0.compute_create_context(source, target, class.into())
449    }
450
451    /// Computes the access vector that associates type `source_type_name` and
452    /// `target_type_name` via an explicit `allow [...];` statement in the
453    /// binary policy, subject to any matching constraint statements. Computes
454    /// `AccessVector::NONE` if no such statement exists.
455    ///
456    /// Access decisions are currently based on explicit "allow" rules and
457    /// "constrain" or "mlsconstrain" statements. A permission is allowed if
458    /// it is allowed by an explicit "allow", and if in addition, all matching
459    /// constraints are satisfied.
460    //
461    // TODO: https://fxbug.dev/372400976 - Check that this is actually the
462    // correct interaction between constraints and explicit "allow" rules.
463    //
464    // TODO: https://fxbug.dev/372400419 - Validate that "neverallow" rules
465    // don't need any deliberate handling here.
466    pub fn compute_access_decision(
467        &self,
468        source_context: &SecurityContext,
469        target_context: &SecurityContext,
470        object_class: impl Into<sc::ObjectClass>,
471    ) -> AccessDecision {
472        if let Some(target_class) = self.0.class(object_class.into()) {
473            self.0.parsed_policy().compute_access_decision(
474                source_context,
475                target_context,
476                target_class,
477            )
478        } else {
479            AccessDecision::allow(AccessVector::NONE)
480        }
481    }
482
483    /// Computes the ioctl extended permissions that should be allowed, audited when allowed, and
484    /// audited when denied, for a given source context, target context, target class, and ioctl
485    /// prefix byte.
486    pub fn compute_ioctl_access_decision(
487        &self,
488        source_context: &SecurityContext,
489        target_context: &SecurityContext,
490        object_class: impl Into<sc::ObjectClass>,
491        ioctl_prefix: u8,
492    ) -> IoctlAccessDecision {
493        if let Some(target_class) = self.0.class(object_class.into()) {
494            self.0.parsed_policy().compute_ioctl_access_decision(
495                source_context,
496                target_context,
497                target_class,
498                ioctl_prefix,
499            )
500        } else {
501            IoctlAccessDecision::DENY_ALL
502        }
503    }
504
505    pub fn is_bounded_by(&self, bounded_type: TypeId, parent_type: TypeId) -> bool {
506        let type_ = self.0.parsed_policy().type_(bounded_type);
507        type_.bounded_by() == Some(parent_type)
508    }
509
510    /// Returns true if the policy has the marked the type/domain for permissive checks.
511    pub fn is_permissive(&self, type_: TypeId) -> bool {
512        self.0.parsed_policy().permissive_types().is_set(type_.0.get())
513    }
514}
515
516impl<PS: ParseStrategy> AccessVectorComputer for Policy<PS> {
517    fn access_vector_from_permissions<
518        P: sc::ClassPermission + Into<sc::KernelPermission> + Clone + 'static,
519    >(
520        &self,
521        permissions: &[P],
522    ) -> Option<AccessVector> {
523        let mut access_vector = AccessVector::NONE;
524        for permission in permissions {
525            if let Some(permission_info) = self.0.permission(&permission.clone().into()) {
526                // Compute bit flag associated with permission.
527                access_vector |= AccessVector::from_class_permission_id(permission_info.id());
528            } else {
529                // The permission is unknown so defer to the policy-define unknown handling behaviour.
530                if self.0.parsed_policy().handle_unknown() != HandleUnknown::Allow {
531                    return None;
532                }
533            }
534        }
535        Some(access_vector)
536    }
537}
538
539impl<PS: ParseStrategy> Validate for Policy<PS> {
540    type Error = anyhow::Error;
541
542    fn validate(&self) -> Result<(), Self::Error> {
543        self.0.parsed_policy().validate()
544    }
545}
546
547/// A [`Policy`] that has been successfully parsed, but not validated.
548pub struct Unvalidated<PS: ParseStrategy>(ParsedPolicy<PS>);
549
550impl<PS: ParseStrategy> Unvalidated<PS> {
551    pub fn validate(self) -> Result<Policy<PS>, anyhow::Error> {
552        Validate::validate(&self.0).context("validating parsed policy")?;
553        let index = PolicyIndex::new(self.0).context("building index")?;
554        Ok(Policy(index))
555    }
556}
557
558/// An owner of policy information that can translate [`sc::Permission`] values into
559/// [`AccessVector`] values that are consistent with the owned policy.
560pub trait AccessVectorComputer {
561    /// Returns an [`AccessVector`] containing the supplied kernel `permissions`.
562    ///
563    /// The loaded policy's "handle unknown" configuration determines how `permissions`
564    /// entries not explicitly defined by the policy are handled. Allow-unknown will
565    /// result in unknown `permissions` being ignored, while deny-unknown will cause
566    /// `None` to be returned if one or more `permissions` are unknown.
567    fn access_vector_from_permissions<
568        P: sc::ClassPermission + Into<sc::KernelPermission> + Clone + 'static,
569    >(
570        &self,
571        permissions: &[P],
572    ) -> Option<AccessVector>;
573}
574
575/// A data structure that can be parsed as a part of a binary policy.
576pub trait Parse<PS: ParseStrategy>: Sized {
577    /// The type of error that may be returned from `parse()`, usually [`ParseError`] or
578    /// [`anyhow::Error`].
579    type Error: Into<anyhow::Error>;
580
581    /// Parses a `Self` from `bytes`, returning the `Self` and trailing bytes, or an error if
582    /// bytes corresponding to a `Self` are malformed.
583    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error>;
584}
585
586/// Parse a data as a slice of inner data structures from a prefix of a [`ByteSlice`].
587pub(super) trait ParseSlice<PS: ParseStrategy>: Sized {
588    /// The type of error that may be returned from `parse()`, usually [`ParseError`] or
589    /// [`anyhow::Error`].
590    type Error: Into<anyhow::Error>;
591
592    /// Parses a `Self` as `count` of internal itemsfrom `bytes`, returning the `Self` and trailing
593    /// bytes, or an error if bytes corresponding to a `Self` are malformed.
594    fn parse_slice(bytes: PS, count: usize) -> Result<(Self, PS), Self::Error>;
595}
596
597/// Validate a parsed data structure.
598pub(super) trait Validate {
599    /// The type of error that may be returned from `validate()`, usually [`ParseError`] or
600    /// [`anyhow::Error`].
601    type Error: Into<anyhow::Error>;
602
603    /// Validates a `Self`, returning a `Self::Error` if `self` is internally inconsistent.
604    fn validate(&self) -> Result<(), Self::Error>;
605}
606
607pub(super) trait ValidateArray<M, D> {
608    /// The type of error that may be returned from `validate()`, usually [`ParseError`] or
609    /// [`anyhow::Error`].
610    type Error: Into<anyhow::Error>;
611
612    /// Validates a `Self`, returning a `Self::Error` if `self` is internally inconsistent.
613    fn validate_array<'a>(metadata: &'a M, data: &'a [D]) -> Result<(), Self::Error>;
614}
615
616/// Treat a type as metadata that contains a count of subsequent data.
617pub(super) trait Counted {
618    /// Returns the count of subsequent data items.
619    fn count(&self) -> u32;
620}
621
622impl<T: Validate> Validate for Option<T> {
623    type Error = <T as Validate>::Error;
624
625    fn validate(&self) -> Result<(), Self::Error> {
626        match self {
627            Some(value) => value.validate(),
628            None => Ok(()),
629        }
630    }
631}
632
633impl Validate for le::U32 {
634    type Error = anyhow::Error;
635
636    /// Using a raw `le::U32` implies no additional constraints on its value. To operate with
637    /// constraints, define a `struct T(le::U32);` and `impl Validate for T { ... }`.
638    fn validate(&self) -> Result<(), Self::Error> {
639        Ok(())
640    }
641}
642
643impl Validate for u8 {
644    type Error = anyhow::Error;
645
646    /// Using a raw `u8` implies no additional constraints on its value. To operate with
647    /// constraints, define a `struct T(u8);` and `impl Validate for T { ... }`.
648    fn validate(&self) -> Result<(), Self::Error> {
649        Ok(())
650    }
651}
652
653impl Validate for [u8] {
654    type Error = anyhow::Error;
655
656    /// Using a raw `[u8]` implies no additional constraints on its value. To operate with
657    /// constraints, define a `struct T([u8]);` and `impl Validate for T { ... }`.
658    fn validate(&self) -> Result<(), Self::Error> {
659        Ok(())
660    }
661}
662
663impl<B: SplitByteSlice, T: Validate + FromBytes + KnownLayout + Immutable> Validate for Ref<B, T> {
664    type Error = <T as Validate>::Error;
665
666    fn validate(&self) -> Result<(), Self::Error> {
667        self.deref().validate()
668    }
669}
670
671impl<B: SplitByteSlice, T: Counted + FromBytes + KnownLayout + Immutable> Counted for Ref<B, T> {
672    fn count(&self) -> u32 {
673        self.deref().count()
674    }
675}
676
677/// A length-encoded array that contains metadata in `M` and a slice of data items internally
678/// managed by `D`.
679#[derive(Clone, Debug, PartialEq)]
680struct Array<PS, M, D> {
681    metadata: M,
682    data: D,
683    _marker: PhantomData<PS>,
684}
685
686impl<PS: ParseStrategy, M: Counted + Parse<PS>, D: ParseSlice<PS>> Parse<PS> for Array<PS, M, D> {
687    /// [`Array`] abstracts over two types (`M` and `D`) that may have different [`Parse::Error`]
688    /// types. Unify error return type via [`anyhow::Error`].
689    type Error = anyhow::Error;
690
691    /// Parses [`Array`] by parsing *and validating* `metadata`, `data`, and `self`.
692    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
693        let tail = bytes;
694
695        let (metadata, tail) = M::parse(tail).map_err(Into::<anyhow::Error>::into)?;
696
697        let (data, tail) =
698            D::parse_slice(tail, metadata.count() as usize).map_err(Into::<anyhow::Error>::into)?;
699
700        let array = Self { metadata, data, _marker: PhantomData };
701
702        Ok((array, tail))
703    }
704}
705
706impl<
707        T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned,
708        PS: ParseStrategy<Output<T> = T>,
709    > Parse<PS> for T
710{
711    type Error = anyhow::Error;
712
713    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
714        let num_bytes = bytes.len();
715        let (data, tail) = PS::parse::<T>(bytes).ok_or_else(|| ParseError::MissingData {
716            type_name: std::any::type_name::<T>(),
717            type_size: std::mem::size_of::<T>(),
718            num_bytes,
719        })?;
720
721        Ok((data, tail))
722    }
723}
724
725/// Defines a at type that wraps an [`Array`], implementing `Deref`-as-`Array` and [`Parse`]. This
726/// macro should be used in contexts where using a general [`Array`] implementation may introduce
727/// conflicting implementations on account of general [`Array`] type parameters.
728macro_rules! array_type {
729    ($type_name:ident, $parse_strategy:ident, $metadata_type:ty, $data_type:ty, $metadata_type_name:expr, $data_type_name:expr) => {
730        #[doc = "An [`Array`] with [`"]
731        #[doc = $metadata_type_name]
732        #[doc = "`] metadata and [`"]
733        #[doc = $data_type_name]
734        #[doc = "`] data items."]
735        #[derive(Debug, PartialEq)]
736        pub(super) struct $type_name<$parse_strategy: crate::policy::parser::ParseStrategy>(
737            crate::policy::Array<PS, $metadata_type, $data_type>,
738        );
739
740        impl<PS: crate::policy::parser::ParseStrategy> std::ops::Deref for $type_name<PS> {
741            type Target = crate::policy::Array<PS, $metadata_type, $data_type>;
742
743            fn deref(&self) -> &Self::Target {
744                &self.0
745            }
746        }
747
748        impl<PS: crate::policy::parser::ParseStrategy> crate::policy::Parse<PS> for $type_name<PS>
749        where
750            crate::policy::Array<PS, $metadata_type, $data_type>: crate::policy::Parse<PS>,
751        {
752            type Error = <Array<PS, $metadata_type, $data_type> as crate::policy::Parse<PS>>::Error;
753
754            fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
755                let (array, tail) = Array::<PS, $metadata_type, $data_type>::parse(bytes)?;
756                Ok((Self(array), tail))
757            }
758        }
759    };
760
761    ($type_name:ident, $parse_strategy:ident, $metadata_type:ty, $data_type:ty) => {
762        array_type!(
763            $type_name,
764            $parse_strategy,
765            $metadata_type,
766            $data_type,
767            stringify!($metadata_type),
768            stringify!($data_type)
769        );
770    };
771}
772
773pub(super) use array_type;
774
775macro_rules! array_type_validate_deref_both {
776    ($type_name:ident) => {
777        impl<PS: crate::policy::parser::ParseStrategy> Validate for $type_name<PS> {
778            type Error = anyhow::Error;
779
780            fn validate(&self) -> Result<(), Self::Error> {
781                let metadata = PS::deref(&self.metadata);
782                metadata.validate()?;
783
784                let data = PS::deref_slice(&self.data);
785                data.validate()?;
786
787                Self::validate_array(metadata, data).map_err(Into::<anyhow::Error>::into)
788            }
789        }
790    };
791}
792
793pub(super) use array_type_validate_deref_both;
794
795macro_rules! array_type_validate_deref_data {
796    ($type_name:ident) => {
797        impl<PS: crate::policy::parser::ParseStrategy> Validate for $type_name<PS> {
798            type Error = anyhow::Error;
799
800            fn validate(&self) -> Result<(), Self::Error> {
801                let metadata = &self.metadata;
802                metadata.validate()?;
803
804                let data = PS::deref_slice(&self.data);
805                data.validate()?;
806
807                Self::validate_array(metadata, data)
808            }
809        }
810    };
811}
812
813pub(super) use array_type_validate_deref_data;
814
815macro_rules! array_type_validate_deref_metadata_data_vec {
816    ($type_name:ident) => {
817        impl<PS: crate::policy::parser::ParseStrategy> Validate for $type_name<PS> {
818            type Error = anyhow::Error;
819
820            fn validate(&self) -> Result<(), Self::Error> {
821                let metadata = PS::deref(&self.metadata);
822                metadata.validate()?;
823
824                let data = &self.data;
825                data.validate()?;
826
827                Self::validate_array(metadata, data.as_slice())
828            }
829        }
830    };
831}
832
833pub(super) use array_type_validate_deref_metadata_data_vec;
834
835macro_rules! array_type_validate_deref_none_data_vec {
836    ($type_name:ident) => {
837        impl<PS: crate::policy::parser::ParseStrategy> Validate for $type_name<PS> {
838            type Error = anyhow::Error;
839
840            fn validate(&self) -> Result<(), Self::Error> {
841                let metadata = &self.metadata;
842                metadata.validate()?;
843
844                let data = &self.data;
845                data.validate()?;
846
847                Self::validate_array(metadata, data.as_slice())
848            }
849        }
850    };
851}
852
853pub(super) use array_type_validate_deref_none_data_vec;
854
855impl<
856        B: Debug + SplitByteSlice + PartialEq,
857        T: Clone + Debug + FromBytes + KnownLayout + Immutable + PartialEq + Unaligned,
858    > Parse<ByRef<B>> for Ref<B, T>
859{
860    type Error = anyhow::Error;
861
862    fn parse(bytes: ByRef<B>) -> Result<(Self, ByRef<B>), Self::Error> {
863        let num_bytes = bytes.len();
864        let (data, tail) =
865            ByRef::<B>::parse::<T>(bytes).ok_or_else(|| ParseError::MissingData {
866                type_name: std::any::type_name::<T>(),
867                type_size: std::mem::size_of::<T>(),
868                num_bytes,
869            })?;
870
871        Ok((data, tail))
872    }
873}
874
875impl<
876        B: Debug + SplitByteSlice + PartialEq,
877        T: Clone + Debug + FromBytes + Immutable + PartialEq + Unaligned,
878    > ParseSlice<ByRef<B>> for Ref<B, [T]>
879{
880    /// [`Ref`] may return a [`ParseError`] internally, or `<T as Parse>::Error`. Unify error return
881    /// type via [`anyhow::Error`].
882    type Error = anyhow::Error;
883
884    /// Parses [`Ref`] by consuming it as an unaligned prefix as a slice, then validating the slice
885    /// via `Ref::deref`.
886    fn parse_slice(bytes: ByRef<B>, count: usize) -> Result<(Self, ByRef<B>), Self::Error> {
887        let num_bytes = bytes.len();
888        let (data, tail) = ByRef::<B>::parse_slice::<T>(bytes, count).ok_or_else(|| {
889            ParseError::MissingSliceData {
890                type_name: std::any::type_name::<T>(),
891                type_size: std::mem::size_of::<T>(),
892                num_items: count,
893                num_bytes,
894            }
895        })?;
896
897        Ok((data, tail))
898    }
899}
900
901impl<PS: ParseStrategy, T: Parse<PS>> ParseSlice<PS> for Vec<T> {
902    /// `Vec<T>` may return a [`ParseError`] internally, or `<T as Parse>::Error`. Unify error
903    /// return type via [`anyhow::Error`].
904    type Error = anyhow::Error;
905
906    /// Parses `Vec<T>` by parsing individual `T` instances, then validating them.
907    fn parse_slice(bytes: PS, count: usize) -> Result<(Self, PS), Self::Error> {
908        let mut slice = Vec::with_capacity(count);
909        let mut tail = bytes;
910
911        for _ in 0..count {
912            let (item, next_tail) = T::parse(tail).map_err(Into::<anyhow::Error>::into)?;
913            slice.push(item);
914            tail = next_tail;
915        }
916
917        Ok((slice, tail))
918    }
919}
920
921#[cfg(test)]
922pub(super) mod testing {
923    use crate::policy::error::ValidateError;
924    use crate::policy::{AccessVector, ParseError};
925
926    pub const ACCESS_VECTOR_0001: AccessVector = AccessVector(0b0001u32);
927    pub const ACCESS_VECTOR_0010: AccessVector = AccessVector(0b0010u32);
928
929    /// Downcasts an [`anyhow::Error`] to a [`ParseError`] for structured error comparison in tests.
930    pub(super) fn as_parse_error(error: anyhow::Error) -> ParseError {
931        error.downcast::<ParseError>().expect("parse error")
932    }
933
934    /// Downcasts an [`anyhow::Error`] to a [`ParseError`] for structured error comparison in tests.
935    pub(super) fn as_validate_error(error: anyhow::Error) -> ValidateError {
936        error.downcast::<ValidateError>().expect("validate error")
937    }
938}
939
940#[cfg(test)]
941pub(super) mod tests {
942    use super::*;
943
944    use crate::policy::metadata::HandleUnknown;
945    use crate::policy::{parse_policy_by_reference, parse_policy_by_value, SecurityContext};
946    use crate::{FileClass, InitialSid, KernelClass};
947
948    use serde::Deserialize;
949    use std::ops::Shl;
950
951    /// Returns whether the input types are explicitly granted `permission` via an `allow [...];`
952    /// policy statement.
953    ///
954    /// # Panics
955    /// If supplied with type Ids not previously obtained from the `Policy` itself; validation
956    /// ensures that all such Ids have corresponding definitions.
957    /// If either of `target_class` or `permission` cannot be resolved in the policy.
958    fn is_explicitly_allowed<PS: ParseStrategy>(
959        policy: &Policy<PS>,
960        source_type: TypeId,
961        target_type: TypeId,
962        target_class: &str,
963        permission: &str,
964    ) -> bool {
965        let class = policy
966            .0
967            .parsed_policy()
968            .classes()
969            .iter()
970            .find(|class| class.name_bytes() == target_class.as_bytes())
971            .expect("class not found");
972        let class_permissions = policy
973            .find_class_permissions_by_name(target_class)
974            .expect("class permissions not found");
975        let (permission_id, _) = class_permissions
976            .iter()
977            .find(|(_, name)| permission.as_bytes() == name)
978            .expect("permission not found");
979        let permission_bit = AccessVector::from_class_permission_id(*permission_id);
980        let access_decision =
981            policy.0.parsed_policy().compute_explicitly_allowed(source_type, target_type, class);
982        permission_bit == access_decision.allow & permission_bit
983    }
984
985    #[derive(Debug, Deserialize)]
986    struct Expectations {
987        expected_policy_version: u32,
988        expected_handle_unknown: LocalHandleUnknown,
989    }
990
991    #[derive(Debug, Deserialize, PartialEq)]
992    #[serde(rename_all = "snake_case")]
993    enum LocalHandleUnknown {
994        Deny,
995        Reject,
996        Allow,
997    }
998
999    impl PartialEq<HandleUnknown> for LocalHandleUnknown {
1000        fn eq(&self, other: &HandleUnknown) -> bool {
1001            match self {
1002                LocalHandleUnknown::Deny => *other == HandleUnknown::Deny,
1003                LocalHandleUnknown::Reject => *other == HandleUnknown::Reject,
1004                LocalHandleUnknown::Allow => *other == HandleUnknown::Allow,
1005            }
1006        }
1007    }
1008
1009    /// Given a vector of integer (u8) values, returns a bitmap in which the set bits correspond to
1010    /// the indices of the provided values.
1011    fn xperms_bitmap_from_elements(elements: &[u8]) -> XpermsBitmap {
1012        let mut bitmap = [le::U32::ZERO; 8];
1013        for element in elements.iter() {
1014            let block_index = (*element as usize) / 32;
1015            let bit_index = ((*element as usize) % 32) as u32;
1016            let bitmask = le::U32::new(1).shl(bit_index);
1017            bitmap[block_index] = bitmap[block_index] | bitmask;
1018        }
1019        XpermsBitmap::new(bitmap)
1020    }
1021
1022    #[test]
1023    fn known_policies() {
1024        let policies_and_expectations = [
1025            [
1026                b"testdata/policies/emulator".to_vec(),
1027                include_bytes!("../../testdata/policies/emulator").to_vec(),
1028                include_bytes!("../../testdata/expectations/emulator").to_vec(),
1029            ],
1030            [
1031                b"testdata/policies/selinux_testsuite".to_vec(),
1032                include_bytes!("../../testdata/policies/selinux_testsuite").to_vec(),
1033                include_bytes!("../../testdata/expectations/selinux_testsuite").to_vec(),
1034            ],
1035        ];
1036
1037        for [policy_path, policy_bytes, expectations_bytes] in policies_and_expectations {
1038            let expectations = serde_json5::from_reader::<_, Expectations>(
1039                &mut std::io::Cursor::new(expectations_bytes),
1040            )
1041            .expect("deserialize expectations");
1042
1043            // Test parse-by-value.
1044
1045            let (policy, returned_policy_bytes) =
1046                parse_policy_by_value(policy_bytes.clone()).expect("parse policy");
1047
1048            let policy = policy
1049                .validate()
1050                .with_context(|| {
1051                    format!(
1052                        "policy path: {:?}",
1053                        std::str::from_utf8(policy_path.as_slice()).unwrap()
1054                    )
1055                })
1056                .expect("validate policy");
1057
1058            assert_eq!(expectations.expected_policy_version, policy.policy_version());
1059            assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
1060
1061            // Returned policy bytes must be identical to input policy bytes.
1062            assert_eq!(policy_bytes, returned_policy_bytes);
1063
1064            // Test parse-by-reference.
1065            let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1066            let policy = policy.validate().expect("validate policy");
1067
1068            assert_eq!(expectations.expected_policy_version, policy.policy_version());
1069            assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
1070        }
1071    }
1072
1073    #[test]
1074    fn policy_lookup() {
1075        let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
1076        let (policy, _) = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1077        let policy = policy.validate().expect("validate selinux testsuite policy");
1078
1079        let unconfined_t = policy.type_id_by_name("unconfined_t").expect("look up type id");
1080
1081        assert!(is_explicitly_allowed(&policy, unconfined_t, unconfined_t, "process", "fork",));
1082    }
1083
1084    #[test]
1085    fn initial_contexts() {
1086        let policy_bytes = include_bytes!(
1087            "../../testdata/micro_policies/multiple_levels_and_categories_policy.pp"
1088        );
1089        let (policy, _) = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1090        let policy = policy.validate().expect("validate policy");
1091
1092        let kernel_context = policy.initial_context(InitialSid::Kernel);
1093        assert_eq!(
1094            policy.serialize_security_context(&kernel_context),
1095            b"user0:object_r:type0:s0:c0-s1:c0.c2,c4"
1096        )
1097    }
1098
1099    #[test]
1100    fn explicit_allow_type_type() {
1101        let policy_bytes =
1102            include_bytes!("../../testdata/micro_policies/allow_a_t_b_t_class0_perm0_policy.pp");
1103        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1104            .expect("parse policy")
1105            .validate()
1106            .expect("validate policy");
1107
1108        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1109        let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1110
1111        assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1112    }
1113
1114    #[test]
1115    fn no_explicit_allow_type_type() {
1116        let policy_bytes =
1117            include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_t_class0_perm0_policy.pp");
1118        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1119            .expect("parse policy")
1120            .validate()
1121            .expect("validate policy");
1122
1123        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1124        let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1125
1126        assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1127    }
1128
1129    #[test]
1130    fn explicit_allow_type_attr() {
1131        let policy_bytes =
1132            include_bytes!("../../testdata/micro_policies/allow_a_t_b_attr_class0_perm0_policy.pp");
1133        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1134            .expect("parse policy")
1135            .validate()
1136            .expect("validate policy");
1137
1138        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1139        let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1140
1141        assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1142    }
1143
1144    #[test]
1145    fn no_explicit_allow_type_attr() {
1146        let policy_bytes = include_bytes!(
1147            "../../testdata/micro_policies/no_allow_a_t_b_attr_class0_perm0_policy.pp"
1148        );
1149        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1150            .expect("parse policy")
1151            .validate()
1152            .expect("validate policy");
1153
1154        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1155        let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1156
1157        assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1158    }
1159
1160    #[test]
1161    fn explicit_allow_attr_attr() {
1162        let policy_bytes = include_bytes!(
1163            "../../testdata/micro_policies/allow_a_attr_b_attr_class0_perm0_policy.pp"
1164        );
1165        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1166            .expect("parse policy")
1167            .validate()
1168            .expect("validate policy");
1169
1170        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1171        let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1172
1173        assert!(is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1174    }
1175
1176    #[test]
1177    fn no_explicit_allow_attr_attr() {
1178        let policy_bytes = include_bytes!(
1179            "../../testdata/micro_policies/no_allow_a_attr_b_attr_class0_perm0_policy.pp"
1180        );
1181        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1182            .expect("parse policy")
1183            .validate()
1184            .expect("validate policy");
1185
1186        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1187        let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1188
1189        assert!(!is_explicitly_allowed(&policy, a_t, b_t, "class0", "perm0"));
1190    }
1191
1192    #[test]
1193    fn compute_explicitly_allowed_multiple_attributes() {
1194        let policy_bytes = include_bytes!("../../testdata/micro_policies/allow_a_t_a1_attr_class0_perm0_a2_attr_class0_perm1_policy.pp");
1195        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1196            .expect("parse policy")
1197            .validate()
1198            .expect("validate policy");
1199
1200        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1201
1202        let class = policy
1203            .0
1204            .parsed_policy()
1205            .classes()
1206            .iter()
1207            .find(|class| class.name_bytes() == b"class0")
1208            .expect("class not found");
1209        let raw_access_vector =
1210            policy.0.parsed_policy().compute_explicitly_allowed(a_t, a_t, class).allow.0;
1211
1212        // Two separate attributes are each allowed one permission on `[attr] self:class0`. Both
1213        // attributes are associated with "a_t". No other `allow` statements appear in the policy
1214        // in relation to "a_t". Therefore, we expect exactly two 1's in the access vector for
1215        // query `("a_t", "a_t", "class0")`.
1216        assert_eq!(2, raw_access_vector.count_ones());
1217    }
1218
1219    #[test]
1220    fn compute_access_decision_with_constraints() {
1221        let policy_bytes =
1222            include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1223        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1224            .expect("parse policy")
1225            .validate()
1226            .expect("validate policy");
1227
1228        let source_context: SecurityContext = policy
1229            .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1230            .expect("create source security context");
1231
1232        let target_context_satisfied: SecurityContext = source_context.clone();
1233        let decision_satisfied = policy.compute_access_decision(
1234            &source_context,
1235            &target_context_satisfied,
1236            KernelClass::File,
1237        );
1238        // The class `file` has 4 permissions, 3 of which are explicitly
1239        // allowed for this target context. All of those permissions satisfy all
1240        // matching constraints.
1241        assert_eq!(decision_satisfied.allow, AccessVector(7));
1242
1243        let target_context_unsatisfied: SecurityContext = policy
1244            .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1245            .expect("create target security context failing some constraints");
1246        let decision_unsatisfied = policy.compute_access_decision(
1247            &source_context,
1248            &target_context_unsatisfied,
1249            KernelClass::File,
1250        );
1251        // Two of the explicitly-allowed permissions fail to satisfy a matching
1252        // constraint. Only 1 is allowed in the final access decision.
1253        assert_eq!(decision_unsatisfied.allow, AccessVector(4));
1254    }
1255
1256    #[test]
1257    fn compute_ioctl_access_decision_explicitly_allowed() {
1258        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1259        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1260            .expect("parse policy")
1261            .validate()
1262            .expect("validate policy");
1263
1264        let source_context: SecurityContext = policy
1265            .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1266            .expect("create source security context");
1267        let target_context_matched: SecurityContext = source_context.clone();
1268
1269        // `allowxperm` rules for the `file` class:
1270        //
1271        // `allowxperm type0 self:file ioctl { 0xabcd };`
1272        // `allowxperm type0 self:file ioctl { 0xabef };`
1273        // `allowxperm type0 self:file ioctl { 0x1000 - 0x10ff };`
1274        //
1275        // `auditallowxperm` rules for the `file` class:
1276        //
1277        // auditallowxperm type0 self:file ioctl { 0xabcd };
1278        // auditallowxperm type0 self:file ioctl { 0xabef };
1279        // auditallowxperm type0 self:file ioctl { 0x1000 - 0x10ff };
1280        //
1281        // `dontauditxperm` rules for the `file` class:
1282        //
1283        // dontauditxperm type0 self:file ioctl { 0xabcd };
1284        // dontauditxperm type0 self:file ioctl { 0xabef };
1285        // dontauditxperm type0 self:file ioctl { 0x1000 - 0x10ff };
1286        let decision_single = policy.compute_ioctl_access_decision(
1287            &source_context,
1288            &target_context_matched,
1289            KernelClass::File,
1290            0xab,
1291        );
1292
1293        let mut expected_auditdeny =
1294            xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1295        expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1296
1297        let expected_decision_single = IoctlAccessDecision {
1298            allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1299            auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1300            auditdeny: expected_auditdeny,
1301        };
1302        assert_eq!(decision_single, expected_decision_single);
1303
1304        let decision_range = policy.compute_ioctl_access_decision(
1305            &source_context,
1306            &target_context_matched,
1307            KernelClass::File,
1308            0x10,
1309        );
1310        let expected_decision_range = IoctlAccessDecision {
1311            allow: XpermsBitmap::ALL,
1312            auditallow: XpermsBitmap::ALL,
1313            auditdeny: XpermsBitmap::NONE,
1314        };
1315        assert_eq!(decision_range, expected_decision_range);
1316    }
1317
1318    #[test]
1319    fn compute_ioctl_access_decision_unmatched() {
1320        let policy_bytes =
1321            include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1322        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1323            .expect("parse policy")
1324            .validate()
1325            .expect("validate policy");
1326
1327        let source_context: SecurityContext = policy
1328            .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1329            .expect("create source security context");
1330
1331        // No matching ioctl xperm-related statements for this target's type
1332        let target_context_unmatched: SecurityContext = policy
1333            .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1334            .expect("create source security context");
1335
1336        for prefix in 0x0..=0xff {
1337            let decision = policy.compute_ioctl_access_decision(
1338                &source_context,
1339                &target_context_unmatched,
1340                KernelClass::File,
1341                prefix,
1342            );
1343            assert_eq!(decision, IoctlAccessDecision::ALLOW_ALL);
1344        }
1345    }
1346
1347    #[test]
1348    fn compute_create_context_minimal() {
1349        let policy_bytes =
1350            include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1351        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1352            .expect("parse policy")
1353            .validate()
1354            .expect("validate policy");
1355        let source = policy
1356            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1357            .expect("valid source security context");
1358        let target = policy
1359            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1360            .expect("valid target security context");
1361
1362        let actual = policy.compute_create_context(&source, &target, FileClass::File);
1363        let expected: SecurityContext = policy
1364            .parse_security_context(b"source_u:object_r:target_t:s0:c0".into())
1365            .expect("valid expected security context");
1366
1367        assert_eq!(expected, actual);
1368    }
1369
1370    #[test]
1371    fn new_security_context_minimal() {
1372        let policy_bytes =
1373            include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1374        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1375            .expect("parse policy")
1376            .validate()
1377            .expect("validate policy");
1378        let source = policy
1379            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1380            .expect("valid source security context");
1381        let target = policy
1382            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1383            .expect("valid target security context");
1384
1385        let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1386
1387        assert_eq!(source, actual);
1388    }
1389
1390    #[test]
1391    fn compute_create_context_class_defaults() {
1392        let policy_bytes =
1393            include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1394        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1395            .expect("parse policy")
1396            .validate()
1397            .expect("validate policy");
1398        let source = policy
1399            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1400            .expect("valid source security context");
1401        let target = policy
1402            .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1403            .expect("valid target security context");
1404
1405        let actual = policy.compute_create_context(&source, &target, FileClass::File);
1406        let expected: SecurityContext = policy
1407            .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1408            .expect("valid expected security context");
1409
1410        assert_eq!(expected, actual);
1411    }
1412
1413    #[test]
1414    fn new_security_context_class_defaults() {
1415        let policy_bytes =
1416            include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1417        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1418            .expect("parse policy")
1419            .validate()
1420            .expect("validate policy");
1421        let source = policy
1422            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1423            .expect("valid source security context");
1424        let target = policy
1425            .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1426            .expect("valid target security context");
1427
1428        let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1429        let expected: SecurityContext = policy
1430            .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1431            .expect("valid expected security context");
1432
1433        assert_eq!(expected, actual);
1434    }
1435
1436    #[test]
1437    fn compute_create_context_role_transition() {
1438        let policy_bytes =
1439            include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
1440        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1441            .expect("parse policy")
1442            .validate()
1443            .expect("validate policy");
1444        let source = policy
1445            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1446            .expect("valid source security context");
1447        let target = policy
1448            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1449            .expect("valid target security context");
1450
1451        let actual = policy.compute_create_context(&source, &target, FileClass::File);
1452        let expected: SecurityContext = policy
1453            .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
1454            .expect("valid expected security context");
1455
1456        assert_eq!(expected, actual);
1457    }
1458
1459    #[test]
1460    fn new_security_context_role_transition() {
1461        let policy_bytes =
1462            include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
1463        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1464            .expect("parse policy")
1465            .validate()
1466            .expect("validate policy");
1467        let source = policy
1468            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1469            .expect("valid source security context");
1470        let target = policy
1471            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1472            .expect("valid target security context");
1473
1474        let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1475        let expected: SecurityContext = policy
1476            .parse_security_context(b"source_u:transition_r:source_t:s0:c0-s2:c0.c1".into())
1477            .expect("valid expected security context");
1478
1479        assert_eq!(expected, actual);
1480    }
1481
1482    #[test]
1483    // TODO(http://b/334968228): Determine whether allow-role-transition check belongs in `compute_create_context()`, or in the calling hooks, or `PermissionCheck::has_permission()`.
1484    #[ignore]
1485    fn compute_create_context_role_transition_not_allowed() {
1486        let policy_bytes = include_bytes!(
1487            "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy.pp"
1488        );
1489        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1490            .expect("parse policy")
1491            .validate()
1492            .expect("validate policy");
1493        let source = policy
1494            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1495            .expect("valid source security context");
1496        let target = policy
1497            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1498            .expect("valid target security context");
1499
1500        let actual = policy.compute_create_context(&source, &target, FileClass::File);
1501
1502        // TODO(http://b/334968228): Update expectation once role validation is implemented.
1503        assert!(policy.validate_security_context(&actual).is_err());
1504    }
1505
1506    #[test]
1507    fn compute_create_context_type_transition() {
1508        let policy_bytes =
1509            include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
1510        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1511            .expect("parse policy")
1512            .validate()
1513            .expect("validate policy");
1514        let source = policy
1515            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1516            .expect("valid source security context");
1517        let target = policy
1518            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1519            .expect("valid target security context");
1520
1521        let actual = policy.compute_create_context(&source, &target, FileClass::File);
1522        let expected: SecurityContext = policy
1523            .parse_security_context(b"source_u:object_r:transition_t:s0:c0".into())
1524            .expect("valid expected security context");
1525
1526        assert_eq!(expected, actual);
1527    }
1528
1529    #[test]
1530    fn new_security_context_type_transition() {
1531        let policy_bytes =
1532            include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
1533        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1534            .expect("parse policy")
1535            .validate()
1536            .expect("validate policy");
1537        let source = policy
1538            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1539            .expect("valid source security context");
1540        let target = policy
1541            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1542            .expect("valid target security context");
1543
1544        let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1545        let expected: SecurityContext = policy
1546            .parse_security_context(b"source_u:source_r:transition_t:s0:c0-s2:c0.c1".into())
1547            .expect("valid expected security context");
1548
1549        assert_eq!(expected, actual);
1550    }
1551
1552    #[test]
1553    fn compute_create_context_range_transition() {
1554        let policy_bytes =
1555            include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
1556        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1557            .expect("parse policy")
1558            .validate()
1559            .expect("validate policy");
1560        let source = policy
1561            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1562            .expect("valid source security context");
1563        let target = policy
1564            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1565            .expect("valid target security context");
1566
1567        let actual = policy.compute_create_context(&source, &target, FileClass::File);
1568        let expected: SecurityContext = policy
1569            .parse_security_context(b"source_u:object_r:target_t:s1:c1-s2:c1.c2".into())
1570            .expect("valid expected security context");
1571
1572        assert_eq!(expected, actual);
1573    }
1574
1575    #[test]
1576    fn new_security_context_range_transition() {
1577        let policy_bytes =
1578            include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
1579        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1580            .expect("parse policy")
1581            .validate()
1582            .expect("validate policy");
1583        let source = policy
1584            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1585            .expect("valid source security context");
1586        let target = policy
1587            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1588            .expect("valid target security context");
1589
1590        let actual = policy.compute_create_context(&source, &target, KernelClass::Process);
1591        let expected: SecurityContext = policy
1592            .parse_security_context(b"source_u:source_r:source_t:s1:c1-s2:c1.c2".into())
1593            .expect("valid expected security context");
1594
1595        assert_eq!(expected, actual);
1596    }
1597}