selinux/policy/
symbols.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
5use super::constraints::{evaluate_constraint, ConstraintError};
6use super::error::{ParseError, ValidateError};
7use super::extensible_bitmap::{
8    ExtensibleBitmap, ExtensibleBitmapSpan, ExtensibleBitmapSpansIterator,
9};
10use super::parser::ParseStrategy;
11use super::security_context::{CategoryIterator, Level, SecurityContext};
12use super::{
13    array_type, array_type_validate_deref_both, array_type_validate_deref_data,
14    array_type_validate_deref_metadata_data_vec, array_type_validate_deref_none_data_vec,
15    AccessVector, Array, CategoryId, ClassId, ClassPermissionId, Counted, Parse, ParseSlice,
16    RoleId, SensitivityId, TypeId, UserId, Validate, ValidateArray,
17};
18
19use anyhow::{anyhow, Context as _};
20use std::fmt::Debug;
21use std::num::NonZeroU32;
22use std::ops::Deref;
23use zerocopy::{little_endian as le, FromBytes, Immutable, KnownLayout, Unaligned};
24
25/// ** Constraint term types ***
26///
27/// The `constraint_term_type` metadata field value for a [`ConstraintTerm`]
28/// that represents the "not" operator.
29pub(super) const CONSTRAINT_TERM_TYPE_NOT_OPERATOR: u32 = 1;
30/// The `constraint_term_type` metadata field value for a [`ConstraintTerm`]
31/// that represents the "and" operator.
32pub(super) const CONSTRAINT_TERM_TYPE_AND_OPERATOR: u32 = 2;
33/// The `constraint_term_type` metadata field value for a [`ConstraintTerm`]
34/// that represents the "or" operator.
35pub(super) const CONSTRAINT_TERM_TYPE_OR_OPERATOR: u32 = 3;
36/// The `constraint_term_type` metadata field value for a [`ConstraintTerm`]
37/// that represents a boolean expression where both arguments are fields of
38/// a source and/or target security context.
39pub(super) const CONSTRAINT_TERM_TYPE_EXPR: u32 = 4;
40/// The `constraint_term_type` metadata field value for a [`ConstraintTerm`]
41/// that represents a boolean expression where:
42///
43/// - the left-hand side is the user, role, or type of the source or target
44///   security context
45/// - the right-hand side is a set of users, roles, or types that are
46///   specified by name in the text policy, independent of the source
47///   or target security context.
48///
49/// In this case, the [`ConstraintTerm`] contains an [`ExtensibleBitmap`] that
50/// encodes the set of user, role, or type IDs corresponding to the names, and a
51/// [`TypeSet`] encoding the corresponding set of types.
52pub(super) const CONSTRAINT_TERM_TYPE_EXPR_WITH_NAMES: u32 = 5;
53
54/// ** Constraint expression operator types ***
55///
56/// Valid `expr_operator_type` metadata field values for a [`ConstraintTerm`]
57/// with `type` equal to `CONSTRAINT_TERM_TYPE_EXPR` or
58/// `CONSTRAINT_TERM_TYPE_EXPR_WITH_NAMES`.
59///
60/// NB. `EXPR_OPERATOR_TYPE_{DOM,DOMBY,INCOMP}` were previously valid for
61///      constraints on role IDs, but this was deprecated as of SELinux
62///      policy version 26.
63///
64/// The `expr_operator_type` value for an expression of form "A == B".
65/// Valid for constraints on user, role, and type IDs.
66pub(super) const CONSTRAINT_EXPR_OPERATOR_TYPE_EQ: u32 = 1;
67/// The `expr_operator_type` value for an expression of form "A != B".
68/// Valid for constraints on user, role, and type IDs.
69pub(super) const CONSTRAINT_EXPR_OPERATOR_TYPE_NE: u32 = 2;
70/// The `expr_operator_type` value for an expression of form "A dominates B".
71/// Valid for constraints on security levels.
72pub(super) const CONSTRAINT_EXPR_OPERATOR_TYPE_DOM: u32 = 3;
73/// The `expr_operator_type` value for an expression of form "A is dominated
74/// by B".
75/// Valid for constraints on security levels.
76pub(super) const CONSTRAINT_EXPR_OPERATOR_TYPE_DOMBY: u32 = 4;
77/// The `expr_operator_type` value for an expression of form "A is
78/// incomparable to B".
79/// Valid for constraints on security levels.
80pub(super) const CONSTRAINT_EXPR_OPERATOR_TYPE_INCOMP: u32 = 5;
81
82/// ** Constraint expression types ***
83///
84/// Although these values each have a single bit set, they appear to be
85/// used as enum values rather than as bit masks: i.e., the policy compiler
86/// does not produce access vector rule structures that have more than
87/// one of these types.
88///
89/// Valid `expr_operand_type` metadata field values for a [`ConstraintTerm`]
90/// with `constraint_term_type` equal to `CONSTRAINT_TERM_TYPE_EXPR` or
91/// `CONSTRAINT_TERM_TYPE_EXPR_WITH_NAMES`.
92///
93/// When the `constraint_term_type` is equal to `CONSTRAINT_TERM_TYPE_EXPR` and
94/// the `expr_operand_type` value is `EXPR_OPERAND_TYPE_{USER,ROLE,TYPE}`, the
95/// expression compares the source's {user,role,type} ID to the target's
96/// {user,role,type} ID.
97///
98/// When the `constraint_term_type` is equal to
99/// `CONSTRAINT_TERM_TYPE_EXPR_WITH_NAMES`, then the right-hand side of the
100/// expression is the set of IDs listed in the [`ConstraintTerm`]'s `names`
101/// field. The left-hand side of the expression is the user, role, or type ID of
102/// either the target security context, or the source security context,
103/// depending on whether the `EXPR_WITH_NAMES_OPERAND_TYPE_TARGET_MASK` bit of
104/// the `expr_operand_type` field is set (--> target) or not (--> source).
105///
106/// The `expr_operand_type` value for an expression comparing user IDs.
107pub(super) const CONSTRAINT_EXPR_OPERAND_TYPE_USER: u32 = 0x1;
108/// The `expr_operand_type` value for an expression comparing role IDs.
109pub(super) const CONSTRAINT_EXPR_OPERAND_TYPE_ROLE: u32 = 0x2;
110/// The `expr_operand_type` value for an expression comparing type IDs.
111pub(super) const CONSTRAINT_EXPR_OPERAND_TYPE_TYPE: u32 = 0x4;
112/// The `expr_operand_type` value for an expression comparing the source
113/// context's low security level to the target context's low security level.
114pub(super) const CONSTRAINT_EXPR_OPERAND_TYPE_L1_L2: u32 = 0x20;
115/// The `expr_operand_type` value for an expression comparing the source
116/// context's low security level to the target context's high security level.
117pub(super) const CONSTRAINT_EXPR_OPERAND_TYPE_L1_H2: u32 = 0x40;
118/// The `expr_operand_type` value for an expression comparing the source
119/// context's high security level to the target context's low security level.
120pub(super) const CONSTRAINT_EXPR_OPERAND_TYPE_H1_L2: u32 = 0x80;
121/// The `expr_operand_type` value for an expression comparing the source
122/// context's high security level to the target context's high security level.
123pub(super) const CONSTRAINT_EXPR_OPERAND_TYPE_H1_H2: u32 = 0x100;
124/// The `expr_operand_type` value for an expression comparing the source
125/// context's low security level to the source context's high security level.
126pub(super) const CONSTRAINT_EXPR_OPERAND_TYPE_L1_H1: u32 = 0x200;
127/// The `expr_operand_type` value for an expression comparing the target
128/// context's low security level to the target context's high security level.
129pub(super) const CONSTRAINT_EXPR_OPERAND_TYPE_L2_H2: u32 = 0x400;
130
131/// For a [`ConstraintTerm`] with `constraint_term_type` equal to
132/// `CONSTRAINT_TERM_TYPE_EXPR_WITH_NAMES` the `expr_operand_type` may have the
133/// `EXPR_WITH_NAMES_OPERAND_TYPE_TARGET_MASK` bit set in addition to one of the
134/// `EXPR_OPERAND_TYPE_{USER,ROLE,TYPE}` bits.
135///
136/// If the `EXPR_WITH_NAMES_OPERAND_TYPE_TARGET_MASK` bit is set, then the
137/// expression compares the target's {user,role,type} ID to the set of IDs
138/// listed in the [`ConstraintTerm`]'s `names` field.
139///
140/// If the bit is not set, then the expression compares the source's
141/// {user,role,type} ID to the set of IDs listed in the [`ConstraintTerm`]'s
142/// `names` field.
143pub(super) const CONSTRAINT_EXPR_WITH_NAMES_OPERAND_TYPE_TARGET_MASK: u32 = 0x8;
144
145/// Exact value of [`Type`] `properties` when the underlying data refers to an SELinux type.
146///
147/// TODO: Eliminate `dead_code` guard.
148#[allow(dead_code)]
149pub(super) const TYPE_PROPERTIES_TYPE: u32 = 1;
150
151/// Exact value of [`Type`] `properties` when the underlying data refers to an SELinux alias.
152pub(super) const TYPE_PROPERTIES_ALIAS: u32 = 0;
153
154/// Exact value of [`Type`] `properties` when the underlying data refers to an SELinux attribute.
155pub(super) const TYPE_PROPERTIES_ATTRIBUTE: u32 = 0;
156
157/// [`SymbolList`] is an [`Array`] of items with the count of items determined by [`Metadata`] as
158/// [`Counted`].
159#[derive(Debug, PartialEq)]
160pub(super) struct SymbolList<PS: ParseStrategy, T>(Array<PS, PS::Output<Metadata>, Vec<T>>);
161
162impl<PS: ParseStrategy, T> Deref for SymbolList<PS, T> {
163    type Target = Array<PS, PS::Output<Metadata>, Vec<T>>;
164
165    fn deref(&self) -> &Self::Target {
166        &self.0
167    }
168}
169
170impl<PS: ParseStrategy, T> Parse<PS> for SymbolList<PS, T>
171where
172    Array<PS, PS::Output<Metadata>, Vec<T>>: Parse<PS>,
173{
174    type Error = <Array<PS, PS::Output<Metadata>, Vec<T>> as Parse<PS>>::Error;
175
176    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
177        let (array, tail) = Array::<PS, PS::Output<Metadata>, Vec<T>>::parse(bytes)?;
178        Ok((Self(array), tail))
179    }
180}
181
182impl<PS: ParseStrategy, T> Validate for SymbolList<PS, T>
183where
184    [T]: Validate,
185{
186    type Error = anyhow::Error;
187
188    /// [`SymbolList`] has no internal constraints beyond those imposed by [`Array`].
189    fn validate(&self) -> Result<(), Self::Error> {
190        PS::deref(&self.metadata).validate().map_err(Into::<anyhow::Error>::into)?;
191        self.data.as_slice().validate().map_err(Into::<anyhow::Error>::into)?;
192
193        Ok(())
194    }
195}
196
197/// Binary metadata prefix to [`SymbolList`] objects.
198#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
199#[repr(C, packed)]
200pub(super) struct Metadata {
201    /// The number of primary names referred to in the associated [`SymbolList`].
202    primary_names_count: le::U32,
203    /// The number of objects in the associated [`SymbolList`] [`Array`].
204    count: le::U32,
205}
206
207impl Metadata {
208    pub fn primary_names_count(&self) -> u32 {
209        self.primary_names_count.get()
210    }
211}
212
213impl Counted for Metadata {
214    /// The number of items that follow a [`Metadata`] is the value stored in the `metadata.count`
215    /// field.
216    fn count(&self) -> u32 {
217        self.count.get()
218    }
219}
220
221impl Validate for Metadata {
222    type Error = anyhow::Error;
223
224    /// TODO: Should there be an upper bound on `primary_names_count` or `count`?
225    fn validate(&self) -> Result<(), Self::Error> {
226        Ok(())
227    }
228}
229
230impl<PS: ParseStrategy> Validate for [CommonSymbol<PS>] {
231    type Error = <CommonSymbol<PS> as Validate>::Error;
232
233    /// [`CommonSymbols`] have no internal constraints beyond those imposed by individual
234    /// [`CommonSymbol`] objects.
235    fn validate(&self) -> Result<(), Self::Error> {
236        Ok(())
237    }
238}
239
240array_type!(CommonSymbol, PS, CommonSymbolMetadata<PS>, Permissions<PS>);
241
242array_type_validate_deref_none_data_vec!(CommonSymbol);
243
244impl<PS: ParseStrategy> CommonSymbol<PS> {
245    pub fn permissions(&self) -> &Permissions<PS> {
246        &self.data
247    }
248}
249
250pub(super) type CommonSymbols<PS> = Vec<CommonSymbol<PS>>;
251
252impl<PS: ParseStrategy> CommonSymbol<PS> {
253    /// Returns the name of this common symbol (a string), encoded a borrow of a byte slice. For
254    /// example, the policy statement `common file { common_file_perm }` induces a [`CommonSymbol`]
255    /// where `name_bytes() == "file".as_slice()`.
256    pub fn name_bytes(&self) -> &[u8] {
257        PS::deref_slice(&self.metadata.data)
258    }
259}
260
261impl<PS: ParseStrategy> Counted for CommonSymbol<PS>
262where
263    CommonSymbolMetadata<PS>: Parse<PS> + Validate,
264    Array<PS, PS::Output<CommonSymbolStaticMetadata>, PS::Slice<u8>>: Parse<PS>,
265    Array<PS, PS::Output<PermissionMetadata>, PS::Slice<u8>>: Parse<PS>,
266    Array<PS, CommonSymbolMetadata<PS>, Vec<Permission<PS>>>: Parse<PS>,
267    Vec<Permission<PS>>: ParseSlice<PS>,
268{
269    /// The count of items in the associated [`Permissions`] is exposed via
270    /// `CommonSymbolMetadata::count()`.
271    fn count(&self) -> u32 {
272        self.metadata.count()
273    }
274}
275
276impl<PS: ParseStrategy> ValidateArray<CommonSymbolMetadata<PS>, Permission<PS>>
277    for CommonSymbol<PS>
278{
279    type Error = anyhow::Error;
280
281    /// [`CommonSymbol`] have no internal constraints beyond those imposed by [`Array`].
282    fn validate_array<'a>(
283        _metadata: &'a CommonSymbolMetadata<PS>,
284        _data: &'a [Permission<PS>],
285    ) -> Result<(), Self::Error> {
286        Ok(())
287    }
288}
289
290array_type!(CommonSymbolMetadata, PS, PS::Output<CommonSymbolStaticMetadata>, PS::Slice<u8>);
291
292array_type_validate_deref_both!(CommonSymbolMetadata);
293
294impl<PS: ParseStrategy> Counted for CommonSymbolMetadata<PS> {
295    /// The count of items in the associated [`Permissions`] is stored in the associated
296    /// `CommonSymbolStaticMetadata::count` field.
297    fn count(&self) -> u32 {
298        PS::deref(&self.metadata).count.get()
299    }
300}
301
302impl<PS: ParseStrategy> ValidateArray<CommonSymbolStaticMetadata, u8> for CommonSymbolMetadata<PS> {
303    type Error = anyhow::Error;
304
305    /// Array of [`u8`] sized by [`CommonSymbolStaticMetadata`] requires no additional validation.
306    fn validate_array<'a>(
307        _metadata: &'a CommonSymbolStaticMetadata,
308        _data: &'a [u8],
309    ) -> Result<(), Self::Error> {
310        Ok(())
311    }
312}
313
314/// Static (that is, fixed-sized) metadata for a common symbol.
315#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
316#[repr(C, packed)]
317pub(super) struct CommonSymbolStaticMetadata {
318    /// The length of the `[u8]` key stored in the associated [`CommonSymbolMetadata`].
319    length: le::U32,
320    /// An integer that identifies this this common symbol, unique to this common symbol relative
321    /// to all common symbols and classes in this policy.
322    id: le::U32,
323    /// The number of primary names referred to by the associated [`CommonSymbol`].
324    primary_names_count: le::U32,
325    /// The number of items stored in the [`Permissions`] in the associated [`CommonSymbol`].
326    count: le::U32,
327}
328
329impl Validate for CommonSymbolStaticMetadata {
330    type Error = anyhow::Error;
331
332    /// TODO: Should there be an upper bound on `length`?
333    fn validate(&self) -> Result<(), Self::Error> {
334        Ok(())
335    }
336}
337
338impl Counted for CommonSymbolStaticMetadata {
339    /// The count of bytes in the `[u8]` in the associated [`CommonSymbolMetadata`].
340    fn count(&self) -> u32 {
341        self.length.get()
342    }
343}
344
345/// [`Permissions`] is a dynamically allocated slice (that is, [`Vec`]) of [`Permission`].
346pub(super) type Permissions<PS> = Vec<Permission<PS>>;
347
348impl<PS: ParseStrategy> Validate for Permissions<PS> {
349    type Error = anyhow::Error;
350
351    /// [`Permissions`] have no internal constraints beyond those imposed by individual
352    /// [`Permission`] objects.
353    fn validate(&self) -> Result<(), Self::Error> {
354        Ok(())
355    }
356}
357
358array_type!(Permission, PS, PS::Output<PermissionMetadata>, PS::Slice<u8>);
359
360array_type_validate_deref_both!(Permission);
361
362impl<PS: ParseStrategy> Permission<PS> {
363    /// Returns the name of this permission (a string), encoded a borrow of a byte slice. For
364    /// example the class named `"file"` class has a permission named `"entrypoint"` and the
365    /// `"process"` class has a permission named `"fork"`.
366    pub fn name_bytes(&self) -> &[u8] {
367        PS::deref_slice(&self.data)
368    }
369
370    /// Returns the ID of this permission in the scope of its associated class.
371    pub fn id(&self) -> ClassPermissionId {
372        ClassPermissionId(NonZeroU32::new(PS::deref(&self.metadata).id.get()).unwrap())
373    }
374}
375
376impl<PS: ParseStrategy> ValidateArray<PermissionMetadata, u8> for Permission<PS> {
377    type Error = anyhow::Error;
378
379    /// [`Permission`] has no internal constraints beyond those imposed by [`Array`].
380    fn validate_array<'a>(
381        _metadata: &'a PermissionMetadata,
382        _data: &'a [u8],
383    ) -> Result<(), Self::Error> {
384        Ok(())
385    }
386}
387
388#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
389#[repr(C, packed)]
390pub(super) struct PermissionMetadata {
391    /// The length of the `[u8]` in the associated [`Permission`].
392    length: le::U32,
393    id: le::U32,
394}
395
396impl Counted for PermissionMetadata {
397    /// The count of bytes in the `[u8]` in the associated [`Permission`].
398    fn count(&self) -> u32 {
399        self.length.get()
400    }
401}
402
403impl Validate for PermissionMetadata {
404    type Error = anyhow::Error;
405
406    /// TODO: Should there be an upper bound on `length`?
407    fn validate(&self) -> Result<(), Self::Error> {
408        Ok(())
409    }
410}
411
412/// The list of [`Constraints`] associated with a class.
413pub(super) type Constraints<PS> = Vec<Constraint<PS>>;
414
415impl<PS: ParseStrategy> Validate for Constraints<PS> {
416    type Error = anyhow::Error;
417
418    /// [`Constraints`] has no internal constraints beyond those imposed by individual
419    /// [`Constraint`] objects.
420    fn validate(&self) -> Result<(), Self::Error> {
421        Ok(())
422    }
423}
424
425/// A set of permissions and a boolean expression giving a constraint on those
426/// permissions, for a particular class. Corresponds to a single `constrain` or
427/// `mlsconstrain` statement in policy language.
428#[derive(Debug, PartialEq)]
429pub(super) struct Constraint<PS: ParseStrategy>
430where
431    ConstraintExpr<PS>: Debug + PartialEq,
432{
433    access_vector: PS::Output<le::U32>,
434    constraint_expr: ConstraintExpr<PS>,
435}
436
437impl<PS: ParseStrategy> Constraint<PS> {
438    pub(super) fn access_vector(&self) -> AccessVector {
439        AccessVector((*PS::deref(&self.access_vector)).get())
440    }
441
442    pub(super) fn constraint_expr(&self) -> &ConstraintExpr<PS> {
443        &self.constraint_expr
444    }
445}
446
447impl<PS: ParseStrategy> Parse<PS> for Constraint<PS>
448where
449    ConstraintExpr<PS>: Debug + PartialEq + Parse<PS>,
450{
451    type Error = anyhow::Error;
452
453    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
454        let tail = bytes;
455
456        let num_bytes = tail.len();
457        let (access_vector, tail) = PS::parse::<le::U32>(tail).ok_or_else(|| {
458            Into::<anyhow::Error>::into(ParseError::MissingData {
459                type_name: "AccessVector",
460                type_size: std::mem::size_of::<le::U32>(),
461                num_bytes,
462            })
463        })?;
464        let (constraint_expr, tail) = ConstraintExpr::parse(tail)
465            .map_err(|error| error.into() as anyhow::Error)
466            .context("parsing constraint expression")?;
467
468        Ok((Self { access_vector, constraint_expr }, tail))
469    }
470}
471
472// A [`ConstraintExpr`] describes a constraint expression, represented as a
473// postfix-ordered list of terms.
474array_type!(ConstraintExpr, PS, PS::Output<ConstraintTermCount>, ConstraintTerms<PS>);
475
476array_type_validate_deref_metadata_data_vec!(ConstraintExpr);
477
478impl<PS: ParseStrategy> ValidateArray<ConstraintTermCount, ConstraintTerm<PS>>
479    for ConstraintExpr<PS>
480{
481    type Error = anyhow::Error;
482
483    /// [`ConstraintExpr`] has no internal constraints beyond those imposed by
484    /// [`Array`]. The `ParsedPolicy::validate()` function separately validates
485    /// that the constraint expression is well-formed.
486    fn validate_array<'a>(
487        _metadata: &'a ConstraintTermCount,
488        _data: &'a [ConstraintTerm<PS>],
489    ) -> Result<(), Self::Error> {
490        Ok(())
491    }
492}
493
494impl<PS: ParseStrategy> ConstraintExpr<PS> {
495    pub(super) fn evaluate(
496        &self,
497        source_context: &SecurityContext,
498        target_context: &SecurityContext,
499    ) -> Result<bool, ConstraintError> {
500        evaluate_constraint(&self, source_context, target_context)
501    }
502
503    pub(super) fn constraint_terms(&self) -> &[ConstraintTerm<PS>] {
504        &self.data
505    }
506}
507
508#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
509#[repr(C, packed)]
510pub(super) struct ConstraintTermCount(le::U32);
511
512impl Counted for ConstraintTermCount {
513    fn count(&self) -> u32 {
514        self.0.get()
515    }
516}
517
518impl Validate for ConstraintTermCount {
519    type Error = anyhow::Error;
520
521    fn validate(&self) -> Result<(), Self::Error> {
522        Ok(())
523    }
524}
525
526impl<PS: ParseStrategy> Validate for ConstraintTerms<PS> {
527    type Error = anyhow::Error;
528
529    /// [`ConstraintTerms`] have no internal constraints beyond those imposed by
530    /// individual [`ConstraintTerm`] objects. The `ParsedPolicy::validate()`
531    /// function separately validates that the constraint expression is
532    /// well-formed.
533    fn validate(&self) -> Result<(), Self::Error> {
534        Ok(())
535    }
536}
537
538#[derive(Debug, PartialEq)]
539pub(super) struct ConstraintTerm<PS: ParseStrategy> {
540    metadata: PS::Output<ConstraintTermMetadata>,
541    names: Option<ExtensibleBitmap<PS>>,
542    names_type_set: Option<TypeSet<PS>>,
543}
544
545pub(super) type ConstraintTerms<PS> = Vec<ConstraintTerm<PS>>;
546
547impl<PS: ParseStrategy> Parse<PS> for ConstraintTerm<PS>
548where
549    ExtensibleBitmap<PS>: Parse<PS>,
550{
551    type Error = anyhow::Error;
552
553    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
554        let tail = bytes;
555
556        let (metadata, tail) = PS::parse::<ConstraintTermMetadata>(tail)
557            .context("parsing constraint term metadata")?;
558
559        let (names, names_type_set, tail) = match PS::deref(&metadata).constraint_term_type.get() {
560            CONSTRAINT_TERM_TYPE_EXPR_WITH_NAMES => {
561                let (names, tail) = ExtensibleBitmap::parse(tail)
562                    .map_err(Into::<anyhow::Error>::into)
563                    .context("parsing constraint term names")?;
564                let (names_type_set, tail) =
565                    TypeSet::parse(tail).context("parsing constraint term names type set")?;
566                (Some(names), Some(names_type_set), tail)
567            }
568            _ => (None, None, tail),
569        };
570
571        Ok((Self { metadata, names, names_type_set }, tail))
572    }
573}
574
575impl<PS: ParseStrategy> ConstraintTerm<PS> {
576    pub(super) fn constraint_term_type(&self) -> u32 {
577        PS::deref(&self.metadata).constraint_term_type.get()
578    }
579
580    pub(super) fn expr_operand_type(&self) -> u32 {
581        PS::deref(&self.metadata).expr_operand_type.get()
582    }
583
584    pub(super) fn expr_operator_type(&self) -> u32 {
585        PS::deref(&self.metadata).expr_operator_type.get()
586    }
587
588    pub(super) fn names(&self) -> Option<&ExtensibleBitmap<PS>> {
589        self.names.as_ref()
590    }
591
592    // TODO: https://fxbug.dev/372400976 - Unused, unsure if needed.
593    // Possibly becomes interesting when the policy contains type
594    // attributes.
595    #[allow(dead_code)]
596    pub(super) fn names_type_set(&self) -> &Option<TypeSet<PS>> {
597        &self.names_type_set
598    }
599}
600
601#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
602#[repr(C, packed)]
603pub(super) struct ConstraintTermMetadata {
604    constraint_term_type: le::U32,
605    expr_operand_type: le::U32,
606    expr_operator_type: le::U32,
607}
608
609impl Validate for ConstraintTermMetadata {
610    type Error = anyhow::Error;
611
612    /// Further validation is done by the `ParsedPolicy::validate()` function,
613    /// which separately validates that constraint expressions are well-formed.
614    fn validate(&self) -> Result<(), Self::Error> {
615        if !(self.constraint_term_type > 0
616            && self.constraint_term_type <= CONSTRAINT_TERM_TYPE_EXPR_WITH_NAMES)
617        {
618            return Err(anyhow!("invalid constraint term type"));
619        }
620        if !(self.constraint_term_type == CONSTRAINT_TERM_TYPE_EXPR
621            || self.constraint_term_type == CONSTRAINT_TERM_TYPE_EXPR_WITH_NAMES)
622        {
623            if self.expr_operand_type != 0 {
624                return Err(anyhow!(
625                    "invalid operand type {} for constraint term type {}",
626                    self.expr_operand_type,
627                    self.constraint_term_type
628                ));
629            }
630            if self.expr_operator_type != 0 {
631                return Err(anyhow!(
632                    "invalid operator type {} for constraint term type {}",
633                    self.expr_operator_type,
634                    self.constraint_term_type
635                ));
636            }
637        }
638        // TODO: https://fxbug.dev/372400976 - Consider validating operator
639        // and operand types for expr and expr-with-names terms.
640        Ok(())
641    }
642}
643
644#[derive(Debug, PartialEq)]
645pub(super) struct TypeSet<PS: ParseStrategy> {
646    types: ExtensibleBitmap<PS>,
647    negative_set: ExtensibleBitmap<PS>,
648    flags: PS::Output<le::U32>,
649}
650
651impl<PS: ParseStrategy> Parse<PS> for TypeSet<PS>
652where
653    ExtensibleBitmap<PS>: Parse<PS>,
654{
655    type Error = anyhow::Error;
656
657    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
658        let tail = bytes;
659
660        let (types, tail) = ExtensibleBitmap::parse(tail)
661            .map_err(Into::<anyhow::Error>::into)
662            .context("parsing type set types")?;
663
664        let (negative_set, tail) = ExtensibleBitmap::parse(tail)
665            .map_err(Into::<anyhow::Error>::into)
666            .context("parsing type set negative set")?;
667
668        let num_bytes = tail.len();
669        let (flags, tail) = PS::parse::<le::U32>(tail).ok_or_else(|| {
670            Into::<anyhow::Error>::into(ParseError::MissingData {
671                type_name: "TypeSetFlags",
672                type_size: std::mem::size_of::<le::U32>(),
673                num_bytes,
674            })
675        })?;
676
677        Ok((Self { types, negative_set, flags }, tail))
678    }
679}
680
681/// Locates a class named `name` among `classes`. Returns the first such class found, though policy
682/// validation should ensure that only one such class exists.
683pub(super) fn find_class_by_name<'a, PS: ParseStrategy>(
684    classes: &'a Classes<PS>,
685    name: &str,
686) -> Option<&'a Class<PS>> {
687    find_class_by_name_bytes(classes, name.as_bytes())
688}
689
690fn find_class_by_name_bytes<'a, PS: ParseStrategy>(
691    classes: &'a Classes<PS>,
692    name_bytes: &[u8],
693) -> Option<&'a Class<PS>> {
694    for cls in classes.into_iter() {
695        if cls.name_bytes() == name_bytes {
696            return Some(cls);
697        }
698    }
699
700    None
701}
702
703/// Locates a symbol named `name_bytes` among `common_symbols`. Returns
704/// the first such symbol found, though policy validation should ensure
705/// that only one exists.
706pub(super) fn find_common_symbol_by_name_bytes<'a, PS: ParseStrategy>(
707    common_symbols: &'a CommonSymbols<PS>,
708    name_bytes: &[u8],
709) -> Option<&'a CommonSymbol<PS>> {
710    for common_symbol in common_symbols.into_iter() {
711        if common_symbol.name_bytes() == name_bytes {
712            return Some(common_symbol);
713        }
714    }
715
716    None
717}
718
719impl<PS: ParseStrategy> Validate for [Class<PS>] {
720    type Error = anyhow::Error;
721
722    fn validate(&self) -> Result<(), Self::Error> {
723        // TODO: Validate internal consistency between consecutive [`Class`] instances.
724        for class in self {
725            // TODO: Validate `self.constraints` and `self.validate_transitions`.
726            class.defaults().validate().context("class defaults")?;
727        }
728        Ok(())
729    }
730}
731
732#[derive(Debug, PartialEq)]
733pub(super) struct Class<PS: ParseStrategy> {
734    constraints: ClassConstraints<PS>,
735    validate_transitions: ClassValidateTransitions<PS>,
736    defaults: PS::Output<ClassDefaults>,
737}
738
739pub(super) type Classes<PS> = Vec<Class<PS>>;
740
741impl<PS: ParseStrategy> Class<PS> {
742    /// Returns the name of the `common` from which this `class` inherits as a borrow of a byte
743    /// slice. For example, `common file { common_file_perm }`,
744    /// `class file inherits file { file_perm }` yields two [`Class`] objects, one that refers to a
745    /// permission named `"common_file_perm"` permission and has `self.common_name_bytes() == ""`,
746    /// and another that refers to a permission named `"file_perm"` and has
747    /// `self.common_name_bytes() == "file"`.
748    pub fn common_name_bytes(&self) -> &[u8] {
749        // `ClassCommonKey` is an `Array` of `[u8]` with metadata `ClassKey`, and
750        // `ClassKey::count()` returns the `common_key_length` field. That is, the `[u8]` string
751        // on `ClassCommonKey` is the "common key" (name in the inherited `common` statement) for
752        // this class.
753        let class_common_key: &ClassCommonKey<PS> = &self.constraints.metadata.metadata;
754        PS::deref_slice(&class_common_key.data)
755    }
756
757    /// Returns the name of this class as a borrow of a byte slice.
758    pub fn name_bytes(&self) -> &[u8] {
759        // `ClassKey` is an `Array` of `[u8]` with metadata `ClassMetadata`, and
760        // `ClassMetadata::count()` returns the `key_length` field. That is, the `[u8]` string on
761        // `ClassKey` is the "class key" (name in the `class` or `common` statement) for this class.
762        let class_key: &ClassKey<PS> = &self.constraints.metadata.metadata.metadata;
763        PS::deref_slice(&class_key.data)
764    }
765
766    /// Returns the id associated with this class. The id is used to index into collections
767    /// and bitmaps associated with this class. The id is 1-indexed, whereas most collections and
768    /// bitmaps are 0-indexed, so clients of this API will usually use `id - 1`.
769    pub fn id(&self) -> ClassId {
770        let class_metadata: &ClassMetadata =
771            &PS::deref(&self.constraints.metadata.metadata.metadata.metadata);
772        ClassId(NonZeroU32::new(class_metadata.id.get()).unwrap())
773    }
774
775    /// Returns the full listing of permissions used in this policy.
776    pub fn permissions(&self) -> &Permissions<PS> {
777        &self.constraints.metadata.data
778    }
779
780    /// Returns a list of permission masks and constraint expressions for this
781    /// class. The permissions in a given mask may be granted if the
782    /// corresponding constraint expression is satisfied.
783    ///
784    /// The same permission may appear in multiple entries in the returned list.
785    // TODO: https://fxbug.dev/372400976 - Is it accurate to change "may be
786    // granted to "are granted" above?
787    pub fn constraints(&self) -> &Vec<Constraint<PS>> {
788        &self.constraints.data
789    }
790
791    pub fn defaults(&self) -> &ClassDefaults {
792        PS::deref(&self.defaults)
793    }
794}
795
796impl<PS: ParseStrategy> Parse<PS> for Class<PS>
797where
798    ClassConstraints<PS>: Parse<PS>,
799    ClassValidateTransitions<PS>: Parse<PS>,
800{
801    type Error = anyhow::Error;
802
803    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
804        let tail = bytes;
805
806        let (constraints, tail) = ClassConstraints::parse(tail)
807            .map_err(Into::<anyhow::Error>::into)
808            .context("parsing class constraints")?;
809
810        let (validate_transitions, tail) = ClassValidateTransitions::parse(tail)
811            .map_err(Into::<anyhow::Error>::into)
812            .context("parsing class validate transitions")?;
813
814        let (defaults, tail) =
815            PS::parse::<ClassDefaults>(tail).context("parsing class defaults")?;
816
817        Ok((Self { constraints, validate_transitions, defaults }, tail))
818    }
819}
820
821#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
822#[repr(C, packed)]
823pub(super) struct ClassDefaults {
824    default_user: le::U32,
825    default_role: le::U32,
826    default_range: le::U32,
827    default_type: le::U32,
828}
829
830impl ClassDefaults {
831    pub fn user(&self) -> ClassDefault {
832        self.default_user.get().into()
833    }
834
835    pub fn role(&self) -> ClassDefault {
836        self.default_role.get().into()
837    }
838
839    pub fn range(&self) -> ClassDefaultRange {
840        self.default_range.get().into()
841    }
842
843    pub fn type_(&self) -> ClassDefault {
844        self.default_type.get().into()
845    }
846}
847
848impl Validate for ClassDefaults {
849    type Error = anyhow::Error;
850
851    fn validate(&self) -> Result<(), Self::Error> {
852        ClassDefault::validate(self.default_user.get()).context("default user")?;
853        ClassDefault::validate(self.default_role.get()).context("default role")?;
854        ClassDefault::validate(self.default_type.get()).context("default type")?;
855        ClassDefaultRange::validate(self.default_range.get()).context("default range")?;
856        Ok(())
857    }
858}
859
860#[derive(PartialEq)]
861pub(super) enum ClassDefault {
862    Unspecified,
863    Source,
864    Target,
865}
866
867impl ClassDefault {
868    pub(super) const DEFAULT_UNSPECIFIED: u32 = 0;
869    pub(super) const DEFAULT_SOURCE: u32 = 1;
870    pub(super) const DEFAULT_TARGET: u32 = 2;
871
872    fn validate(value: u32) -> Result<(), ValidateError> {
873        match value {
874            Self::DEFAULT_UNSPECIFIED | Self::DEFAULT_SOURCE | Self::DEFAULT_TARGET => Ok(()),
875            value => Err(ValidateError::InvalidClassDefault { value }),
876        }
877    }
878}
879
880impl From<u32> for ClassDefault {
881    fn from(value: u32) -> Self {
882        match value {
883            Self::DEFAULT_UNSPECIFIED => Self::Unspecified,
884            Self::DEFAULT_SOURCE => Self::Source,
885            Self::DEFAULT_TARGET => Self::Target,
886            v => panic!(
887                "invalid SELinux class default; expected {}, {}, or {}, but got {}",
888                Self::DEFAULT_UNSPECIFIED,
889                Self::DEFAULT_SOURCE,
890                Self::DEFAULT_TARGET,
891                v
892            ),
893        }
894    }
895}
896
897#[derive(PartialEq)]
898pub(super) enum ClassDefaultRange {
899    Unspecified,
900    SourceLow,
901    SourceHigh,
902    SourceLowHigh,
903    TargetLow,
904    TargetHigh,
905    TargetLowHigh,
906}
907
908impl ClassDefaultRange {
909    pub(super) const DEFAULT_UNSPECIFIED: u32 = 0;
910    pub(super) const DEFAULT_SOURCE_LOW: u32 = 1;
911    pub(super) const DEFAULT_SOURCE_HIGH: u32 = 2;
912    pub(super) const DEFAULT_SOURCE_LOW_HIGH: u32 = 3;
913    pub(super) const DEFAULT_TARGET_LOW: u32 = 4;
914    pub(super) const DEFAULT_TARGET_HIGH: u32 = 5;
915    pub(super) const DEFAULT_TARGET_LOW_HIGH: u32 = 6;
916    // TODO: Determine what this value means.
917    pub(super) const DEFAULT_UNKNOWN_USED_VALUE: u32 = 7;
918
919    fn validate(value: u32) -> Result<(), ValidateError> {
920        match value {
921            Self::DEFAULT_UNSPECIFIED
922            | Self::DEFAULT_SOURCE_LOW
923            | Self::DEFAULT_SOURCE_HIGH
924            | Self::DEFAULT_SOURCE_LOW_HIGH
925            | Self::DEFAULT_TARGET_LOW
926            | Self::DEFAULT_TARGET_HIGH
927            | Self::DEFAULT_TARGET_LOW_HIGH
928            | Self::DEFAULT_UNKNOWN_USED_VALUE => Ok(()),
929            value => Err(ValidateError::InvalidClassDefaultRange { value }),
930        }
931    }
932}
933
934impl From<u32> for ClassDefaultRange {
935    fn from(value: u32) -> Self {
936        match value {
937            Self::DEFAULT_UNSPECIFIED => Self::Unspecified,
938            Self::DEFAULT_SOURCE_LOW => Self::SourceLow,
939            Self::DEFAULT_SOURCE_HIGH => Self::SourceHigh,
940            Self::DEFAULT_SOURCE_LOW_HIGH => Self::SourceLowHigh,
941            Self::DEFAULT_TARGET_LOW => Self::TargetLow,
942            Self::DEFAULT_TARGET_HIGH => Self::TargetHigh,
943            Self::DEFAULT_TARGET_LOW_HIGH => Self::TargetLowHigh,
944            v => panic!(
945                "invalid SELinux MLS range default; expected one of {:?}, but got {}",
946                [
947                    Self::DEFAULT_UNSPECIFIED,
948                    Self::DEFAULT_SOURCE_LOW,
949                    Self::DEFAULT_SOURCE_HIGH,
950                    Self::DEFAULT_SOURCE_LOW_HIGH,
951                    Self::DEFAULT_TARGET_LOW,
952                    Self::DEFAULT_TARGET_HIGH,
953                    Self::DEFAULT_TARGET_LOW_HIGH,
954                ],
955                v
956            ),
957        }
958    }
959}
960
961array_type!(
962    ClassValidateTransitions,
963    PS,
964    PS::Output<ClassValidateTransitionsCount>,
965    ConstraintTerms<PS>
966);
967
968array_type_validate_deref_metadata_data_vec!(ClassValidateTransitions);
969
970impl<PS: ParseStrategy> ValidateArray<ClassValidateTransitionsCount, ConstraintTerm<PS>>
971    for ClassValidateTransitions<PS>
972{
973    type Error = anyhow::Error;
974
975    /// [`ClassValidateTransitions`] has no internal constraints beyond those imposed by [`Array`].
976    fn validate_array<'a>(
977        _metadata: &'a ClassValidateTransitionsCount,
978        _data: &'a [ConstraintTerm<PS>],
979    ) -> Result<(), Self::Error> {
980        Ok(())
981    }
982}
983
984#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
985#[repr(C, packed)]
986pub(super) struct ClassValidateTransitionsCount(le::U32);
987
988impl Counted for ClassValidateTransitionsCount {
989    fn count(&self) -> u32 {
990        self.0.get()
991    }
992}
993
994impl Validate for ClassValidateTransitionsCount {
995    type Error = anyhow::Error;
996
997    /// TODO: Should there be an upper bound on class validate transitions count?
998    fn validate(&self) -> Result<(), Self::Error> {
999        Ok(())
1000    }
1001}
1002
1003array_type!(ClassConstraints, PS, ClassPermissions<PS>, Constraints<PS>);
1004
1005array_type_validate_deref_none_data_vec!(ClassConstraints);
1006
1007impl<PS: ParseStrategy> ValidateArray<ClassPermissions<PS>, Constraint<PS>>
1008    for ClassConstraints<PS>
1009{
1010    type Error = anyhow::Error;
1011
1012    /// [`ClassConstraints`] has no internal constraints beyond those imposed by [`Array`].
1013    fn validate_array<'a>(
1014        _metadata: &'a ClassPermissions<PS>,
1015        _data: &'a [Constraint<PS>],
1016    ) -> Result<(), Self::Error> {
1017        Ok(())
1018    }
1019}
1020
1021array_type!(ClassPermissions, PS, ClassCommonKey<PS>, Permissions<PS>);
1022
1023array_type_validate_deref_none_data_vec!(ClassPermissions);
1024
1025impl<PS: ParseStrategy> ValidateArray<ClassCommonKey<PS>, Permission<PS>> for ClassPermissions<PS> {
1026    type Error = anyhow::Error;
1027
1028    /// [`ClassPermissions`] has no internal constraints beyond those imposed by [`Array`].
1029    fn validate_array<'a>(
1030        _metadata: &'a ClassCommonKey<PS>,
1031        _data: &'a [Permission<PS>],
1032    ) -> Result<(), Self::Error> {
1033        Ok(())
1034    }
1035}
1036
1037impl<PS: ParseStrategy> Counted for ClassPermissions<PS>
1038where
1039    ClassCommonKey<PS>: Parse<PS>,
1040    Array<PS, ClassKey<PS>, PS::Slice<u8>>: Parse<PS>,
1041    Array<PS, PS::Output<ClassMetadata>, PS::Slice<u8>>: Parse<PS>,
1042    ClassKey<PS>: Parse<PS>,
1043    Vec<Permission<PS>>: ParseSlice<PS>,
1044    Array<PS, PS::Output<PermissionMetadata>, PS::Slice<u8>>: Parse<PS>,
1045    Array<PS, ClassCommonKey<PS>, Vec<Permission<PS>>>: Parse<PS>,
1046{
1047    /// [`ClassPermissions`] acts as counted metadata for [`ClassConstraints`].
1048    fn count(&self) -> u32 {
1049        PS::deref(&self.metadata.metadata.metadata).constraint_count.get()
1050    }
1051}
1052
1053array_type!(ClassCommonKey, PS, ClassKey<PS>, PS::Slice<u8>);
1054
1055array_type_validate_deref_data!(ClassCommonKey);
1056
1057impl<PS: ParseStrategy> ValidateArray<ClassKey<PS>, u8> for ClassCommonKey<PS> {
1058    type Error = anyhow::Error;
1059
1060    /// [`ClassCommonKey`] has no internal constraints beyond those imposed by [`Array`].
1061    fn validate_array<'a>(_metadata: &'a ClassKey<PS>, _data: &'a [u8]) -> Result<(), Self::Error> {
1062        Ok(())
1063    }
1064}
1065
1066impl<PS: ParseStrategy> Counted for ClassCommonKey<PS>
1067where
1068    Array<PS, ClassKey<PS>, PS::Slice<u8>>: Parse<PS>,
1069    Array<PS, PS::Output<ClassMetadata>, PS::Slice<u8>>: Parse<PS>,
1070    ClassKey<PS>: Parse<PS>,
1071{
1072    /// [`ClassCommonKey`] acts as counted metadata for [`ClassPermissions`].
1073    fn count(&self) -> u32 {
1074        PS::deref(&self.metadata.metadata).elements_count.get()
1075    }
1076}
1077
1078array_type!(ClassKey, PS, PS::Output<ClassMetadata>, PS::Slice<u8>);
1079
1080array_type_validate_deref_both!(ClassKey);
1081
1082impl<PS: ParseStrategy> ValidateArray<ClassMetadata, u8> for ClassKey<PS> {
1083    type Error = anyhow::Error;
1084
1085    /// [`ClassKey`] has no internal constraints beyond those imposed by [`Array`].
1086    fn validate_array<'a>(
1087        _metadata: &'a ClassMetadata,
1088        _data: &'a [u8],
1089    ) -> Result<(), Self::Error> {
1090        Ok(())
1091    }
1092}
1093
1094impl<PS: ParseStrategy> Counted for ClassKey<PS>
1095where
1096    Array<PS, PS::Output<ClassMetadata>, PS::Slice<u8>>: Parse<PS>,
1097{
1098    /// [`ClassKey`] acts as counted metadata for [`ClassCommonKey`].
1099    fn count(&self) -> u32 {
1100        PS::deref(&self.metadata).common_key_length.get()
1101    }
1102}
1103
1104#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1105#[repr(C, packed)]
1106pub(super) struct ClassMetadata {
1107    key_length: le::U32,
1108    common_key_length: le::U32,
1109    id: le::U32,
1110    primary_names_count: le::U32,
1111    elements_count: le::U32,
1112    constraint_count: le::U32,
1113}
1114
1115impl Counted for ClassMetadata {
1116    fn count(&self) -> u32 {
1117        self.key_length.get()
1118    }
1119}
1120
1121impl Validate for ClassMetadata {
1122    type Error = anyhow::Error;
1123
1124    /// TODO: Should there be an upper bound `u32` values in [`ClassMetadata`]?
1125    fn validate(&self) -> Result<(), Self::Error> {
1126        if self.id.get() == 0 {
1127            return Err(ValidateError::NonOptionalIdIsZero.into());
1128        } else {
1129            Ok(())
1130        }
1131    }
1132}
1133
1134impl<PS: ParseStrategy> Validate for [Role<PS>] {
1135    type Error = anyhow::Error;
1136
1137    /// TODO: Validate internal consistency between consecutive [`Role`] instances.
1138    fn validate(&self) -> Result<(), Self::Error> {
1139        Ok(())
1140    }
1141}
1142
1143#[derive(Debug, PartialEq)]
1144pub(super) struct Role<PS: ParseStrategy> {
1145    metadata: RoleMetadata<PS>,
1146    role_dominates: ExtensibleBitmap<PS>,
1147    role_types: ExtensibleBitmap<PS>,
1148}
1149
1150impl<PS: ParseStrategy> Role<PS> {
1151    pub(super) fn id(&self) -> RoleId {
1152        RoleId(NonZeroU32::new(PS::deref(&self.metadata.metadata).id.get()).unwrap())
1153    }
1154
1155    pub(super) fn name_bytes(&self) -> &[u8] {
1156        PS::deref_slice(&self.metadata.data)
1157    }
1158}
1159
1160impl<PS: ParseStrategy> Parse<PS> for Role<PS>
1161where
1162    RoleMetadata<PS>: Parse<PS>,
1163    ExtensibleBitmap<PS>: Parse<PS>,
1164{
1165    type Error = anyhow::Error;
1166
1167    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1168        let tail = bytes;
1169
1170        let (metadata, tail) = RoleMetadata::parse(tail)
1171            .map_err(Into::<anyhow::Error>::into)
1172            .context("parsing role metadata")?;
1173
1174        let (role_dominates, tail) = ExtensibleBitmap::parse(tail)
1175            .map_err(Into::<anyhow::Error>::into)
1176            .context("parsing role dominates")?;
1177
1178        let (role_types, tail) = ExtensibleBitmap::parse(tail)
1179            .map_err(Into::<anyhow::Error>::into)
1180            .context("parsing role types")?;
1181
1182        Ok((Self { metadata, role_dominates, role_types }, tail))
1183    }
1184}
1185
1186array_type!(RoleMetadata, PS, PS::Output<RoleStaticMetadata>, PS::Slice<u8>);
1187
1188array_type_validate_deref_both!(RoleMetadata);
1189
1190impl<PS: ParseStrategy> ValidateArray<RoleStaticMetadata, u8> for RoleMetadata<PS> {
1191    type Error = anyhow::Error;
1192
1193    /// [`RoleMetadata`] has no internal constraints beyond those imposed by [`Array`].
1194    fn validate_array<'a>(
1195        _metadata: &'a RoleStaticMetadata,
1196        _data: &'a [u8],
1197    ) -> Result<(), Self::Error> {
1198        Ok(())
1199    }
1200}
1201
1202#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1203#[repr(C, packed)]
1204pub(super) struct RoleStaticMetadata {
1205    length: le::U32,
1206    id: le::U32,
1207    bounds: le::U32,
1208}
1209
1210impl Counted for RoleStaticMetadata {
1211    /// [`RoleStaticMetadata`] serves as [`Counted`] for a length-encoded `[u8]`.
1212    fn count(&self) -> u32 {
1213        self.length.get()
1214    }
1215}
1216
1217impl Validate for RoleStaticMetadata {
1218    type Error = anyhow::Error;
1219
1220    /// TODO: Should there be any constraints on `length`, `value`, or `bounds`?
1221    fn validate(&self) -> Result<(), Self::Error> {
1222        Ok(())
1223    }
1224}
1225
1226/// Returns whether `ty` is associated with `attr` via the mappings `attribute_maps`. Such
1227/// associations arise from policy statements of the form `typeattribute [ty] [attributes];` where
1228/// `attr` appears in the comma-separated list, `[attributes]`.
1229///
1230/// TODO: Eliminate `dead_code` guard.
1231#[allow(dead_code)]
1232pub(super) fn type_has_attribute<'a, PS: ParseStrategy>(
1233    ty: &'a Type<PS>,
1234    attr: &'a Type<PS>,
1235    attribute_maps: &Vec<ExtensibleBitmap<PS>>,
1236) -> bool {
1237    let type_id = PS::deref(&ty.metadata).id.get();
1238    let type_index = type_id - 1;
1239
1240    let attribute_id = PS::deref(&attr.metadata).id.get();
1241    let attribute_index = attribute_id - 1;
1242
1243    attribute_maps[type_index as usize].is_set(attribute_index)
1244}
1245
1246impl<PS: ParseStrategy> Validate for [Type<PS>] {
1247    type Error = anyhow::Error;
1248
1249    /// TODO: Validate internal consistency between consecutive [`Type`] instances.
1250    fn validate(&self) -> Result<(), Self::Error> {
1251        Ok(())
1252    }
1253}
1254
1255array_type!(Type, PS, PS::Output<TypeMetadata>, PS::Slice<u8>);
1256
1257array_type_validate_deref_both!(Type);
1258
1259impl<PS: ParseStrategy> Type<PS> {
1260    /// Returns the name of this type.
1261    pub fn name_bytes(&self) -> &[u8] {
1262        PS::deref_slice(&self.data)
1263    }
1264
1265    /// Returns the id associated with this type. The id is used to index into collections and
1266    /// bitmaps associated with this type. The id is 1-indexed, whereas most collections and
1267    /// bitmaps are 0-indexed, so clients of this API will usually use `id - 1`.
1268    pub fn id(&self) -> TypeId {
1269        TypeId(NonZeroU32::new(PS::deref(&self.metadata).id.get()).unwrap())
1270    }
1271
1272    /// Returns the Id of the bounding type, if any.
1273    pub fn bounded_by(&self) -> Option<TypeId> {
1274        NonZeroU32::new(PS::deref(&self.metadata).bounds.get()).map(|id| TypeId(id))
1275    }
1276
1277    /// Returns whether this type is from a `type [name];` policy statement.
1278    ///
1279    /// TODO: Eliminate `dead_code` guard.
1280    #[allow(dead_code)]
1281    pub fn is_type(&self) -> bool {
1282        PS::deref(&self.metadata).properties.get() == TYPE_PROPERTIES_TYPE
1283    }
1284
1285    /// Returns whether this type is from a `typealias [typename] alias [aliasname];` policy
1286    /// statement.
1287    ///
1288    /// TODO: Eliminate `dead_code` guard.
1289    #[allow(dead_code)]
1290    pub fn is_alias(&self) -> bool {
1291        PS::deref(&self.metadata).properties.get() == TYPE_PROPERTIES_ALIAS
1292    }
1293
1294    /// Returns whether this type is from an `attribute [name];` policy statement.
1295    ///
1296    /// TODO: Eliminate `dead_code` guard.
1297    #[allow(dead_code)]
1298    pub fn is_attribute(&self) -> bool {
1299        PS::deref(&self.metadata).properties.get() == TYPE_PROPERTIES_ATTRIBUTE
1300    }
1301}
1302
1303impl<PS: ParseStrategy> ValidateArray<TypeMetadata, u8> for Type<PS> {
1304    type Error = anyhow::Error;
1305
1306    /// TODO: Validate that `PS::deref(&self.data)` is an ascii string that contains a valid type name.
1307    fn validate_array<'a>(_metadata: &'a TypeMetadata, _data: &'a [u8]) -> Result<(), Self::Error> {
1308        Ok(())
1309    }
1310}
1311
1312#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1313#[repr(C, packed)]
1314pub(super) struct TypeMetadata {
1315    length: le::U32,
1316    id: le::U32,
1317    properties: le::U32,
1318    bounds: le::U32,
1319}
1320
1321impl Counted for TypeMetadata {
1322    fn count(&self) -> u32 {
1323        self.length.get()
1324    }
1325}
1326
1327impl Validate for TypeMetadata {
1328    type Error = anyhow::Error;
1329
1330    /// TODO: Validate [`TypeMetadata`] internals.
1331    fn validate(&self) -> Result<(), Self::Error> {
1332        Ok(())
1333    }
1334}
1335
1336impl<PS: ParseStrategy> Validate for [User<PS>] {
1337    type Error = anyhow::Error;
1338
1339    /// TODO: Validate internal consistency between consecutive [`User`] instances.
1340    fn validate(&self) -> Result<(), Self::Error> {
1341        Ok(())
1342    }
1343}
1344
1345#[derive(Debug, PartialEq)]
1346pub(super) struct User<PS: ParseStrategy> {
1347    user_data: UserData<PS>,
1348    roles: ExtensibleBitmap<PS>,
1349    expanded_range: MlsRange<PS>,
1350    default_level: MlsLevel<PS>,
1351}
1352
1353impl<PS: ParseStrategy> User<PS> {
1354    pub(super) fn id(&self) -> UserId {
1355        UserId(NonZeroU32::new(PS::deref(&self.user_data.metadata).id.get()).unwrap())
1356    }
1357
1358    pub(super) fn name_bytes(&self) -> &[u8] {
1359        PS::deref_slice(&self.user_data.data)
1360    }
1361
1362    pub(super) fn roles(&self) -> &ExtensibleBitmap<PS> {
1363        &self.roles
1364    }
1365
1366    pub(super) fn mls_range(&self) -> &MlsRange<PS> {
1367        &self.expanded_range
1368    }
1369}
1370
1371impl<PS: ParseStrategy> Parse<PS> for User<PS>
1372where
1373    UserData<PS>: Parse<PS>,
1374    ExtensibleBitmap<PS>: Parse<PS>,
1375{
1376    type Error = anyhow::Error;
1377
1378    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1379        let tail = bytes;
1380
1381        let (user_data, tail) = UserData::parse(tail)
1382            .map_err(Into::<anyhow::Error>::into)
1383            .context("parsing user data")?;
1384
1385        let (roles, tail) = ExtensibleBitmap::parse(tail)
1386            .map_err(Into::<anyhow::Error>::into)
1387            .context("parsing user roles")?;
1388
1389        let (expanded_range, tail) =
1390            MlsRange::parse(tail).context("parsing user expanded range")?;
1391
1392        let (default_level, tail) = MlsLevel::parse(tail).context("parsing user default level")?;
1393
1394        Ok((Self { user_data, roles, expanded_range, default_level }, tail))
1395    }
1396}
1397
1398array_type!(UserData, PS, PS::Output<UserMetadata>, PS::Slice<u8>);
1399
1400array_type_validate_deref_both!(UserData);
1401
1402impl<PS: ParseStrategy> ValidateArray<UserMetadata, u8> for UserData<PS> {
1403    type Error = anyhow::Error;
1404
1405    /// TODO: Validate consistency between [`UserMetadata`] in `self.metadata` and `[u8]` key in `self.data`.
1406    fn validate_array<'a>(_metadata: &'a UserMetadata, _data: &'a [u8]) -> Result<(), Self::Error> {
1407        Ok(())
1408    }
1409}
1410
1411#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1412#[repr(C, packed)]
1413pub(super) struct UserMetadata {
1414    length: le::U32,
1415    id: le::U32,
1416    bounds: le::U32,
1417}
1418
1419impl Counted for UserMetadata {
1420    fn count(&self) -> u32 {
1421        self.length.get()
1422    }
1423}
1424
1425impl Validate for UserMetadata {
1426    type Error = anyhow::Error;
1427
1428    /// TODO: Validate [`UserMetadata`] internals.
1429    fn validate(&self) -> Result<(), Self::Error> {
1430        Ok(())
1431    }
1432}
1433
1434#[derive(Debug, PartialEq)]
1435pub(super) struct MlsLevel<PS: ParseStrategy> {
1436    sensitivity: PS::Output<le::U32>,
1437    categories: ExtensibleBitmap<PS>,
1438}
1439
1440impl<PS: ParseStrategy> MlsLevel<PS> {
1441    pub fn category_ids(&self) -> impl Iterator<Item = CategoryId> + use<'_, PS> {
1442        self.categories.spans().flat_map(|span| {
1443            (span.low..=span.high).map(|i| CategoryId(NonZeroU32::new(i + 1).unwrap()))
1444        })
1445    }
1446}
1447
1448impl<PS: ParseStrategy> Parse<PS> for MlsLevel<PS>
1449where
1450    ExtensibleBitmap<PS>: Parse<PS>,
1451{
1452    type Error = anyhow::Error;
1453
1454    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1455        let tail = bytes;
1456
1457        let num_bytes = tail.len();
1458        let (sensitivity, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1459            type_name: "MlsLevelSensitivity",
1460            type_size: std::mem::size_of::<le::U32>(),
1461            num_bytes,
1462        })?;
1463
1464        let (categories, tail) = ExtensibleBitmap::parse(tail)
1465            .map_err(Into::<anyhow::Error>::into)
1466            .context("parsing mls level categories")?;
1467
1468        Ok((Self { sensitivity, categories }, tail))
1469    }
1470}
1471
1472impl<'a, PS: ParseStrategy> Level<'a, ExtensibleBitmapSpan, ExtensibleBitmapSpansIterator<'a, PS>>
1473    for MlsLevel<PS>
1474{
1475    fn sensitivity(&self) -> SensitivityId {
1476        SensitivityId(NonZeroU32::new(PS::deref(&self.sensitivity).get()).unwrap())
1477    }
1478
1479    fn category_spans(
1480        &'a self,
1481    ) -> CategoryIterator<ExtensibleBitmapSpan, ExtensibleBitmapSpansIterator<'a, PS>> {
1482        CategoryIterator::new(self.categories.spans())
1483    }
1484}
1485
1486#[derive(Debug, PartialEq)]
1487pub(super) struct MlsRange<PS: ParseStrategy> {
1488    count: PS::Output<le::U32>,
1489    low: MlsLevel<PS>,
1490    high: Option<MlsLevel<PS>>,
1491}
1492
1493impl<PS: ParseStrategy> MlsRange<PS> {
1494    pub fn low(&self) -> &MlsLevel<PS> {
1495        &self.low
1496    }
1497
1498    pub fn high(&self) -> &Option<MlsLevel<PS>> {
1499        &self.high
1500    }
1501}
1502
1503impl<PS: ParseStrategy> Parse<PS> for MlsRange<PS>
1504where
1505    ExtensibleBitmap<PS>: Parse<PS>,
1506{
1507    type Error = anyhow::Error;
1508
1509    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1510        let tail = bytes;
1511
1512        let num_bytes = tail.len();
1513        let (count, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1514            type_name: "MlsLevelCount",
1515            type_size: std::mem::size_of::<le::U32>(),
1516            num_bytes,
1517        })?;
1518
1519        // `MlsRange::parse()` cannot be implemented in terms of `MlsLevel::parse()` for the
1520        // low and optional high level, because of the order in which the sensitivity and
1521        // category bitmap fields appear.
1522        let num_bytes = tail.len();
1523        let (sensitivity_low, tail) =
1524            PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1525                type_name: "MlsLevelSensitivityLow",
1526                type_size: std::mem::size_of::<le::U32>(),
1527                num_bytes,
1528            })?;
1529
1530        let (low_categories, high_level, tail) = if PS::deref(&count).get() > 1 {
1531            let num_bytes = tail.len();
1532            let (sensitivity_high, tail) =
1533                PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1534                    type_name: "MlsLevelSensitivityHigh",
1535                    type_size: std::mem::size_of::<le::U32>(),
1536                    num_bytes,
1537                })?;
1538            let (low_categories, tail) = ExtensibleBitmap::parse(tail)
1539                .map_err(Into::<anyhow::Error>::into)
1540                .context("parsing mls range low categories")?;
1541            let (high_categories, tail) = ExtensibleBitmap::parse(tail)
1542                .map_err(Into::<anyhow::Error>::into)
1543                .context("parsing mls range high categories")?;
1544
1545            (
1546                low_categories,
1547                Some(MlsLevel { sensitivity: sensitivity_high, categories: high_categories }),
1548                tail,
1549            )
1550        } else {
1551            let (low_categories, tail) = ExtensibleBitmap::parse(tail)
1552                .map_err(Into::<anyhow::Error>::into)
1553                .context("parsing mls range low categories")?;
1554
1555            (low_categories, None, tail)
1556        };
1557
1558        Ok((
1559            Self {
1560                count,
1561                low: MlsLevel { sensitivity: sensitivity_low, categories: low_categories },
1562                high: high_level,
1563            },
1564            tail,
1565        ))
1566    }
1567}
1568
1569impl<PS: ParseStrategy> Validate for [ConditionalBoolean<PS>] {
1570    type Error = anyhow::Error;
1571
1572    /// TODO: Validate consistency of sequence of [`ConditionalBoolean`].
1573    fn validate(&self) -> Result<(), Self::Error> {
1574        Ok(())
1575    }
1576}
1577
1578array_type!(ConditionalBoolean, PS, PS::Output<ConditionalBooleanMetadata>, PS::Slice<u8>);
1579
1580array_type_validate_deref_both!(ConditionalBoolean);
1581
1582impl<PS: ParseStrategy> ValidateArray<ConditionalBooleanMetadata, u8> for ConditionalBoolean<PS> {
1583    type Error = anyhow::Error;
1584
1585    /// TODO: Validate consistency between [`ConditionalBooleanMetadata`] and `[u8]` key.
1586    fn validate_array<'a>(
1587        _metadata: &'a ConditionalBooleanMetadata,
1588        _data: &'a [u8],
1589    ) -> Result<(), Self::Error> {
1590        Ok(())
1591    }
1592}
1593
1594#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1595#[repr(C, packed)]
1596pub(super) struct ConditionalBooleanMetadata {
1597    id: le::U32,
1598    /// Current active value of this conditional boolean.
1599    active: le::U32,
1600    length: le::U32,
1601}
1602
1603impl ConditionalBooleanMetadata {
1604    /// Returns the active value for the boolean.
1605    pub(super) fn active(&self) -> bool {
1606        self.active != le::U32::ZERO
1607    }
1608}
1609
1610impl Counted for ConditionalBooleanMetadata {
1611    /// [`ConditionalBooleanMetadata`] used as `M` in of `Array<PS, PS::Output<M>, PS::Slice<u8>>` with
1612    /// `self.length` denoting size of inner `[u8]`.
1613    fn count(&self) -> u32 {
1614        self.length.get()
1615    }
1616}
1617
1618impl Validate for ConditionalBooleanMetadata {
1619    type Error = anyhow::Error;
1620
1621    /// TODO: Validate internal consistency of [`ConditionalBooleanMetadata`].
1622    fn validate(&self) -> Result<(), Self::Error> {
1623        Ok(())
1624    }
1625}
1626
1627impl<PS: ParseStrategy> Validate for [Sensitivity<PS>] {
1628    type Error = anyhow::Error;
1629
1630    /// TODO: Validate consistency of sequence of [`Sensitivity`].
1631    fn validate(&self) -> Result<(), Self::Error> {
1632        Ok(())
1633    }
1634}
1635
1636#[derive(Debug, PartialEq)]
1637pub(super) struct Sensitivity<PS: ParseStrategy> {
1638    metadata: SensitivityMetadata<PS>,
1639    level: MlsLevel<PS>,
1640}
1641
1642impl<PS: ParseStrategy> Sensitivity<PS> {
1643    pub fn id(&self) -> SensitivityId {
1644        SensitivityId(NonZeroU32::new(PS::deref(&self.level.sensitivity).get()).unwrap())
1645    }
1646
1647    pub fn name_bytes(&self) -> &[u8] {
1648        PS::deref_slice(&self.metadata.data)
1649    }
1650}
1651
1652impl<PS: ParseStrategy> Parse<PS> for Sensitivity<PS>
1653where
1654    SensitivityMetadata<PS>: Parse<PS>,
1655    MlsLevel<PS>: Parse<PS>,
1656{
1657    type Error = anyhow::Error;
1658
1659    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1660        let tail = bytes;
1661
1662        let (metadata, tail) = SensitivityMetadata::parse(tail)
1663            .map_err(Into::<anyhow::Error>::into)
1664            .context("parsing sensitivity metadata")?;
1665
1666        let (level, tail) = MlsLevel::parse(tail)
1667            .map_err(Into::<anyhow::Error>::into)
1668            .context("parsing sensitivity mls level")?;
1669
1670        Ok((Self { metadata, level }, tail))
1671    }
1672}
1673
1674impl<PS: ParseStrategy> Validate for Sensitivity<PS> {
1675    type Error = anyhow::Error;
1676
1677    /// TODO: Validate internal consistency of `self.metadata` and `self.level`.
1678    fn validate(&self) -> Result<(), Self::Error> {
1679        NonZeroU32::new(PS::deref(&self.level.sensitivity).get())
1680            .ok_or(ValidateError::NonOptionalIdIsZero)?;
1681        Ok(())
1682    }
1683}
1684
1685array_type!(SensitivityMetadata, PS, PS::Output<SensitivityStaticMetadata>, PS::Slice<u8>);
1686
1687array_type_validate_deref_both!(SensitivityMetadata);
1688
1689impl<PS: ParseStrategy> ValidateArray<SensitivityStaticMetadata, u8> for SensitivityMetadata<PS> {
1690    type Error = anyhow::Error;
1691
1692    /// TODO: Validate consistency between [`SensitivityMetadata`] and `[u8]` key.
1693    fn validate_array<'a>(
1694        _metadata: &'a SensitivityStaticMetadata,
1695        _data: &'a [u8],
1696    ) -> Result<(), Self::Error> {
1697        Ok(())
1698    }
1699}
1700
1701#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1702#[repr(C, packed)]
1703pub(super) struct SensitivityStaticMetadata {
1704    length: le::U32,
1705    is_alias: le::U32,
1706}
1707
1708impl Counted for SensitivityStaticMetadata {
1709    /// [`SensitivityStaticMetadata`] used as `M` in of `Array<PS, PS::Output<M>, PS::Slice<u8>>` with
1710    /// `self.length` denoting size of inner `[u8]`.
1711    fn count(&self) -> u32 {
1712        self.length.get()
1713    }
1714}
1715
1716impl Validate for SensitivityStaticMetadata {
1717    type Error = anyhow::Error;
1718
1719    /// TODO: Validate internal consistency of [`SensitivityStaticMetadata`].
1720    fn validate(&self) -> Result<(), Self::Error> {
1721        Ok(())
1722    }
1723}
1724
1725impl<PS: ParseStrategy> Validate for [Category<PS>] {
1726    type Error = anyhow::Error;
1727
1728    /// TODO: Validate consistency of sequence of [`Category`].
1729    fn validate(&self) -> Result<(), Self::Error> {
1730        Ok(())
1731    }
1732}
1733
1734array_type!(Category, PS, PS::Output<CategoryMetadata>, PS::Slice<u8>);
1735
1736array_type_validate_deref_both!(Category);
1737
1738impl<PS: ParseStrategy> Category<PS> {
1739    pub fn id(&self) -> CategoryId {
1740        CategoryId(NonZeroU32::new(PS::deref(&self.metadata).id.get()).unwrap())
1741    }
1742
1743    pub fn name_bytes(&self) -> &[u8] {
1744        PS::deref_slice(&self.data)
1745    }
1746}
1747
1748impl<PS: ParseStrategy> ValidateArray<CategoryMetadata, u8> for Category<PS> {
1749    type Error = anyhow::Error;
1750
1751    /// TODO: Validate consistency between [`CategoryMetadata`] and `[u8]` key.
1752    fn validate_array<'a>(
1753        _metadata: &'a CategoryMetadata,
1754        _data: &'a [u8],
1755    ) -> Result<(), Self::Error> {
1756        Ok(())
1757    }
1758}
1759
1760#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1761#[repr(C, packed)]
1762pub(super) struct CategoryMetadata {
1763    length: le::U32,
1764    id: le::U32,
1765    is_alias: le::U32,
1766}
1767
1768impl Counted for CategoryMetadata {
1769    /// [`CategoryMetadata`] used as `M` in of `Array<PS, PS::Output<M>, PS::Slice<u8>>` with
1770    /// `self.length` denoting size of inner `[u8]`.
1771    fn count(&self) -> u32 {
1772        self.length.get()
1773    }
1774}
1775
1776impl Validate for CategoryMetadata {
1777    type Error = anyhow::Error;
1778
1779    /// TODO: Validate internal consistency of [`CategoryMetadata`].
1780    fn validate(&self) -> Result<(), Self::Error> {
1781        NonZeroU32::new(self.id.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
1782        Ok(())
1783    }
1784}
1785
1786#[cfg(test)]
1787mod tests {
1788    use super::super::security_context::Level;
1789    use super::super::{parse_policy_by_reference, CategoryId, SensitivityId, UserId};
1790    use super::*;
1791
1792    use std::num::NonZeroU32;
1793
1794    #[test]
1795    fn mls_levels_for_user_context() {
1796        const TEST_POLICY: &[u8] = include_bytes! {"../../testdata/micro_policies/multiple_levels_and_categories_policy.pp"};
1797        let policy = parse_policy_by_reference(TEST_POLICY).unwrap().validate().unwrap();
1798        let parsed_policy = policy.0.parsed_policy();
1799
1800        let user = parsed_policy.user(UserId(NonZeroU32::new(1).expect("user with id 1")));
1801        let mls_range = user.mls_range();
1802        let low_level = mls_range.low();
1803        let high_level = mls_range.high().as_ref().expect("user 1 has a high mls level");
1804
1805        assert_eq!(low_level.sensitivity(), SensitivityId(NonZeroU32::new(1).unwrap()));
1806        assert_eq!(
1807            low_level.category_ids().collect::<Vec<_>>(),
1808            vec![CategoryId(NonZeroU32::new(1).unwrap())]
1809        );
1810
1811        assert_eq!(high_level.sensitivity(), SensitivityId(NonZeroU32::new(2).unwrap()));
1812        assert_eq!(
1813            high_level.category_ids().collect::<Vec<_>>(),
1814            vec![
1815                CategoryId(NonZeroU32::new(1).unwrap()),
1816                CategoryId(NonZeroU32::new(2).unwrap()),
1817                CategoryId(NonZeroU32::new(3).unwrap()),
1818                CategoryId(NonZeroU32::new(4).unwrap()),
1819                CategoryId(NonZeroU32::new(5).unwrap()),
1820            ]
1821        );
1822    }
1823
1824    #[test]
1825    fn parse_mls_constrain_statement() {
1826        let policy_bytes = include_bytes!("../../testdata/micro_policies/constraints_policy.pp");
1827        let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1828        let parsed_policy = &policy.0;
1829        Validate::validate(parsed_policy).expect("validate policy");
1830
1831        let class = find_class_by_name(parsed_policy.classes(), "class_mls_constraints")
1832            .expect("look up class");
1833        let constraints = class.constraints();
1834        assert_eq!(constraints.len(), 6);
1835        // Expected (`constraint_term_type`, `expr_operator_type`,
1836        // `expr_operand_type`) values for the single term of the
1837        // corresponding class constraint.
1838        //
1839        // NB. Constraint statements appear in reverse order in binary policy
1840        // vs. text policy.
1841        let expected = [
1842            (
1843                CONSTRAINT_TERM_TYPE_EXPR,
1844                CONSTRAINT_EXPR_OPERATOR_TYPE_INCOMP,
1845                CONSTRAINT_EXPR_OPERAND_TYPE_L1_H1,
1846            ),
1847            (
1848                CONSTRAINT_TERM_TYPE_EXPR,
1849                CONSTRAINT_EXPR_OPERATOR_TYPE_INCOMP,
1850                CONSTRAINT_EXPR_OPERAND_TYPE_H1_H2,
1851            ),
1852            (
1853                CONSTRAINT_TERM_TYPE_EXPR,
1854                CONSTRAINT_EXPR_OPERATOR_TYPE_DOMBY,
1855                CONSTRAINT_EXPR_OPERAND_TYPE_L1_H2,
1856            ),
1857            (
1858                CONSTRAINT_TERM_TYPE_EXPR,
1859                CONSTRAINT_EXPR_OPERATOR_TYPE_DOM,
1860                CONSTRAINT_EXPR_OPERAND_TYPE_H1_L2,
1861            ),
1862            (
1863                CONSTRAINT_TERM_TYPE_EXPR,
1864                CONSTRAINT_EXPR_OPERATOR_TYPE_NE,
1865                CONSTRAINT_EXPR_OPERAND_TYPE_L2_H2,
1866            ),
1867            (
1868                CONSTRAINT_TERM_TYPE_EXPR,
1869                CONSTRAINT_EXPR_OPERATOR_TYPE_EQ,
1870                CONSTRAINT_EXPR_OPERAND_TYPE_L1_L2,
1871            ),
1872        ];
1873        for (i, constraint) in constraints.iter().enumerate() {
1874            assert_eq!(constraint.access_vector(), AccessVector(1), "constraint {}", i);
1875            let terms = constraint.constraint_expr().constraint_terms();
1876            assert_eq!(terms.len(), 1, "constraint {}", i);
1877            let term = &terms[0];
1878            assert_eq!(
1879                (term.constraint_term_type(), term.expr_operator_type(), term.expr_operand_type()),
1880                expected[i],
1881                "constraint {}",
1882                i
1883            );
1884        }
1885    }
1886
1887    #[test]
1888    fn parse_constrain_statement() {
1889        let policy_bytes = include_bytes!("../../testdata/micro_policies/constraints_policy.pp");
1890        let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1891        let parsed_policy = &policy.0;
1892        Validate::validate(parsed_policy).expect("validate policy");
1893
1894        let class = find_class_by_name(parsed_policy.classes(), "class_constraint_nested")
1895            .expect("look up class");
1896        let constraints = class.constraints();
1897        assert_eq!(constraints.len(), 1);
1898        let constraint = &constraints[0];
1899        assert_eq!(constraint.access_vector(), AccessVector(1));
1900        let terms = constraint.constraint_expr().constraint_terms();
1901        assert_eq!(terms.len(), 8);
1902
1903        // Expected (`constraint_term_type`, `expr_operator_type`,
1904        // `expr_operand_type`) values for the constraint terms.
1905        //
1906        // NB. Constraint statements appear in reverse order in binary policy
1907        // vs. text policy.
1908        let expected = [
1909            (
1910                CONSTRAINT_TERM_TYPE_EXPR_WITH_NAMES,
1911                CONSTRAINT_EXPR_OPERATOR_TYPE_EQ,
1912                CONSTRAINT_EXPR_OPERAND_TYPE_USER
1913                    | CONSTRAINT_EXPR_WITH_NAMES_OPERAND_TYPE_TARGET_MASK,
1914            ),
1915            (
1916                CONSTRAINT_TERM_TYPE_EXPR,
1917                CONSTRAINT_EXPR_OPERATOR_TYPE_EQ,
1918                CONSTRAINT_EXPR_OPERAND_TYPE_ROLE,
1919            ),
1920            (CONSTRAINT_TERM_TYPE_AND_OPERATOR, 0, 0),
1921            (
1922                CONSTRAINT_TERM_TYPE_EXPR,
1923                CONSTRAINT_EXPR_OPERATOR_TYPE_EQ,
1924                CONSTRAINT_EXPR_OPERAND_TYPE_USER,
1925            ),
1926            (
1927                CONSTRAINT_TERM_TYPE_EXPR,
1928                CONSTRAINT_EXPR_OPERATOR_TYPE_EQ,
1929                CONSTRAINT_EXPR_OPERAND_TYPE_TYPE,
1930            ),
1931            (CONSTRAINT_TERM_TYPE_NOT_OPERATOR, 0, 0),
1932            (CONSTRAINT_TERM_TYPE_AND_OPERATOR, 0, 0),
1933            (CONSTRAINT_TERM_TYPE_OR_OPERATOR, 0, 0),
1934        ];
1935        for (i, term) in terms.iter().enumerate() {
1936            assert_eq!(
1937                (term.constraint_term_type(), term.expr_operator_type(), term.expr_operand_type()),
1938                expected[i],
1939                "term {}",
1940                i
1941            );
1942        }
1943    }
1944}