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