selinux/policy/
mod.rs

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