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