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