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