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    pub(super) fn types(&self) -> &ExtensibleBitmap<PS> {
1160        &self.role_types
1161    }
1162}
1163
1164impl<PS: ParseStrategy> Parse<PS> for Role<PS>
1165where
1166    RoleMetadata<PS>: Parse<PS>,
1167    ExtensibleBitmap<PS>: Parse<PS>,
1168{
1169    type Error = anyhow::Error;
1170
1171    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1172        let tail = bytes;
1173
1174        let (metadata, tail) = RoleMetadata::parse(tail)
1175            .map_err(Into::<anyhow::Error>::into)
1176            .context("parsing role metadata")?;
1177
1178        let (role_dominates, tail) = ExtensibleBitmap::parse(tail)
1179            .map_err(Into::<anyhow::Error>::into)
1180            .context("parsing role dominates")?;
1181
1182        let (role_types, tail) = ExtensibleBitmap::parse(tail)
1183            .map_err(Into::<anyhow::Error>::into)
1184            .context("parsing role types")?;
1185
1186        Ok((Self { metadata, role_dominates, role_types }, tail))
1187    }
1188}
1189
1190array_type!(RoleMetadata, PS, PS::Output<RoleStaticMetadata>, PS::Slice<u8>);
1191
1192array_type_validate_deref_both!(RoleMetadata);
1193
1194impl<PS: ParseStrategy> ValidateArray<RoleStaticMetadata, u8> for RoleMetadata<PS> {
1195    type Error = anyhow::Error;
1196
1197    /// [`RoleMetadata`] has no internal constraints beyond those imposed by [`Array`].
1198    fn validate_array<'a>(
1199        _metadata: &'a RoleStaticMetadata,
1200        _data: &'a [u8],
1201    ) -> Result<(), Self::Error> {
1202        Ok(())
1203    }
1204}
1205
1206#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1207#[repr(C, packed)]
1208pub(super) struct RoleStaticMetadata {
1209    length: le::U32,
1210    id: le::U32,
1211    bounds: le::U32,
1212}
1213
1214impl Counted for RoleStaticMetadata {
1215    /// [`RoleStaticMetadata`] serves as [`Counted`] for a length-encoded `[u8]`.
1216    fn count(&self) -> u32 {
1217        self.length.get()
1218    }
1219}
1220
1221impl Validate for RoleStaticMetadata {
1222    type Error = anyhow::Error;
1223
1224    /// TODO: Should there be any constraints on `length`, `value`, or `bounds`?
1225    fn validate(&self) -> Result<(), Self::Error> {
1226        Ok(())
1227    }
1228}
1229
1230/// Returns whether `ty` is associated with `attr` via the mappings `attribute_maps`. Such
1231/// associations arise from policy statements of the form `typeattribute [ty] [attributes];` where
1232/// `attr` appears in the comma-separated list, `[attributes]`.
1233///
1234/// TODO: Eliminate `dead_code` guard.
1235#[allow(dead_code)]
1236pub(super) fn type_has_attribute<'a, PS: ParseStrategy>(
1237    ty: &'a Type<PS>,
1238    attr: &'a Type<PS>,
1239    attribute_maps: &Vec<ExtensibleBitmap<PS>>,
1240) -> bool {
1241    let type_id = PS::deref(&ty.metadata).id.get();
1242    let type_index = type_id - 1;
1243
1244    let attribute_id = PS::deref(&attr.metadata).id.get();
1245    let attribute_index = attribute_id - 1;
1246
1247    attribute_maps[type_index as usize].is_set(attribute_index)
1248}
1249
1250impl<PS: ParseStrategy> Validate for [Type<PS>] {
1251    type Error = anyhow::Error;
1252
1253    /// TODO: Validate internal consistency between consecutive [`Type`] instances.
1254    fn validate(&self) -> Result<(), Self::Error> {
1255        Ok(())
1256    }
1257}
1258
1259array_type!(Type, PS, PS::Output<TypeMetadata>, PS::Slice<u8>);
1260
1261array_type_validate_deref_both!(Type);
1262
1263impl<PS: ParseStrategy> Type<PS> {
1264    /// Returns the name of this type.
1265    pub fn name_bytes(&self) -> &[u8] {
1266        PS::deref_slice(&self.data)
1267    }
1268
1269    /// Returns the id associated with this type. The id is used to index into collections and
1270    /// bitmaps associated with this type. The id is 1-indexed, whereas most collections and
1271    /// bitmaps are 0-indexed, so clients of this API will usually use `id - 1`.
1272    pub fn id(&self) -> TypeId {
1273        TypeId(NonZeroU32::new(PS::deref(&self.metadata).id.get()).unwrap())
1274    }
1275
1276    /// Returns the Id of the bounding type, if any.
1277    pub fn bounded_by(&self) -> Option<TypeId> {
1278        NonZeroU32::new(PS::deref(&self.metadata).bounds.get()).map(|id| TypeId(id))
1279    }
1280
1281    /// Returns whether this type is from a `type [name];` policy statement.
1282    ///
1283    /// TODO: Eliminate `dead_code` guard.
1284    #[allow(dead_code)]
1285    pub fn is_type(&self) -> bool {
1286        PS::deref(&self.metadata).properties.get() == TYPE_PROPERTIES_TYPE
1287    }
1288
1289    /// Returns whether this type is from a `typealias [typename] alias [aliasname];` policy
1290    /// statement.
1291    ///
1292    /// TODO: Eliminate `dead_code` guard.
1293    #[allow(dead_code)]
1294    pub fn is_alias(&self) -> bool {
1295        PS::deref(&self.metadata).properties.get() == TYPE_PROPERTIES_ALIAS
1296    }
1297
1298    /// Returns whether this type is from an `attribute [name];` policy statement.
1299    ///
1300    /// TODO: Eliminate `dead_code` guard.
1301    #[allow(dead_code)]
1302    pub fn is_attribute(&self) -> bool {
1303        PS::deref(&self.metadata).properties.get() == TYPE_PROPERTIES_ATTRIBUTE
1304    }
1305}
1306
1307impl<PS: ParseStrategy> ValidateArray<TypeMetadata, u8> for Type<PS> {
1308    type Error = anyhow::Error;
1309
1310    /// TODO: Validate that `PS::deref(&self.data)` is an ascii string that contains a valid type name.
1311    fn validate_array<'a>(_metadata: &'a TypeMetadata, _data: &'a [u8]) -> Result<(), Self::Error> {
1312        Ok(())
1313    }
1314}
1315
1316#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1317#[repr(C, packed)]
1318pub(super) struct TypeMetadata {
1319    length: le::U32,
1320    id: le::U32,
1321    properties: le::U32,
1322    bounds: le::U32,
1323}
1324
1325impl Counted for TypeMetadata {
1326    fn count(&self) -> u32 {
1327        self.length.get()
1328    }
1329}
1330
1331impl Validate for TypeMetadata {
1332    type Error = anyhow::Error;
1333
1334    /// TODO: Validate [`TypeMetadata`] internals.
1335    fn validate(&self) -> Result<(), Self::Error> {
1336        Ok(())
1337    }
1338}
1339
1340impl<PS: ParseStrategy> Validate for [User<PS>] {
1341    type Error = anyhow::Error;
1342
1343    /// TODO: Validate internal consistency between consecutive [`User`] instances.
1344    fn validate(&self) -> Result<(), Self::Error> {
1345        Ok(())
1346    }
1347}
1348
1349#[derive(Debug, PartialEq)]
1350pub(super) struct User<PS: ParseStrategy> {
1351    user_data: UserData<PS>,
1352    roles: ExtensibleBitmap<PS>,
1353    expanded_range: MlsRange<PS>,
1354    default_level: MlsLevel<PS>,
1355}
1356
1357impl<PS: ParseStrategy> User<PS> {
1358    pub(super) fn id(&self) -> UserId {
1359        UserId(NonZeroU32::new(PS::deref(&self.user_data.metadata).id.get()).unwrap())
1360    }
1361
1362    pub(super) fn name_bytes(&self) -> &[u8] {
1363        PS::deref_slice(&self.user_data.data)
1364    }
1365
1366    pub(super) fn roles(&self) -> &ExtensibleBitmap<PS> {
1367        &self.roles
1368    }
1369
1370    pub(super) fn mls_range(&self) -> &MlsRange<PS> {
1371        &self.expanded_range
1372    }
1373}
1374
1375impl<PS: ParseStrategy> Parse<PS> for User<PS>
1376where
1377    UserData<PS>: Parse<PS>,
1378    ExtensibleBitmap<PS>: Parse<PS>,
1379{
1380    type Error = anyhow::Error;
1381
1382    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1383        let tail = bytes;
1384
1385        let (user_data, tail) = UserData::parse(tail)
1386            .map_err(Into::<anyhow::Error>::into)
1387            .context("parsing user data")?;
1388
1389        let (roles, tail) = ExtensibleBitmap::parse(tail)
1390            .map_err(Into::<anyhow::Error>::into)
1391            .context("parsing user roles")?;
1392
1393        let (expanded_range, tail) =
1394            MlsRange::parse(tail).context("parsing user expanded range")?;
1395
1396        let (default_level, tail) = MlsLevel::parse(tail).context("parsing user default level")?;
1397
1398        Ok((Self { user_data, roles, expanded_range, default_level }, tail))
1399    }
1400}
1401
1402array_type!(UserData, PS, PS::Output<UserMetadata>, PS::Slice<u8>);
1403
1404array_type_validate_deref_both!(UserData);
1405
1406impl<PS: ParseStrategy> ValidateArray<UserMetadata, u8> for UserData<PS> {
1407    type Error = anyhow::Error;
1408
1409    /// TODO: Validate consistency between [`UserMetadata`] in `self.metadata` and `[u8]` key in `self.data`.
1410    fn validate_array<'a>(_metadata: &'a UserMetadata, _data: &'a [u8]) -> Result<(), Self::Error> {
1411        Ok(())
1412    }
1413}
1414
1415#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1416#[repr(C, packed)]
1417pub(super) struct UserMetadata {
1418    length: le::U32,
1419    id: le::U32,
1420    bounds: le::U32,
1421}
1422
1423impl Counted for UserMetadata {
1424    fn count(&self) -> u32 {
1425        self.length.get()
1426    }
1427}
1428
1429impl Validate for UserMetadata {
1430    type Error = anyhow::Error;
1431
1432    /// TODO: Validate [`UserMetadata`] internals.
1433    fn validate(&self) -> Result<(), Self::Error> {
1434        Ok(())
1435    }
1436}
1437
1438#[derive(Debug, PartialEq)]
1439pub(super) struct MlsLevel<PS: ParseStrategy> {
1440    sensitivity: PS::Output<le::U32>,
1441    categories: ExtensibleBitmap<PS>,
1442}
1443
1444impl<PS: ParseStrategy> MlsLevel<PS> {
1445    pub fn category_ids(&self) -> impl Iterator<Item = CategoryId> + use<'_, PS> {
1446        self.categories.spans().flat_map(|span| {
1447            (span.low..=span.high).map(|i| CategoryId(NonZeroU32::new(i + 1).unwrap()))
1448        })
1449    }
1450}
1451
1452impl<PS: ParseStrategy> Parse<PS> for MlsLevel<PS>
1453where
1454    ExtensibleBitmap<PS>: Parse<PS>,
1455{
1456    type Error = anyhow::Error;
1457
1458    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1459        let tail = bytes;
1460
1461        let num_bytes = tail.len();
1462        let (sensitivity, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1463            type_name: "MlsLevelSensitivity",
1464            type_size: std::mem::size_of::<le::U32>(),
1465            num_bytes,
1466        })?;
1467
1468        let (categories, tail) = ExtensibleBitmap::parse(tail)
1469            .map_err(Into::<anyhow::Error>::into)
1470            .context("parsing mls level categories")?;
1471
1472        Ok((Self { sensitivity, categories }, tail))
1473    }
1474}
1475
1476impl<'a, PS: ParseStrategy> Level<'a, ExtensibleBitmapSpan, ExtensibleBitmapSpansIterator<'a, PS>>
1477    for MlsLevel<PS>
1478{
1479    fn sensitivity(&self) -> SensitivityId {
1480        SensitivityId(NonZeroU32::new(PS::deref(&self.sensitivity).get()).unwrap())
1481    }
1482
1483    fn category_spans(
1484        &'a self,
1485    ) -> CategoryIterator<ExtensibleBitmapSpan, ExtensibleBitmapSpansIterator<'a, PS>> {
1486        CategoryIterator::new(self.categories.spans())
1487    }
1488}
1489
1490#[derive(Debug, PartialEq)]
1491pub(super) struct MlsRange<PS: ParseStrategy> {
1492    count: PS::Output<le::U32>,
1493    low: MlsLevel<PS>,
1494    high: Option<MlsLevel<PS>>,
1495}
1496
1497impl<PS: ParseStrategy> MlsRange<PS> {
1498    pub fn low(&self) -> &MlsLevel<PS> {
1499        &self.low
1500    }
1501
1502    pub fn high(&self) -> &Option<MlsLevel<PS>> {
1503        &self.high
1504    }
1505}
1506
1507impl<PS: ParseStrategy> Parse<PS> for MlsRange<PS>
1508where
1509    ExtensibleBitmap<PS>: Parse<PS>,
1510{
1511    type Error = anyhow::Error;
1512
1513    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1514        let tail = bytes;
1515
1516        let num_bytes = tail.len();
1517        let (count, tail) = PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1518            type_name: "MlsLevelCount",
1519            type_size: std::mem::size_of::<le::U32>(),
1520            num_bytes,
1521        })?;
1522
1523        // `MlsRange::parse()` cannot be implemented in terms of `MlsLevel::parse()` for the
1524        // low and optional high level, because of the order in which the sensitivity and
1525        // category bitmap fields appear.
1526        let num_bytes = tail.len();
1527        let (sensitivity_low, tail) =
1528            PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1529                type_name: "MlsLevelSensitivityLow",
1530                type_size: std::mem::size_of::<le::U32>(),
1531                num_bytes,
1532            })?;
1533
1534        let (low_categories, high_level, tail) = if PS::deref(&count).get() > 1 {
1535            let num_bytes = tail.len();
1536            let (sensitivity_high, tail) =
1537                PS::parse::<le::U32>(tail).ok_or(ParseError::MissingData {
1538                    type_name: "MlsLevelSensitivityHigh",
1539                    type_size: std::mem::size_of::<le::U32>(),
1540                    num_bytes,
1541                })?;
1542            let (low_categories, tail) = ExtensibleBitmap::parse(tail)
1543                .map_err(Into::<anyhow::Error>::into)
1544                .context("parsing mls range low categories")?;
1545            let (high_categories, tail) = ExtensibleBitmap::parse(tail)
1546                .map_err(Into::<anyhow::Error>::into)
1547                .context("parsing mls range high categories")?;
1548
1549            (
1550                low_categories,
1551                Some(MlsLevel { sensitivity: sensitivity_high, categories: high_categories }),
1552                tail,
1553            )
1554        } else {
1555            let (low_categories, tail) = ExtensibleBitmap::parse(tail)
1556                .map_err(Into::<anyhow::Error>::into)
1557                .context("parsing mls range low categories")?;
1558
1559            (low_categories, None, tail)
1560        };
1561
1562        Ok((
1563            Self {
1564                count,
1565                low: MlsLevel { sensitivity: sensitivity_low, categories: low_categories },
1566                high: high_level,
1567            },
1568            tail,
1569        ))
1570    }
1571}
1572
1573impl<PS: ParseStrategy> Validate for [ConditionalBoolean<PS>] {
1574    type Error = anyhow::Error;
1575
1576    /// TODO: Validate consistency of sequence of [`ConditionalBoolean`].
1577    fn validate(&self) -> Result<(), Self::Error> {
1578        Ok(())
1579    }
1580}
1581
1582array_type!(ConditionalBoolean, PS, PS::Output<ConditionalBooleanMetadata>, PS::Slice<u8>);
1583
1584array_type_validate_deref_both!(ConditionalBoolean);
1585
1586impl<PS: ParseStrategy> ValidateArray<ConditionalBooleanMetadata, u8> for ConditionalBoolean<PS> {
1587    type Error = anyhow::Error;
1588
1589    /// TODO: Validate consistency between [`ConditionalBooleanMetadata`] and `[u8]` key.
1590    fn validate_array<'a>(
1591        _metadata: &'a ConditionalBooleanMetadata,
1592        _data: &'a [u8],
1593    ) -> Result<(), Self::Error> {
1594        Ok(())
1595    }
1596}
1597
1598#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1599#[repr(C, packed)]
1600pub(super) struct ConditionalBooleanMetadata {
1601    id: le::U32,
1602    /// Current active value of this conditional boolean.
1603    active: le::U32,
1604    length: le::U32,
1605}
1606
1607impl ConditionalBooleanMetadata {
1608    /// Returns the active value for the boolean.
1609    pub(super) fn active(&self) -> bool {
1610        self.active != le::U32::ZERO
1611    }
1612}
1613
1614impl Counted for ConditionalBooleanMetadata {
1615    /// [`ConditionalBooleanMetadata`] used as `M` in of `Array<PS, PS::Output<M>, PS::Slice<u8>>` with
1616    /// `self.length` denoting size of inner `[u8]`.
1617    fn count(&self) -> u32 {
1618        self.length.get()
1619    }
1620}
1621
1622impl Validate for ConditionalBooleanMetadata {
1623    type Error = anyhow::Error;
1624
1625    /// TODO: Validate internal consistency of [`ConditionalBooleanMetadata`].
1626    fn validate(&self) -> Result<(), Self::Error> {
1627        Ok(())
1628    }
1629}
1630
1631impl<PS: ParseStrategy> Validate for [Sensitivity<PS>] {
1632    type Error = anyhow::Error;
1633
1634    /// TODO: Validate consistency of sequence of [`Sensitivity`].
1635    fn validate(&self) -> Result<(), Self::Error> {
1636        Ok(())
1637    }
1638}
1639
1640#[derive(Debug, PartialEq)]
1641pub(super) struct Sensitivity<PS: ParseStrategy> {
1642    metadata: SensitivityMetadata<PS>,
1643    level: MlsLevel<PS>,
1644}
1645
1646impl<PS: ParseStrategy> Sensitivity<PS> {
1647    pub fn id(&self) -> SensitivityId {
1648        SensitivityId(NonZeroU32::new(PS::deref(&self.level.sensitivity).get()).unwrap())
1649    }
1650
1651    pub fn name_bytes(&self) -> &[u8] {
1652        PS::deref_slice(&self.metadata.data)
1653    }
1654}
1655
1656impl<PS: ParseStrategy> Parse<PS> for Sensitivity<PS>
1657where
1658    SensitivityMetadata<PS>: Parse<PS>,
1659    MlsLevel<PS>: Parse<PS>,
1660{
1661    type Error = anyhow::Error;
1662
1663    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
1664        let tail = bytes;
1665
1666        let (metadata, tail) = SensitivityMetadata::parse(tail)
1667            .map_err(Into::<anyhow::Error>::into)
1668            .context("parsing sensitivity metadata")?;
1669
1670        let (level, tail) = MlsLevel::parse(tail)
1671            .map_err(Into::<anyhow::Error>::into)
1672            .context("parsing sensitivity mls level")?;
1673
1674        Ok((Self { metadata, level }, tail))
1675    }
1676}
1677
1678impl<PS: ParseStrategy> Validate for Sensitivity<PS> {
1679    type Error = anyhow::Error;
1680
1681    /// TODO: Validate internal consistency of `self.metadata` and `self.level`.
1682    fn validate(&self) -> Result<(), Self::Error> {
1683        NonZeroU32::new(PS::deref(&self.level.sensitivity).get())
1684            .ok_or(ValidateError::NonOptionalIdIsZero)?;
1685        Ok(())
1686    }
1687}
1688
1689array_type!(SensitivityMetadata, PS, PS::Output<SensitivityStaticMetadata>, PS::Slice<u8>);
1690
1691array_type_validate_deref_both!(SensitivityMetadata);
1692
1693impl<PS: ParseStrategy> ValidateArray<SensitivityStaticMetadata, u8> for SensitivityMetadata<PS> {
1694    type Error = anyhow::Error;
1695
1696    /// TODO: Validate consistency between [`SensitivityMetadata`] and `[u8]` key.
1697    fn validate_array<'a>(
1698        _metadata: &'a SensitivityStaticMetadata,
1699        _data: &'a [u8],
1700    ) -> Result<(), Self::Error> {
1701        Ok(())
1702    }
1703}
1704
1705#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1706#[repr(C, packed)]
1707pub(super) struct SensitivityStaticMetadata {
1708    length: le::U32,
1709    is_alias: le::U32,
1710}
1711
1712impl Counted for SensitivityStaticMetadata {
1713    /// [`SensitivityStaticMetadata`] used as `M` in of `Array<PS, PS::Output<M>, PS::Slice<u8>>` with
1714    /// `self.length` denoting size of inner `[u8]`.
1715    fn count(&self) -> u32 {
1716        self.length.get()
1717    }
1718}
1719
1720impl Validate for SensitivityStaticMetadata {
1721    type Error = anyhow::Error;
1722
1723    /// TODO: Validate internal consistency of [`SensitivityStaticMetadata`].
1724    fn validate(&self) -> Result<(), Self::Error> {
1725        Ok(())
1726    }
1727}
1728
1729impl<PS: ParseStrategy> Validate for [Category<PS>] {
1730    type Error = anyhow::Error;
1731
1732    /// TODO: Validate consistency of sequence of [`Category`].
1733    fn validate(&self) -> Result<(), Self::Error> {
1734        Ok(())
1735    }
1736}
1737
1738array_type!(Category, PS, PS::Output<CategoryMetadata>, PS::Slice<u8>);
1739
1740array_type_validate_deref_both!(Category);
1741
1742impl<PS: ParseStrategy> Category<PS> {
1743    pub fn id(&self) -> CategoryId {
1744        CategoryId(NonZeroU32::new(PS::deref(&self.metadata).id.get()).unwrap())
1745    }
1746
1747    pub fn name_bytes(&self) -> &[u8] {
1748        PS::deref_slice(&self.data)
1749    }
1750}
1751
1752impl<PS: ParseStrategy> ValidateArray<CategoryMetadata, u8> for Category<PS> {
1753    type Error = anyhow::Error;
1754
1755    /// TODO: Validate consistency between [`CategoryMetadata`] and `[u8]` key.
1756    fn validate_array<'a>(
1757        _metadata: &'a CategoryMetadata,
1758        _data: &'a [u8],
1759    ) -> Result<(), Self::Error> {
1760        Ok(())
1761    }
1762}
1763
1764#[derive(Clone, Debug, KnownLayout, FromBytes, Immutable, PartialEq, Unaligned)]
1765#[repr(C, packed)]
1766pub(super) struct CategoryMetadata {
1767    length: le::U32,
1768    id: le::U32,
1769    is_alias: le::U32,
1770}
1771
1772impl Counted for CategoryMetadata {
1773    /// [`CategoryMetadata`] used as `M` in of `Array<PS, PS::Output<M>, PS::Slice<u8>>` with
1774    /// `self.length` denoting size of inner `[u8]`.
1775    fn count(&self) -> u32 {
1776        self.length.get()
1777    }
1778}
1779
1780impl Validate for CategoryMetadata {
1781    type Error = anyhow::Error;
1782
1783    /// TODO: Validate internal consistency of [`CategoryMetadata`].
1784    fn validate(&self) -> Result<(), Self::Error> {
1785        NonZeroU32::new(self.id.get()).ok_or(ValidateError::NonOptionalIdIsZero)?;
1786        Ok(())
1787    }
1788}
1789
1790#[cfg(test)]
1791mod tests {
1792    use super::super::security_context::Level;
1793    use super::super::{parse_policy_by_reference, CategoryId, SensitivityId, UserId};
1794    use super::*;
1795
1796    use std::num::NonZeroU32;
1797
1798    #[test]
1799    fn mls_levels_for_user_context() {
1800        const TEST_POLICY: &[u8] = include_bytes! {"../../testdata/micro_policies/multiple_levels_and_categories_policy.pp"};
1801        let policy = parse_policy_by_reference(TEST_POLICY).unwrap().validate().unwrap();
1802        let parsed_policy = policy.0.parsed_policy();
1803
1804        let user = parsed_policy.user(UserId(NonZeroU32::new(1).expect("user with id 1")));
1805        let mls_range = user.mls_range();
1806        let low_level = mls_range.low();
1807        let high_level = mls_range.high().as_ref().expect("user 1 has a high mls level");
1808
1809        assert_eq!(low_level.sensitivity(), SensitivityId(NonZeroU32::new(1).unwrap()));
1810        assert_eq!(
1811            low_level.category_ids().collect::<Vec<_>>(),
1812            vec![CategoryId(NonZeroU32::new(1).unwrap())]
1813        );
1814
1815        assert_eq!(high_level.sensitivity(), SensitivityId(NonZeroU32::new(2).unwrap()));
1816        assert_eq!(
1817            high_level.category_ids().collect::<Vec<_>>(),
1818            vec![
1819                CategoryId(NonZeroU32::new(1).unwrap()),
1820                CategoryId(NonZeroU32::new(2).unwrap()),
1821                CategoryId(NonZeroU32::new(3).unwrap()),
1822                CategoryId(NonZeroU32::new(4).unwrap()),
1823                CategoryId(NonZeroU32::new(5).unwrap()),
1824            ]
1825        );
1826    }
1827
1828    #[test]
1829    fn parse_mls_constrain_statement() {
1830        let policy_bytes = include_bytes!("../../testdata/micro_policies/constraints_policy.pp");
1831        let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1832        let parsed_policy = &policy.0;
1833        Validate::validate(parsed_policy).expect("validate policy");
1834
1835        let class = find_class_by_name(parsed_policy.classes(), "class_mls_constraints")
1836            .expect("look up class");
1837        let constraints = class.constraints();
1838        assert_eq!(constraints.len(), 6);
1839        // Expected (`constraint_term_type`, `expr_operator_type`,
1840        // `expr_operand_type`) values for the single term of the
1841        // corresponding class constraint.
1842        //
1843        // NB. Constraint statements appear in reverse order in binary policy
1844        // vs. text policy.
1845        let expected = [
1846            (
1847                CONSTRAINT_TERM_TYPE_EXPR,
1848                CONSTRAINT_EXPR_OPERATOR_TYPE_INCOMP,
1849                CONSTRAINT_EXPR_OPERAND_TYPE_L1_H1,
1850            ),
1851            (
1852                CONSTRAINT_TERM_TYPE_EXPR,
1853                CONSTRAINT_EXPR_OPERATOR_TYPE_INCOMP,
1854                CONSTRAINT_EXPR_OPERAND_TYPE_H1_H2,
1855            ),
1856            (
1857                CONSTRAINT_TERM_TYPE_EXPR,
1858                CONSTRAINT_EXPR_OPERATOR_TYPE_DOMBY,
1859                CONSTRAINT_EXPR_OPERAND_TYPE_L1_H2,
1860            ),
1861            (
1862                CONSTRAINT_TERM_TYPE_EXPR,
1863                CONSTRAINT_EXPR_OPERATOR_TYPE_DOM,
1864                CONSTRAINT_EXPR_OPERAND_TYPE_H1_L2,
1865            ),
1866            (
1867                CONSTRAINT_TERM_TYPE_EXPR,
1868                CONSTRAINT_EXPR_OPERATOR_TYPE_NE,
1869                CONSTRAINT_EXPR_OPERAND_TYPE_L2_H2,
1870            ),
1871            (
1872                CONSTRAINT_TERM_TYPE_EXPR,
1873                CONSTRAINT_EXPR_OPERATOR_TYPE_EQ,
1874                CONSTRAINT_EXPR_OPERAND_TYPE_L1_L2,
1875            ),
1876        ];
1877        for (i, constraint) in constraints.iter().enumerate() {
1878            assert_eq!(constraint.access_vector(), AccessVector(1), "constraint {}", i);
1879            let terms = constraint.constraint_expr().constraint_terms();
1880            assert_eq!(terms.len(), 1, "constraint {}", i);
1881            let term = &terms[0];
1882            assert_eq!(
1883                (term.constraint_term_type(), term.expr_operator_type(), term.expr_operand_type()),
1884                expected[i],
1885                "constraint {}",
1886                i
1887            );
1888        }
1889    }
1890
1891    #[test]
1892    fn parse_constrain_statement() {
1893        let policy_bytes = include_bytes!("../../testdata/micro_policies/constraints_policy.pp");
1894        let policy = parse_policy_by_reference(policy_bytes.as_slice()).expect("parse policy");
1895        let parsed_policy = &policy.0;
1896        Validate::validate(parsed_policy).expect("validate policy");
1897
1898        let class = find_class_by_name(parsed_policy.classes(), "class_constraint_nested")
1899            .expect("look up class");
1900        let constraints = class.constraints();
1901        assert_eq!(constraints.len(), 1);
1902        let constraint = &constraints[0];
1903        assert_eq!(constraint.access_vector(), AccessVector(1));
1904        let terms = constraint.constraint_expr().constraint_terms();
1905        assert_eq!(terms.len(), 8);
1906
1907        // Expected (`constraint_term_type`, `expr_operator_type`,
1908        // `expr_operand_type`) values for the constraint terms.
1909        //
1910        // NB. Constraint statements appear in reverse order in binary policy
1911        // vs. text policy.
1912        let expected = [
1913            (
1914                CONSTRAINT_TERM_TYPE_EXPR_WITH_NAMES,
1915                CONSTRAINT_EXPR_OPERATOR_TYPE_EQ,
1916                CONSTRAINT_EXPR_OPERAND_TYPE_USER
1917                    | CONSTRAINT_EXPR_WITH_NAMES_OPERAND_TYPE_TARGET_MASK,
1918            ),
1919            (
1920                CONSTRAINT_TERM_TYPE_EXPR,
1921                CONSTRAINT_EXPR_OPERATOR_TYPE_EQ,
1922                CONSTRAINT_EXPR_OPERAND_TYPE_ROLE,
1923            ),
1924            (CONSTRAINT_TERM_TYPE_AND_OPERATOR, 0, 0),
1925            (
1926                CONSTRAINT_TERM_TYPE_EXPR,
1927                CONSTRAINT_EXPR_OPERATOR_TYPE_EQ,
1928                CONSTRAINT_EXPR_OPERAND_TYPE_USER,
1929            ),
1930            (
1931                CONSTRAINT_TERM_TYPE_EXPR,
1932                CONSTRAINT_EXPR_OPERATOR_TYPE_EQ,
1933                CONSTRAINT_EXPR_OPERAND_TYPE_TYPE,
1934            ),
1935            (CONSTRAINT_TERM_TYPE_NOT_OPERATOR, 0, 0),
1936            (CONSTRAINT_TERM_TYPE_AND_OPERATOR, 0, 0),
1937            (CONSTRAINT_TERM_TYPE_OR_OPERATOR, 0, 0),
1938        ];
1939        for (i, term) in terms.iter().enumerate() {
1940            assert_eq!(
1941                (term.constraint_term_type(), term.expr_operator_type(), term.expr_operand_type()),
1942                expected[i],
1943                "term {}",
1944                i
1945            );
1946        }
1947    }
1948}