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, KernelClass, NullessByteStr};
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: &KernelClass,
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::KernelClass,
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::ObjectClass::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::KernelClass,
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::ObjectClass::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::KernelPermission> + 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::KernelPermission> + 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, KernelClass, KernelPermission,
959        ProcessPermission,
960    };
961
962    use serde::Deserialize;
963    use std::ops::Shl;
964
965    /// Returns whether the input types are explicitly granted `permission` via an `allow [...];`
966    /// policy statement.
967    ///
968    /// # Panics
969    /// If supplied with type Ids not previously obtained from the `Policy` itself; validation
970    /// ensures that all such Ids have corresponding definitions.
971    fn is_explicitly_allowed<PS: ParseStrategy>(
972        policy: &Policy<PS>,
973        source_type: TypeId,
974        target_type: TypeId,
975        permission: sc::KernelPermission,
976    ) -> Result<bool, &'static str> {
977        let object_class = permission.class();
978        let target_class = policy.0.class(&object_class).ok_or("class lookup failed")?;
979        let permission = policy.0.permission(&permission).ok_or("permission lookup failed")?;
980        let access_decision = policy.0.parsed_policy().compute_explicitly_allowed(
981            source_type,
982            target_type,
983            target_class,
984        );
985        let permission_bit = AccessVector::from_class_permission_id(permission.id());
986        Ok(permission_bit == access_decision.allow & permission_bit)
987    }
988
989    /// Returns whether the input types are explicitly granted `permission` via an `allow [...];`
990    /// policy statement, when the target class and permission name are specified as strings.
991    ///
992    /// # Panics
993    /// If supplied with type Ids not previously obtained from the `Policy` itself; validation
994    /// ensures that all such Ids have corresponding definitions.
995    fn is_explicitly_allowed_custom<PS: ParseStrategy>(
996        policy: &Policy<PS>,
997        source_type: TypeId,
998        target_type: TypeId,
999        target_class_name: &str,
1000        permission_name: &str,
1001    ) -> Result<bool, &'static str> {
1002        let (permission_id, _) = policy
1003            .find_class_permissions_by_name(target_class_name)
1004            .or(Err("class name lookup failed"))?
1005            .into_iter()
1006            .find(|(_, name)| name == permission_name.as_bytes())
1007            .ok_or("permission name lookup failed")?;
1008        let access_decision = policy.0.parsed_policy().compute_explicitly_allowed_custom(
1009            source_type,
1010            target_type,
1011            target_class_name,
1012        );
1013        let permission_bit = AccessVector::from_class_permission_id(permission_id);
1014        Ok(permission_bit == access_decision.allow & permission_bit)
1015    }
1016
1017    #[derive(Debug, Deserialize)]
1018    struct Expectations {
1019        expected_policy_version: u32,
1020        expected_handle_unknown: LocalHandleUnknown,
1021    }
1022
1023    #[derive(Debug, Deserialize, PartialEq)]
1024    #[serde(rename_all = "snake_case")]
1025    enum LocalHandleUnknown {
1026        Deny,
1027        Reject,
1028        Allow,
1029    }
1030
1031    impl PartialEq<HandleUnknown> for LocalHandleUnknown {
1032        fn eq(&self, other: &HandleUnknown) -> bool {
1033            match self {
1034                LocalHandleUnknown::Deny => *other == HandleUnknown::Deny,
1035                LocalHandleUnknown::Reject => *other == HandleUnknown::Reject,
1036                LocalHandleUnknown::Allow => *other == HandleUnknown::Allow,
1037            }
1038        }
1039    }
1040
1041    /// Given a vector of integer (u8) values, returns a bitmap in which the set bits correspond to
1042    /// the indices of the provided values.
1043    fn xperms_bitmap_from_elements(elements: &[u8]) -> XpermsBitmap {
1044        let mut bitmap = [le::U32::ZERO; 8];
1045        for element in elements.iter() {
1046            let block_index = (*element as usize) / 32;
1047            let bit_index = ((*element as usize) % 32) as u32;
1048            let bitmask = le::U32::new(1).shl(bit_index);
1049            bitmap[block_index] = bitmap[block_index] | bitmask;
1050        }
1051        XpermsBitmap::new(bitmap)
1052    }
1053
1054    #[test]
1055    fn known_policies() {
1056        let policies_and_expectations = [
1057            [
1058                b"testdata/policies/emulator".to_vec(),
1059                include_bytes!("../../testdata/policies/emulator").to_vec(),
1060                include_bytes!("../../testdata/expectations/emulator").to_vec(),
1061            ],
1062            [
1063                b"testdata/policies/selinux_testsuite".to_vec(),
1064                include_bytes!("../../testdata/policies/selinux_testsuite").to_vec(),
1065                include_bytes!("../../testdata/expectations/selinux_testsuite").to_vec(),
1066            ],
1067        ];
1068
1069        for [policy_path, policy_bytes, expectations_bytes] in policies_and_expectations {
1070            let expectations = serde_json5::from_reader::<_, Expectations>(
1071                &mut std::io::Cursor::new(expectations_bytes),
1072            )
1073            .expect("deserialize expectations");
1074
1075            // Test parse-by-value.
1076
1077            let (policy, returned_policy_bytes) =
1078                parse_policy_by_value(policy_bytes.clone()).expect("parse policy");
1079
1080            let policy = policy
1081                .validate()
1082                .with_context(|| {
1083                    format!(
1084                        "policy path: {:?}",
1085                        std::str::from_utf8(policy_path.as_slice()).unwrap()
1086                    )
1087                })
1088                .expect("validate policy");
1089
1090            assert_eq!(expectations.expected_policy_version, policy.policy_version());
1091            assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
1092
1093            // Returned policy bytes must be identical to input policy bytes.
1094            assert_eq!(policy_bytes, returned_policy_bytes);
1095
1096            // Test parse-by-reference.
1097            let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1098            let policy = policy.validate().expect("validate policy");
1099
1100            assert_eq!(expectations.expected_policy_version, policy.policy_version());
1101            assert_eq!(expectations.expected_handle_unknown, policy.handle_unknown());
1102        }
1103    }
1104
1105    #[test]
1106    fn policy_lookup() {
1107        let policy_bytes = include_bytes!("../../testdata/policies/selinux_testsuite");
1108        let (policy, _) = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1109        let policy = policy.validate().expect("validate selinux testsuite policy");
1110
1111        let unconfined_t = policy.type_id_by_name("unconfined_t").expect("look up type id");
1112
1113        assert!(is_explicitly_allowed(
1114            &policy,
1115            unconfined_t,
1116            unconfined_t,
1117            KernelPermission::Process(ProcessPermission::Fork),
1118        )
1119        .expect("check for `allow unconfined_t unconfined_t:process fork;"));
1120    }
1121
1122    #[test]
1123    fn initial_contexts() {
1124        let policy_bytes = include_bytes!(
1125            "../../testdata/micro_policies/multiple_levels_and_categories_policy.pp"
1126        );
1127        let (policy, _) = parse_policy_by_value(policy_bytes.to_vec()).expect("parse policy");
1128        let policy = policy.validate().expect("validate policy");
1129
1130        let kernel_context = policy.initial_context(InitialSid::Kernel);
1131        assert_eq!(
1132            policy.serialize_security_context(&kernel_context),
1133            b"user0:object_r:type0:s0:c0-s1:c0.c2,c4"
1134        )
1135    }
1136
1137    #[test]
1138    fn explicit_allow_type_type() {
1139        let policy_bytes =
1140            include_bytes!("../../testdata/micro_policies/allow_a_t_b_t_class0_perm0_policy.pp");
1141        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1142            .expect("parse policy")
1143            .validate()
1144            .expect("validate policy");
1145
1146        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1147        let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1148
1149        assert!(is_explicitly_allowed_custom(&policy, a_t, b_t, "class0", "perm0")
1150            .expect("query well-formed"));
1151    }
1152
1153    #[test]
1154    fn no_explicit_allow_type_type() {
1155        let policy_bytes =
1156            include_bytes!("../../testdata/micro_policies/no_allow_a_t_b_t_class0_perm0_policy.pp");
1157        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1158            .expect("parse policy")
1159            .validate()
1160            .expect("validate policy");
1161
1162        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1163        let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1164
1165        assert!(!is_explicitly_allowed_custom(&policy, a_t, b_t, "class0", "perm0")
1166            .expect("query well-formed"));
1167    }
1168
1169    #[test]
1170    fn explicit_allow_type_attr() {
1171        let policy_bytes =
1172            include_bytes!("../../testdata/micro_policies/allow_a_t_b_attr_class0_perm0_policy.pp");
1173        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1174            .expect("parse policy")
1175            .validate()
1176            .expect("validate policy");
1177
1178        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1179        let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1180
1181        assert!(is_explicitly_allowed_custom(&policy, a_t, b_t, "class0", "perm0")
1182            .expect("query well-formed"));
1183    }
1184
1185    #[test]
1186    fn no_explicit_allow_type_attr() {
1187        let policy_bytes = include_bytes!(
1188            "../../testdata/micro_policies/no_allow_a_t_b_attr_class0_perm0_policy.pp"
1189        );
1190        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1191            .expect("parse policy")
1192            .validate()
1193            .expect("validate policy");
1194
1195        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1196        let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1197
1198        assert!(!is_explicitly_allowed_custom(&policy, a_t, b_t, "class0", "perm0")
1199            .expect("query well-formed"));
1200    }
1201
1202    #[test]
1203    fn explicit_allow_attr_attr() {
1204        let policy_bytes = include_bytes!(
1205            "../../testdata/micro_policies/allow_a_attr_b_attr_class0_perm0_policy.pp"
1206        );
1207        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1208            .expect("parse policy")
1209            .validate()
1210            .expect("validate policy");
1211
1212        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1213        let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1214
1215        assert!(is_explicitly_allowed_custom(&policy, a_t, b_t, "class0", "perm0")
1216            .expect("query well-formed"));
1217    }
1218
1219    #[test]
1220    fn no_explicit_allow_attr_attr() {
1221        let policy_bytes = include_bytes!(
1222            "../../testdata/micro_policies/no_allow_a_attr_b_attr_class0_perm0_policy.pp"
1223        );
1224        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1225            .expect("parse policy")
1226            .validate()
1227            .expect("validate policy");
1228
1229        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1230        let b_t = policy.type_id_by_name("b_t").expect("look up type id");
1231
1232        assert!(!is_explicitly_allowed_custom(&policy, a_t, b_t, "class0", "perm0")
1233            .expect("query well-formed"));
1234    }
1235
1236    #[test]
1237    fn compute_explicitly_allowed_multiple_attributes() {
1238        let policy_bytes = include_bytes!("../../testdata/micro_policies/allow_a_t_a1_attr_class0_perm0_a2_attr_class0_perm1_policy.pp");
1239        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1240            .expect("parse policy")
1241            .validate()
1242            .expect("validate policy");
1243
1244        let a_t = policy.type_id_by_name("a_t").expect("look up type id");
1245
1246        let raw_access_vector =
1247            policy.0.parsed_policy().compute_explicitly_allowed_custom(a_t, a_t, "class0").allow.0;
1248
1249        // Two separate attributes are each allowed one permission on `[attr] self:class0`. Both
1250        // attributes are associated with "a_t". No other `allow` statements appear in the policy
1251        // in relation to "a_t". Therefore, we expect exactly two 1's in the access vector for
1252        // query `("a_t", "a_t", "class0")`.
1253        assert_eq!(2, raw_access_vector.count_ones());
1254    }
1255
1256    #[test]
1257    fn compute_access_decision_with_constraints() {
1258        let policy_bytes =
1259            include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1260        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1261            .expect("parse policy")
1262            .validate()
1263            .expect("validate policy");
1264
1265        let source_context: SecurityContext = policy
1266            .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1267            .expect("create source security context");
1268
1269        let target_context_satisfied: SecurityContext = source_context.clone();
1270        let decision_satisfied = policy.compute_access_decision(
1271            &source_context,
1272            &target_context_satisfied,
1273            &KernelClass::File,
1274        );
1275        // The class `file` has 4 permissions, 3 of which are explicitly
1276        // allowed for this target context. All of those permissions satisfy all
1277        // matching constraints.
1278        assert_eq!(decision_satisfied.allow, AccessVector(7));
1279
1280        let target_context_unsatisfied: SecurityContext = policy
1281            .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1282            .expect("create target security context failing some constraints");
1283        let decision_unsatisfied = policy.compute_access_decision(
1284            &source_context,
1285            &target_context_unsatisfied,
1286            &KernelClass::File,
1287        );
1288        // Two of the explicitly-allowed permissions fail to satisfy a matching
1289        // constraint. Only 1 is allowed in the final access decision.
1290        assert_eq!(decision_unsatisfied.allow, AccessVector(4));
1291    }
1292
1293    #[test]
1294    fn compute_access_decision_custom_with_mlsconstrain() {
1295        let policy_bytes =
1296            include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1297        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1298            .expect("parse policy")
1299            .validate()
1300            .expect("validate policy");
1301
1302        let source_context: SecurityContext = policy
1303            .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1304            .expect("create source security context");
1305
1306        let target_context_satisfied: SecurityContext = source_context.clone();
1307        let decision_satisfied = policy.compute_access_decision_custom(
1308            &source_context,
1309            &target_context_satisfied,
1310            "class_mlsconstrain",
1311        );
1312        // The class `class_mlsconstrain` has 3 permissions, 2 of which are explicitly
1313        // allowed for this target context. Both of those permissions satisfy all
1314        // matching constraints.
1315        assert_eq!(decision_satisfied.allow, AccessVector(3));
1316
1317        let target_context_unsatisfied: SecurityContext = policy
1318            .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1319            .expect("create target security context failing a constraint");
1320        let decision_unsatisfied = policy.compute_access_decision_custom(
1321            &source_context,
1322            &target_context_unsatisfied,
1323            "class_mlsconstrain",
1324        );
1325        // One of the explicitly-allowed permissions fails to satisfy a matching
1326        // constraint.
1327        assert_eq!(decision_unsatisfied.allow, AccessVector(2));
1328    }
1329
1330    #[test]
1331    fn compute_access_decision_custom_with_constrain() {
1332        let policy_bytes =
1333            include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1334        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1335            .expect("parse policy")
1336            .validate()
1337            .expect("validate policy");
1338
1339        let source_context: SecurityContext = policy
1340            .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1341            .expect("create source security context");
1342
1343        let target_context_satisfied: SecurityContext = source_context.clone();
1344        let decision_satisfied = policy.compute_access_decision_custom(
1345            &source_context,
1346            &target_context_satisfied,
1347            "class_mlsconstrain",
1348        );
1349        // The class `class_constrain` has 3 permissions, 2 of which are explicitly
1350        // allowed for this target context. Both of those permissions satisfy all
1351        // matching constraints.
1352        assert_eq!(decision_satisfied.allow, AccessVector(3));
1353
1354        let target_context_unsatisfied: SecurityContext = policy
1355            .parse_security_context(b"user1:object_r:type0:s0:c0-s0:c0".into())
1356            .expect("create target security context failing a constraint");
1357        let decision_unsatisfied = policy.compute_access_decision_custom(
1358            &source_context,
1359            &target_context_unsatisfied,
1360            "class_constrain",
1361        );
1362        // One of the explicitly-allowed permissions fails to satisfy a matching
1363        // constraint.
1364        assert_eq!(decision_unsatisfied.allow, AccessVector(2));
1365    }
1366
1367    #[test]
1368    fn compute_ioctl_access_decision_explicitly_allowed() {
1369        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1370        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1371            .expect("parse policy")
1372            .validate()
1373            .expect("validate policy");
1374
1375        let source_context: SecurityContext = policy
1376            .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1377            .expect("create source security context");
1378        let target_context_matched: SecurityContext = source_context.clone();
1379
1380        // `allowxperm` rules for the `file` class:
1381        //
1382        // `allowxperm type0 self:file ioctl { 0xabcd };`
1383        // `allowxperm type0 self:file ioctl { 0xabef };`
1384        // `allowxperm type0 self:file ioctl { 0x1000 - 0x10ff };`
1385        //
1386        // `auditallowxperm` rules for the `file` class:
1387        //
1388        // auditallowxperm type0 self:file ioctl { 0xabcd };
1389        // auditallowxperm type0 self:file ioctl { 0xabef };
1390        // auditallowxperm type0 self:file ioctl { 0x1000 - 0x10ff };
1391        //
1392        // `dontauditxperm` rules for the `file` class:
1393        //
1394        // dontauditxperm type0 self:file ioctl { 0xabcd };
1395        // dontauditxperm type0 self:file ioctl { 0xabef };
1396        // dontauditxperm type0 self:file ioctl { 0x1000 - 0x10ff };
1397        let decision_single = policy.compute_ioctl_access_decision(
1398            &source_context,
1399            &target_context_matched,
1400            &KernelClass::File,
1401            0xab,
1402        );
1403
1404        let mut expected_auditdeny =
1405            xperms_bitmap_from_elements((0x0..=0xff).collect::<Vec<_>>().as_slice());
1406        expected_auditdeny -= &xperms_bitmap_from_elements(&[0xcd, 0xef]);
1407
1408        let expected_decision_single = IoctlAccessDecision {
1409            allow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1410            auditallow: xperms_bitmap_from_elements(&[0xcd, 0xef]),
1411            auditdeny: expected_auditdeny,
1412        };
1413        assert_eq!(decision_single, expected_decision_single);
1414
1415        let decision_range = policy.compute_ioctl_access_decision(
1416            &source_context,
1417            &target_context_matched,
1418            &KernelClass::File,
1419            0x10,
1420        );
1421        let expected_decision_range = IoctlAccessDecision {
1422            allow: XpermsBitmap::ALL,
1423            auditallow: XpermsBitmap::ALL,
1424            auditdeny: XpermsBitmap::NONE,
1425        };
1426        assert_eq!(decision_range, expected_decision_range);
1427    }
1428
1429    #[test]
1430    fn compute_ioctl_access_decision_unmatched() {
1431        let policy_bytes =
1432            include_bytes!("../../testdata/micro_policies/allow_with_constraints_policy.pp");
1433        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1434            .expect("parse policy")
1435            .validate()
1436            .expect("validate policy");
1437
1438        let source_context: SecurityContext = policy
1439            .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1440            .expect("create source security context");
1441
1442        // No matching ioctl xperm-related statements for this target's type
1443        let target_context_unmatched: SecurityContext = policy
1444            .parse_security_context(b"user0:object_r:type1:s0-s0".into())
1445            .expect("create source security context");
1446
1447        for prefix in 0x0..=0xff {
1448            let decision = policy.compute_ioctl_access_decision(
1449                &source_context,
1450                &target_context_unmatched,
1451                &KernelClass::File,
1452                prefix,
1453            );
1454            assert_eq!(decision, IoctlAccessDecision::ALLOW_ALL);
1455        }
1456    }
1457
1458    #[test]
1459    fn compute_ioctl_access_decision_custom() {
1460        let policy_bytes = include_bytes!("../../testdata/micro_policies/allowxperm_policy.pp");
1461        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1462            .expect("parse policy")
1463            .validate()
1464            .expect("validate policy");
1465
1466        let source_context: SecurityContext = policy
1467            .parse_security_context(b"user0:object_r:type0:s0-s0".into())
1468            .expect("create source security context");
1469
1470        // xperm-related rules for `class_two_ioctls_same_range`:
1471        //
1472        // `allowxperm type0 self:class_two_ioctls_same_range ioctl { 0x1234 0x1256 };`
1473        let target_context: SecurityContext = source_context.clone();
1474        let decision = policy.compute_ioctl_access_decision_custom(
1475            &source_context,
1476            &target_context,
1477            "class_two_ioctls_same_range",
1478            0x12,
1479        );
1480
1481        let expected_decision = IoctlAccessDecision {
1482            allow: xperms_bitmap_from_elements(&[0x34, 0x56]),
1483            auditallow: XpermsBitmap::NONE,
1484            auditdeny: XpermsBitmap::ALL,
1485        };
1486        assert_eq!(decision, expected_decision);
1487    }
1488
1489    #[test]
1490    fn new_file_security_context_minimal() {
1491        let policy_bytes =
1492            include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1493        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1494            .expect("parse policy")
1495            .validate()
1496            .expect("validate policy");
1497        let source = policy
1498            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1499            .expect("valid source security context");
1500        let target = policy
1501            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1502            .expect("valid target security context");
1503
1504        let actual = policy.new_file_security_context(&source, &target, &FileClass::File.into());
1505        let expected: SecurityContext = policy
1506            .parse_security_context(b"source_u:object_r:target_t:s0:c0".into())
1507            .expect("valid expected security context");
1508
1509        assert_eq!(expected, actual);
1510    }
1511
1512    #[test]
1513    fn new_security_context_minimal() {
1514        let policy_bytes =
1515            include_bytes!("../../testdata/composite_policies/compiled/minimal_policy.pp");
1516        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1517            .expect("parse policy")
1518            .validate()
1519            .expect("validate policy");
1520        let source = policy
1521            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1522            .expect("valid source security context");
1523        let target = policy
1524            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1525            .expect("valid target security context");
1526
1527        let actual = policy.new_security_context(&source, &target, &KernelClass::Process);
1528
1529        assert_eq!(source, actual);
1530    }
1531
1532    #[test]
1533    fn new_file_security_context_class_defaults() {
1534        let policy_bytes =
1535            include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1536        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1537            .expect("parse policy")
1538            .validate()
1539            .expect("validate policy");
1540        let source = policy
1541            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1542            .expect("valid source security context");
1543        let target = policy
1544            .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1545            .expect("valid target security context");
1546
1547        let actual = policy.new_file_security_context(&source, &target, &FileClass::File.into());
1548        let expected: SecurityContext = policy
1549            .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1550            .expect("valid expected security context");
1551
1552        assert_eq!(expected, actual);
1553    }
1554
1555    #[test]
1556    fn new_security_context_class_defaults() {
1557        let policy_bytes =
1558            include_bytes!("../../testdata/composite_policies/compiled/class_defaults_policy.pp");
1559        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1560            .expect("parse policy")
1561            .validate()
1562            .expect("validate policy");
1563        let source = policy
1564            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1565            .expect("valid source security context");
1566        let target = policy
1567            .parse_security_context(b"target_u:target_r:target_t:s1:c0-s1:c0.c1".into())
1568            .expect("valid target security context");
1569
1570        let actual = policy.new_security_context(&source, &target, &KernelClass::Process);
1571        let expected: SecurityContext = policy
1572            .parse_security_context(b"target_u:source_r:source_t:s1:c0-s1:c0.c1".into())
1573            .expect("valid expected security context");
1574
1575        assert_eq!(expected, actual);
1576    }
1577
1578    #[test]
1579    fn new_file_security_context_role_transition() {
1580        let policy_bytes =
1581            include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
1582        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1583            .expect("parse policy")
1584            .validate()
1585            .expect("validate policy");
1586        let source = policy
1587            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1588            .expect("valid source security context");
1589        let target = policy
1590            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1591            .expect("valid target security context");
1592
1593        let actual = policy.new_file_security_context(&source, &target, &FileClass::File.into());
1594        let expected: SecurityContext = policy
1595            .parse_security_context(b"source_u:transition_r:target_t:s0:c0".into())
1596            .expect("valid expected security context");
1597
1598        assert_eq!(expected, actual);
1599    }
1600
1601    #[test]
1602    fn new_security_context_role_transition() {
1603        let policy_bytes =
1604            include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy.pp");
1605        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1606            .expect("parse policy")
1607            .validate()
1608            .expect("validate policy");
1609        let source = policy
1610            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1611            .expect("valid source security context");
1612        let target = policy
1613            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1614            .expect("valid target security context");
1615
1616        let actual = policy.new_security_context(&source, &target, &KernelClass::Process);
1617        let expected: SecurityContext = policy
1618            .parse_security_context(b"source_u:transition_r:source_t:s0:c0-s2:c0.c1".into())
1619            .expect("valid expected security context");
1620
1621        assert_eq!(expected, actual);
1622    }
1623
1624    #[test]
1625    // 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()`.
1626    #[ignore]
1627    fn new_file_security_context_role_transition_not_allowed() {
1628        let policy_bytes = include_bytes!(
1629            "../../testdata/composite_policies/compiled/role_transition_not_allowed_policy.pp"
1630        );
1631        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1632            .expect("parse policy")
1633            .validate()
1634            .expect("validate policy");
1635        let source = policy
1636            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1637            .expect("valid source security context");
1638        let target = policy
1639            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1640            .expect("valid target security context");
1641
1642        let actual = policy.new_file_security_context(&source, &target, &FileClass::File.into());
1643
1644        // TODO(http://b/334968228): Update expectation once role validation is implemented.
1645        assert!(policy.validate_security_context(&actual).is_err());
1646    }
1647
1648    #[test]
1649    fn new_file_security_context_type_transition() {
1650        let policy_bytes =
1651            include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
1652        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1653            .expect("parse policy")
1654            .validate()
1655            .expect("validate policy");
1656        let source = policy
1657            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1658            .expect("valid source security context");
1659        let target = policy
1660            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1661            .expect("valid target security context");
1662
1663        let actual = policy.new_file_security_context(&source, &target, &FileClass::File.into());
1664        let expected: SecurityContext = policy
1665            .parse_security_context(b"source_u:object_r:transition_t:s0:c0".into())
1666            .expect("valid expected security context");
1667
1668        assert_eq!(expected, actual);
1669    }
1670
1671    #[test]
1672    fn new_security_context_type_transition() {
1673        let policy_bytes =
1674            include_bytes!("../../testdata/composite_policies/compiled/type_transition_policy.pp");
1675        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1676            .expect("parse policy")
1677            .validate()
1678            .expect("validate policy");
1679        let source = policy
1680            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1681            .expect("valid source security context");
1682        let target = policy
1683            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1684            .expect("valid target security context");
1685
1686        let actual = policy.new_security_context(&source, &target, &KernelClass::Process);
1687        let expected: SecurityContext = policy
1688            .parse_security_context(b"source_u:source_r:transition_t:s0:c0-s2:c0.c1".into())
1689            .expect("valid expected security context");
1690
1691        assert_eq!(expected, actual);
1692    }
1693
1694    #[test]
1695    fn new_file_security_context_range_transition() {
1696        let policy_bytes =
1697            include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
1698        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1699            .expect("parse policy")
1700            .validate()
1701            .expect("validate policy");
1702        let source = policy
1703            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1704            .expect("valid source security context");
1705        let target = policy
1706            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1707            .expect("valid target security context");
1708
1709        let actual = policy.new_file_security_context(&source, &target, &FileClass::File.into());
1710        let expected: SecurityContext = policy
1711            .parse_security_context(b"source_u:object_r:target_t:s1:c1-s2:c1.c2".into())
1712            .expect("valid expected security context");
1713
1714        assert_eq!(expected, actual);
1715    }
1716
1717    #[test]
1718    fn new_security_context_range_transition() {
1719        let policy_bytes =
1720            include_bytes!("../../testdata/composite_policies/compiled/range_transition_policy.pp");
1721        let policy = parse_policy_by_reference(policy_bytes.as_slice())
1722            .expect("parse policy")
1723            .validate()
1724            .expect("validate policy");
1725        let source = policy
1726            .parse_security_context(b"source_u:source_r:source_t:s0:c0-s2:c0.c1".into())
1727            .expect("valid source security context");
1728        let target = policy
1729            .parse_security_context(b"target_u:target_r:target_t:s1:c1".into())
1730            .expect("valid target security context");
1731
1732        let actual = policy.new_security_context(&source, &target, &KernelClass::Process);
1733        let expected: SecurityContext = policy
1734            .parse_security_context(b"source_u:source_r:source_t:s1:c1-s2:c1.c2".into())
1735            .expect("valid expected security context");
1736
1737        assert_eq!(expected, actual);
1738    }
1739}