selinux/policy/
parsed_policy.rs

1// Copyright 2024 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 crate::NullessByteStr;
6
7use super::arrays::{
8    AccessVectorRules, ConditionalNodes, Context, DeprecatedFilenameTransitions,
9    FilenameTransitionList, FilenameTransitions, FsUses, GenericFsContexts, IPv6Nodes,
10    InfinitiBandEndPorts, InfinitiBandPartitionKeys, InitialSids, NamedContextPairs, Nodes, Ports,
11    RangeTransitions, RoleAllow, RoleAllows, RoleTransition, RoleTransitions, SimpleArray,
12    MIN_POLICY_VERSION_FOR_INFINITIBAND_PARTITION_KEY, XPERMS_TYPE_IOCTL_PREFIXES,
13    XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES,
14};
15use super::error::{ParseError, ValidateError};
16use super::extensible_bitmap::ExtensibleBitmap;
17use super::metadata::{Config, Counts, HandleUnknown, Magic, PolicyVersion, Signature};
18use super::parser::ParseStrategy;
19use super::security_context::{Level, SecurityContext};
20use super::symbols::{
21    Category, Class, Classes, CommonSymbol, CommonSymbols, ConditionalBoolean, MlsLevel, Role,
22    Sensitivity, SymbolList, Type, User,
23};
24use super::{
25    AccessDecision, AccessVector, CategoryId, ClassId, IoctlAccessDecision, Parse, RoleId,
26    SensitivityId, TypeId, UserId, Validate, XpermsBitmap, SELINUX_AVD_FLAGS_PERMISSIVE,
27};
28
29use anyhow::Context as _;
30use std::collections::HashSet;
31use std::fmt::Debug;
32use std::hash::Hash;
33use zerocopy::little_endian as le;
34
35/// A parsed binary policy.
36#[derive(Debug)]
37pub struct ParsedPolicy<PS: ParseStrategy> {
38    /// A distinctive number that acts as a binary format-specific header for SELinux binary policy
39    /// files.
40    magic: PS::Output<Magic>,
41    /// A length-encoded string, "SE Linux", which identifies this policy as an SE Linux policy.
42    signature: Signature<PS>,
43    /// The policy format version number. Different version may support different policy features.
44    policy_version: PS::Output<PolicyVersion>,
45    /// Whole-policy configuration, such as how to handle queries against unknown classes.
46    config: Config<PS>,
47    /// High-level counts of subsequent policy elements.
48    counts: PS::Output<Counts>,
49    policy_capabilities: ExtensibleBitmap<PS>,
50    permissive_map: ExtensibleBitmap<PS>,
51    /// Common permissions that can be mixed in to classes.
52    common_symbols: SymbolList<PS, CommonSymbol<PS>>,
53    /// The set of classes referenced by this policy.
54    classes: SymbolList<PS, Class<PS>>,
55    /// The set of roles referenced by this policy.
56    roles: SymbolList<PS, Role<PS>>,
57    /// The set of types referenced by this policy.
58    types: SymbolList<PS, Type<PS>>,
59    /// The set of users referenced by this policy.
60    users: SymbolList<PS, User<PS>>,
61    /// The set of dynamically adjustable booleans referenced by this policy.
62    conditional_booleans: SymbolList<PS, ConditionalBoolean<PS>>,
63    /// The set of sensitivity levels referenced by this policy.
64    sensitivities: SymbolList<PS, Sensitivity<PS>>,
65    /// The set of categories referenced by this policy.
66    categories: SymbolList<PS, Category<PS>>,
67    /// The set of access vector rules referenced by this policy.
68    access_vector_rules: SimpleArray<PS, AccessVectorRules<PS>>,
69    conditional_lists: SimpleArray<PS, ConditionalNodes<PS>>,
70    /// The set of role transitions to apply when instantiating new objects.
71    role_transitions: RoleTransitions<PS>,
72    /// The set of role transitions allowed by policy.
73    role_allowlist: RoleAllows<PS>,
74    filename_transition_list: FilenameTransitionList<PS>,
75    initial_sids: SimpleArray<PS, InitialSids<PS>>,
76    filesystems: SimpleArray<PS, NamedContextPairs<PS>>,
77    ports: SimpleArray<PS, Ports<PS>>,
78    network_interfaces: SimpleArray<PS, NamedContextPairs<PS>>,
79    nodes: SimpleArray<PS, Nodes<PS>>,
80    fs_uses: SimpleArray<PS, FsUses<PS>>,
81    ipv6_nodes: SimpleArray<PS, IPv6Nodes<PS>>,
82    infinitiband_partition_keys: Option<SimpleArray<PS, InfinitiBandPartitionKeys<PS>>>,
83    infinitiband_end_ports: Option<SimpleArray<PS, InfinitiBandEndPorts<PS>>>,
84    /// A set of labeling statements to apply to given filesystems and/or their subdirectories.
85    /// Corresponds to the `genfscon` labeling statement in the policy.
86    generic_fs_contexts: SimpleArray<PS, GenericFsContexts<PS>>,
87    range_transitions: SimpleArray<PS, RangeTransitions<PS>>,
88    /// Extensible bitmaps that encode associations between types and attributes.
89    attribute_maps: Vec<ExtensibleBitmap<PS>>,
90}
91
92impl<PS: ParseStrategy> ParsedPolicy<PS> {
93    /// The policy version stored in the underlying binary policy.
94    pub fn policy_version(&self) -> u32 {
95        PS::deref(&self.policy_version).policy_version()
96    }
97
98    /// The way "unknown" policy decisions should be handed according to the underlying binary
99    /// policy.
100    pub fn handle_unknown(&self) -> HandleUnknown {
101        self.config.handle_unknown()
102    }
103
104    /// Computes the access granted to `source_type` on `target_type`, for the specified
105    /// `target_class`. The result is a set of access vectors with bits set for each
106    /// `target_class` permission, describing which permissions are allowed, and
107    /// which should have access checks audit-logged when denied, or allowed.
108    ///
109    /// An [`AccessDecision`] is accumulated, starting from no permissions to be granted,
110    /// nor audit-logged if allowed, and all permissions to be audit-logged if denied.
111    /// Permissions that are explicitly `allow`ed, but that are subject to unsatisfied
112    /// constraints, are removed from the allowed set. Matching policy statements then
113    /// add permissions to the granted & audit-allow sets, or remove them from the
114    /// audit-deny set.
115    pub(super) fn compute_access_decision(
116        &self,
117        source_context: &SecurityContext,
118        target_context: &SecurityContext,
119        target_class: &Class<PS>,
120    ) -> AccessDecision {
121        let mut access_decision = self.compute_explicitly_allowed(
122            source_context.type_(),
123            target_context.type_(),
124            target_class,
125        );
126        access_decision.allow -=
127            self.compute_denied_by_constraints(source_context, target_context, target_class);
128        access_decision
129    }
130
131    /// Computes the access granted to `source_type` on `target_type`, for the specified
132    /// `target_class`. The result is a set of access vectors with bits set for each
133    /// `target_class` permission, describing which permissions are explicitly allowed,
134    /// and which should have access checks audit-logged when denied, or allowed.
135    pub(super) fn compute_explicitly_allowed(
136        &self,
137        source_type: TypeId,
138        target_type: TypeId,
139        target_class: &Class<PS>,
140    ) -> AccessDecision {
141        let target_class_id = target_class.id();
142
143        let mut computed_access_vector = AccessVector::NONE;
144        let mut computed_audit_allow = AccessVector::NONE;
145        let mut computed_audit_deny = AccessVector::ALL;
146
147        for access_vector_rule in self.access_vector_rules.data.iter() {
148            // Ignore `access_vector_rule` entries not relayed to "allow" or
149            // audit statements.
150            //
151            // TODO: https://fxbug.dev/379657220 - Can an `access_vector_rule`
152            // entry express e.g. both "allow" and "auditallow" at the same
153            // time?
154            if !access_vector_rule.is_allow()
155                && !access_vector_rule.is_auditallow()
156                && !access_vector_rule.is_dontaudit()
157            {
158                continue;
159            }
160
161            // Concern ourselves only with `allow [source-type] [target-type]:[class] [...];`
162            // policy statements where `[class]` matches `target_class_id`.
163            if access_vector_rule.target_class() != target_class_id {
164                continue;
165            }
166
167            // Note: Perform bitmap lookups last: they are the most expensive comparison operation.
168
169            // Note: Type ids start at 1, but are 0-indexed in bitmaps: hence the `type - 1` bitmap
170            // lookups below.
171
172            // Concern ourselves only with `allow [source-type] [...];` policy statements where
173            // `[source-type]` is associated with `source_type_id`.
174            let source_attribute_bitmap: &ExtensibleBitmap<PS> =
175                &self.attribute_maps[(source_type.0.get() - 1) as usize];
176            if !source_attribute_bitmap.is_set(access_vector_rule.source_type().0.get() - 1) {
177                continue;
178            }
179
180            // Concern ourselves only with `allow [source-type] [target-type][...];` policy
181            // statements where `[target-type]` is associated with `target_type_id`.
182            let target_attribute_bitmap: &ExtensibleBitmap<PS> =
183                &self.attribute_maps[(target_type.0.get() - 1) as usize];
184            if !target_attribute_bitmap.is_set(access_vector_rule.target_type().0.get() - 1) {
185                continue;
186            }
187
188            // Multiple attributes may be associated with source/target types. Accumulate
189            // explicitly allowed permissions into `computed_access_vector`.
190            if let Some(access_vector) = access_vector_rule.access_vector() {
191                if access_vector_rule.is_allow() {
192                    // `access_vector` has bits set for each permission allowed by this rule.
193                    computed_access_vector |= access_vector;
194                } else if access_vector_rule.is_auditallow() {
195                    // `access_vector` has bits set for each permission to audit when allowed.
196                    computed_audit_allow |= access_vector;
197                } else if access_vector_rule.is_dontaudit() {
198                    // `access_vector` has bits cleared for each permission not to audit on denial.
199                    computed_audit_deny &= access_vector;
200                }
201            }
202        }
203
204        // TODO: https://fxbug.dev/362706116 - Collate the auditallow & auditdeny sets.
205        let mut flags = 0;
206        if self.permissive_types().is_set(source_type.0.get()) {
207            flags |= SELINUX_AVD_FLAGS_PERMISSIVE;
208        }
209        AccessDecision {
210            allow: computed_access_vector,
211            auditallow: computed_audit_allow,
212            auditdeny: computed_audit_deny,
213            flags,
214            todo_bug: None,
215        }
216    }
217
218    /// A permission is denied if it matches at least one unsatisfied constraint.
219    fn compute_denied_by_constraints(
220        &self,
221        source_context: &SecurityContext,
222        target_context: &SecurityContext,
223        target_class: &Class<PS>,
224    ) -> AccessVector {
225        let mut denied = AccessVector::NONE;
226        for constraint in target_class.constraints().iter() {
227            match constraint.constraint_expr().evaluate(source_context, target_context) {
228                Err(err) => {
229                    unreachable!("validated constraint expression failed to evaluate: {:?}", err)
230                }
231                Ok(false) => denied |= constraint.access_vector(),
232                Ok(true) => {}
233            }
234        }
235        denied
236    }
237
238    /// Computes the ioctl extended permissions that should be allowed, audited when allowed, and
239    /// audited when denied, for a given source context, target context, target class, and ioctl
240    /// prefix byte.
241    ///
242    /// If there is an `allowxperm` rule for a particular source, target, and class, then only the
243    /// named xperms should be allowed for that tuple. If there is no such `allowxperm` rule, then
244    /// all xperms should be allowed for that tuple. (In both cases, the allow is conditional on the
245    /// `ioctl` permission being allowed, but that should be checked separately before calling this
246    /// function.)
247    pub(super) fn compute_ioctl_access_decision(
248        &self,
249        source_context: &SecurityContext,
250        target_context: &SecurityContext,
251        target_class: &Class<PS>,
252        ioctl_prefix: u8,
253    ) -> IoctlAccessDecision {
254        let target_class_id = target_class.id();
255
256        let mut explicit_allow: Option<XpermsBitmap> = None;
257        let mut auditallow = XpermsBitmap::NONE;
258        let mut auditdeny = XpermsBitmap::ALL;
259
260        for access_vector_rule in self.access_vector_rules.data.iter() {
261            if !access_vector_rule.is_allowxperm()
262                && !access_vector_rule.is_auditallowxperm()
263                && !access_vector_rule.is_dontauditxperm()
264            {
265                continue;
266            }
267            if access_vector_rule.target_class() != target_class_id {
268                continue;
269            }
270            let source_attribute_bitmap: &ExtensibleBitmap<PS> =
271                &self.attribute_maps[(source_context.type_().0.get() - 1) as usize];
272            if !source_attribute_bitmap.is_set(access_vector_rule.source_type().0.get() - 1) {
273                continue;
274            }
275            let target_attribute_bitmap: &ExtensibleBitmap<PS> =
276                &self.attribute_maps[(target_context.type_().0.get() - 1) as usize];
277            if !target_attribute_bitmap.is_set(access_vector_rule.target_type().0.get() - 1) {
278                continue;
279            }
280
281            if let Some(xperms) = access_vector_rule.extended_permissions() {
282                // Only filter ioctls if there is at least one `allowxperm` rule for any ioctl
283                // prefix.
284                if access_vector_rule.is_allowxperm() {
285                    explicit_allow.get_or_insert(XpermsBitmap::NONE);
286                }
287                // If the rule applies to ioctls with prefix `ioctl_prefix`, get a bitmap
288                // of the ioctl postfixes named in the rule.
289                let bitmap_if_prefix_matches = match xperms.xperms_type {
290                    XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES => (xperms.xperms_optional_prefix
291                        == ioctl_prefix)
292                        .then_some(&xperms.xperms_bitmap),
293                    XPERMS_TYPE_IOCTL_PREFIXES => {
294                        xperms.xperms_bitmap.contains(ioctl_prefix).then_some(&XpermsBitmap::ALL)
295                    }
296                    _ => unreachable!("invalid xperms_type in validated ExtendedPermissions"),
297                };
298                let Some(xperms_bitmap) = bitmap_if_prefix_matches else {
299                    continue;
300                };
301                if access_vector_rule.is_allowxperm() {
302                    (*explicit_allow.get_or_insert(XpermsBitmap::NONE)) |= xperms_bitmap;
303                }
304                if access_vector_rule.is_auditallowxperm() {
305                    auditallow |= xperms_bitmap;
306                }
307                if access_vector_rule.is_dontauditxperm() {
308                    auditdeny -= xperms_bitmap;
309                }
310            }
311        }
312        let allow = explicit_allow.unwrap_or(XpermsBitmap::ALL);
313        IoctlAccessDecision { allow, auditallow, auditdeny }
314    }
315
316    /// Returns the policy entry for the specified initial Security Context.
317    pub(super) fn initial_context(&self, id: crate::InitialSid) -> &Context<PS> {
318        let id = le::U32::from(id as u32);
319        // [`InitialSids`] validates that all `InitialSid` values are defined by the policy.
320        &self.initial_sids.data.iter().find(|initial| initial.id() == id).unwrap().context()
321    }
322
323    /// Returns the `User` structure for the requested Id. Valid policies include definitions
324    /// for all the Ids they refer to internally; supply some other Id will trigger a panic.
325    pub(super) fn user(&self, id: UserId) -> &User<PS> {
326        self.users.data.iter().find(|x| x.id() == id).unwrap()
327    }
328
329    /// Returns the named user, if present in the policy.
330    pub(super) fn user_by_name(&self, name: &str) -> Option<&User<PS>> {
331        self.users.data.iter().find(|x| x.name_bytes() == name.as_bytes())
332    }
333
334    /// Returns the `Role` structure for the requested Id. Valid policies include definitions
335    /// for all the Ids they refer to internally; supply some other Id will trigger a panic.
336    pub(super) fn role(&self, id: RoleId) -> &Role<PS> {
337        self.roles.data.iter().find(|x| x.id() == id).unwrap()
338    }
339
340    /// Returns the named role, if present in the policy.
341    pub(super) fn role_by_name(&self, name: &str) -> Option<&Role<PS>> {
342        self.roles.data.iter().find(|x| x.name_bytes() == name.as_bytes())
343    }
344
345    /// Returns the `Type` structure for the requested Id. Valid policies include definitions
346    /// for all the Ids they refer to internally; supply some other Id will trigger a panic.
347    pub(super) fn type_(&self, id: TypeId) -> &Type<PS> {
348        self.types.data.iter().find(|x| x.id() == id).unwrap()
349    }
350
351    /// Returns the named type, if present in the policy.
352    pub(super) fn type_by_name(&self, name: &str) -> Option<&Type<PS>> {
353        self.types.data.iter().find(|x| x.name_bytes() == name.as_bytes())
354    }
355
356    /// Returns the extensible bitmap describing the set of types/domains for which permission
357    /// checks are permissive.
358    pub(super) fn permissive_types(&self) -> &ExtensibleBitmap<PS> {
359        &self.permissive_map
360    }
361
362    /// Returns the `Sensitivity` structure for the requested Id. Valid policies include definitions
363    /// for all the Ids they refer to internally; supply some other Id will trigger a panic.
364    pub(super) fn sensitivity(&self, id: SensitivityId) -> &Sensitivity<PS> {
365        self.sensitivities.data.iter().find(|x| x.id() == id).unwrap()
366    }
367
368    /// Returns the named sensitivity level, if present in the policy.
369    pub(super) fn sensitivity_by_name(&self, name: &str) -> Option<&Sensitivity<PS>> {
370        self.sensitivities.data.iter().find(|x| x.name_bytes() == name.as_bytes())
371    }
372
373    /// Returns the `Category` structure for the requested Id. Valid policies include definitions
374    /// for all the Ids they refer to internally; supply some other Id will trigger a panic.
375    pub(super) fn category(&self, id: CategoryId) -> &Category<PS> {
376        self.categories.data.iter().find(|y| y.id() == id).unwrap()
377    }
378
379    /// Returns the named category, if present in the policy.
380    pub(super) fn category_by_name(&self, name: &str) -> Option<&Category<PS>> {
381        self.categories.data.iter().find(|x| x.name_bytes() == name.as_bytes())
382    }
383
384    pub(super) fn classes(&self) -> &Classes<PS> {
385        &self.classes.data
386    }
387
388    pub(super) fn common_symbols(&self) -> &CommonSymbols<PS> {
389        &self.common_symbols.data
390    }
391
392    pub(super) fn conditional_booleans(&self) -> &Vec<ConditionalBoolean<PS>> {
393        &self.conditional_booleans.data
394    }
395
396    pub(super) fn fs_uses(&self) -> &FsUses<PS> {
397        &self.fs_uses.data
398    }
399
400    pub(super) fn generic_fs_contexts(&self) -> &GenericFsContexts<PS> {
401        &self.generic_fs_contexts.data
402    }
403
404    pub(super) fn role_allowlist(&self) -> &[RoleAllow] {
405        PS::deref_slice(&self.role_allowlist.data)
406    }
407
408    pub(super) fn role_transitions(&self) -> &[RoleTransition] {
409        PS::deref_slice(&self.role_transitions.data)
410    }
411
412    pub(super) fn range_transitions(&self) -> &RangeTransitions<PS> {
413        &self.range_transitions.data
414    }
415
416    pub(super) fn access_vector_rules(&self) -> &AccessVectorRules<PS> {
417        &self.access_vector_rules.data
418    }
419
420    pub(super) fn compute_filename_transition(
421        &self,
422        source_type: TypeId,
423        target_type: TypeId,
424        class: ClassId,
425        name: NullessByteStr<'_>,
426    ) -> Option<TypeId> {
427        match &self.filename_transition_list {
428            FilenameTransitionList::PolicyVersionGeq33(list) => {
429                let entry = list.data.iter().find(|transition| {
430                    transition.target_type() == target_type
431                        && transition.target_class() == class
432                        && transition.name_bytes() == name.as_bytes()
433                })?;
434                entry
435                    .outputs()
436                    .iter()
437                    .find(|entry| entry.has_source_type(source_type))
438                    .map(|x| x.out_type())
439            }
440            FilenameTransitionList::PolicyVersionLeq32(list) => list
441                .data
442                .iter()
443                .find(|transition| {
444                    transition.target_class() == class
445                        && transition.target_type() == target_type
446                        && transition.source_type() == source_type
447                        && transition.name_bytes() == name.as_bytes()
448                })
449                .map(|x| x.out_type()),
450        }
451    }
452
453    // Validate an MLS range statement against sets of defined sensitivity and category
454    // IDs:
455    // - Verify that all sensitivity and category IDs referenced in the MLS levels are
456    //   defined.
457    // - Verify that the range is internally consistent; i.e., the high level (if any)
458    //   dominates the low level.
459    fn validate_mls_range(
460        &self,
461        low_level: &MlsLevel<PS>,
462        high_level: &Option<MlsLevel<PS>>,
463        sensitivity_ids: &HashSet<SensitivityId>,
464        category_ids: &HashSet<CategoryId>,
465    ) -> Result<(), anyhow::Error> {
466        validate_id(sensitivity_ids, low_level.sensitivity(), "sensitivity")?;
467        for id in low_level.category_ids() {
468            validate_id(category_ids, id, "category")?;
469        }
470        if let Some(high) = high_level {
471            validate_id(sensitivity_ids, high.sensitivity(), "sensitivity")?;
472            for id in high.category_ids() {
473                validate_id(category_ids, id, "category")?;
474            }
475            if !high.dominates(low_level) {
476                return Err(ValidateError::InvalidMlsRange {
477                    low: low_level.serialize(self).into(),
478                    high: high.serialize(self).into(),
479                }
480                .into());
481            }
482        }
483        Ok(())
484    }
485}
486
487impl<PS: ParseStrategy> ParsedPolicy<PS>
488where
489    Self: Parse<PS>,
490{
491    /// Parses the binary policy stored in `bytes`. It is an error for `bytes` to have trailing
492    /// bytes after policy parsing completes.
493    pub(super) fn parse(bytes: PS) -> Result<(Self, PS::Input), anyhow::Error> {
494        let (policy, tail) =
495            <ParsedPolicy<PS> as Parse<PS>>::parse(bytes).map_err(Into::<anyhow::Error>::into)?;
496        let num_bytes = tail.len();
497        if num_bytes > 0 {
498            return Err(ParseError::TrailingBytes { num_bytes }.into());
499        }
500        Ok((policy, tail.into_inner()))
501    }
502}
503
504/// Parse a data structure from a prefix of a [`ParseStrategy`].
505impl<PS: ParseStrategy> Parse<PS> for ParsedPolicy<PS>
506where
507    Signature<PS>: Parse<PS>,
508    ExtensibleBitmap<PS>: Parse<PS>,
509    SymbolList<PS, CommonSymbol<PS>>: Parse<PS>,
510    SymbolList<PS, Class<PS>>: Parse<PS>,
511    SymbolList<PS, Role<PS>>: Parse<PS>,
512    SymbolList<PS, Type<PS>>: Parse<PS>,
513    SymbolList<PS, User<PS>>: Parse<PS>,
514    SymbolList<PS, ConditionalBoolean<PS>>: Parse<PS>,
515    SymbolList<PS, Sensitivity<PS>>: Parse<PS>,
516    SymbolList<PS, Category<PS>>: Parse<PS>,
517    SimpleArray<PS, AccessVectorRules<PS>>: Parse<PS>,
518    SimpleArray<PS, ConditionalNodes<PS>>: Parse<PS>,
519    RoleTransitions<PS>: Parse<PS>,
520    RoleAllows<PS>: Parse<PS>,
521    SimpleArray<PS, FilenameTransitions<PS>>: Parse<PS>,
522    SimpleArray<PS, DeprecatedFilenameTransitions<PS>>: Parse<PS>,
523    SimpleArray<PS, InitialSids<PS>>: Parse<PS>,
524    SimpleArray<PS, NamedContextPairs<PS>>: Parse<PS>,
525    SimpleArray<PS, Ports<PS>>: Parse<PS>,
526    SimpleArray<PS, NamedContextPairs<PS>>: Parse<PS>,
527    SimpleArray<PS, Nodes<PS>>: Parse<PS>,
528    SimpleArray<PS, FsUses<PS>>: Parse<PS>,
529    SimpleArray<PS, IPv6Nodes<PS>>: Parse<PS>,
530    SimpleArray<PS, InfinitiBandPartitionKeys<PS>>: Parse<PS>,
531    SimpleArray<PS, InfinitiBandEndPorts<PS>>: Parse<PS>,
532    SimpleArray<PS, GenericFsContexts<PS>>: Parse<PS>,
533    SimpleArray<PS, RangeTransitions<PS>>: Parse<PS>,
534{
535    /// A [`Policy`] may add context to underlying [`ParseError`] values.
536    type Error = anyhow::Error;
537
538    /// Parses an entire binary policy.
539    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
540        let tail = bytes;
541
542        let (magic, tail) = PS::parse::<Magic>(tail).context("parsing magic")?;
543
544        let (signature, tail) = Signature::parse(tail)
545            .map_err(Into::<anyhow::Error>::into)
546            .context("parsing signature")?;
547
548        let (policy_version, tail) =
549            PS::parse::<PolicyVersion>(tail).context("parsing policy version")?;
550        let policy_version_value = PS::deref(&policy_version).policy_version();
551
552        let (config, tail) = Config::parse(tail)
553            .map_err(Into::<anyhow::Error>::into)
554            .context("parsing policy config")?;
555
556        let (counts, tail) =
557            PS::parse::<Counts>(tail).context("parsing high-level policy object counts")?;
558
559        let (policy_capabilities, tail) = ExtensibleBitmap::parse(tail)
560            .map_err(Into::<anyhow::Error>::into)
561            .context("parsing policy capabilities")?;
562
563        let (permissive_map, tail) = ExtensibleBitmap::parse(tail)
564            .map_err(Into::<anyhow::Error>::into)
565            .context("parsing permissive map")?;
566
567        let (common_symbols, tail) = SymbolList::<PS, CommonSymbol<PS>>::parse(tail)
568            .map_err(Into::<anyhow::Error>::into)
569            .context("parsing common symbols")?;
570
571        let (classes, tail) = SymbolList::<PS, Class<PS>>::parse(tail)
572            .map_err(Into::<anyhow::Error>::into)
573            .context("parsing classes")?;
574
575        let (roles, tail) = SymbolList::<PS, Role<PS>>::parse(tail)
576            .map_err(Into::<anyhow::Error>::into)
577            .context("parsing roles")?;
578
579        let (types, tail) = SymbolList::<PS, Type<PS>>::parse(tail)
580            .map_err(Into::<anyhow::Error>::into)
581            .context("parsing types")?;
582
583        let (users, tail) = SymbolList::<PS, User<PS>>::parse(tail)
584            .map_err(Into::<anyhow::Error>::into)
585            .context("parsing users")?;
586
587        let (conditional_booleans, tail) = SymbolList::<PS, ConditionalBoolean<PS>>::parse(tail)
588            .map_err(Into::<anyhow::Error>::into)
589            .context("parsing conditional booleans")?;
590
591        let (sensitivities, tail) = SymbolList::<PS, Sensitivity<PS>>::parse(tail)
592            .map_err(Into::<anyhow::Error>::into)
593            .context("parsing sensitivites")?;
594
595        let (categories, tail) = SymbolList::<PS, Category<PS>>::parse(tail)
596            .map_err(Into::<anyhow::Error>::into)
597            .context("parsing categories")?;
598
599        let (access_vector_rules, tail) = SimpleArray::<PS, AccessVectorRules<PS>>::parse(tail)
600            .map_err(Into::<anyhow::Error>::into)
601            .context("parsing access vector rules")?;
602
603        let (conditional_lists, tail) = SimpleArray::<PS, ConditionalNodes<PS>>::parse(tail)
604            .map_err(Into::<anyhow::Error>::into)
605            .context("parsing conditional lists")?;
606
607        let (role_transitions, tail) = RoleTransitions::<PS>::parse(tail)
608            .map_err(Into::<anyhow::Error>::into)
609            .context("parsing role transitions")?;
610
611        let (role_allowlist, tail) = RoleAllows::<PS>::parse(tail)
612            .map_err(Into::<anyhow::Error>::into)
613            .context("parsing role allow rules")?;
614
615        let (filename_transition_list, tail) = if policy_version_value >= 33 {
616            let (filename_transition_list, tail) =
617                SimpleArray::<PS, FilenameTransitions<PS>>::parse(tail)
618                    .map_err(Into::<anyhow::Error>::into)
619                    .context("parsing standard filename transitions")?;
620            (FilenameTransitionList::PolicyVersionGeq33(filename_transition_list), tail)
621        } else {
622            let (filename_transition_list, tail) =
623                SimpleArray::<PS, DeprecatedFilenameTransitions<PS>>::parse(tail)
624                    .map_err(Into::<anyhow::Error>::into)
625                    .context("parsing deprecated filename transitions")?;
626            (FilenameTransitionList::PolicyVersionLeq32(filename_transition_list), tail)
627        };
628
629        let (initial_sids, tail) = SimpleArray::<PS, InitialSids<PS>>::parse(tail)
630            .map_err(Into::<anyhow::Error>::into)
631            .context("parsing initial sids")?;
632
633        let (filesystems, tail) = SimpleArray::<PS, NamedContextPairs<PS>>::parse(tail)
634            .map_err(Into::<anyhow::Error>::into)
635            .context("parsing filesystem contexts")?;
636
637        let (ports, tail) = SimpleArray::<PS, Ports<PS>>::parse(tail)
638            .map_err(Into::<anyhow::Error>::into)
639            .context("parsing ports")?;
640
641        let (network_interfaces, tail) = SimpleArray::<PS, NamedContextPairs<PS>>::parse(tail)
642            .map_err(Into::<anyhow::Error>::into)
643            .context("parsing network interfaces")?;
644
645        let (nodes, tail) = SimpleArray::<PS, Nodes<PS>>::parse(tail)
646            .map_err(Into::<anyhow::Error>::into)
647            .context("parsing nodes")?;
648
649        let (fs_uses, tail) = SimpleArray::<PS, FsUses<PS>>::parse(tail)
650            .map_err(Into::<anyhow::Error>::into)
651            .context("parsing fs uses")?;
652
653        let (ipv6_nodes, tail) = SimpleArray::<PS, IPv6Nodes<PS>>::parse(tail)
654            .map_err(Into::<anyhow::Error>::into)
655            .context("parsing ipv6 nodes")?;
656
657        let (infinitiband_partition_keys, infinitiband_end_ports, tail) =
658            if policy_version_value >= MIN_POLICY_VERSION_FOR_INFINITIBAND_PARTITION_KEY {
659                let (infinity_band_partition_keys, tail) =
660                    SimpleArray::<PS, InfinitiBandPartitionKeys<PS>>::parse(tail)
661                        .map_err(Into::<anyhow::Error>::into)
662                        .context("parsing infiniti band partition keys")?;
663                let (infinitiband_end_ports, tail) =
664                    SimpleArray::<PS, InfinitiBandEndPorts<PS>>::parse(tail)
665                        .map_err(Into::<anyhow::Error>::into)
666                        .context("parsing infiniti band end ports")?;
667                (Some(infinity_band_partition_keys), Some(infinitiband_end_ports), tail)
668            } else {
669                (None, None, tail)
670            };
671
672        let (generic_fs_contexts, tail) = SimpleArray::<PS, GenericFsContexts<PS>>::parse(tail)
673            .map_err(Into::<anyhow::Error>::into)
674            .context("parsing generic filesystem contexts")?;
675
676        let (range_transitions, tail) = SimpleArray::<PS, RangeTransitions<PS>>::parse(tail)
677            .map_err(Into::<anyhow::Error>::into)
678            .context("parsing range transitions")?;
679
680        let primary_names_count = PS::deref(&types.metadata).primary_names_count();
681        let mut attribute_maps = Vec::with_capacity(primary_names_count as usize);
682        let mut tail = tail;
683
684        for i in 0..primary_names_count {
685            let (item, next_tail) = ExtensibleBitmap::parse(tail)
686                .map_err(Into::<anyhow::Error>::into)
687                .with_context(|| format!("parsing {}th attribtue map", i))?;
688            attribute_maps.push(item);
689            tail = next_tail;
690        }
691        let tail = tail;
692        let attribute_maps = attribute_maps;
693
694        Ok((
695            Self {
696                magic,
697                signature,
698                policy_version,
699                config,
700                counts,
701                policy_capabilities,
702                permissive_map,
703                common_symbols,
704                classes,
705                roles,
706                types,
707                users,
708                conditional_booleans,
709                sensitivities,
710                categories,
711                access_vector_rules,
712                conditional_lists,
713                role_transitions,
714                role_allowlist,
715                filename_transition_list,
716                initial_sids,
717                filesystems,
718                ports,
719                network_interfaces,
720                nodes,
721                fs_uses,
722                ipv6_nodes,
723                infinitiband_partition_keys,
724                infinitiband_end_ports,
725                generic_fs_contexts,
726                range_transitions,
727                attribute_maps,
728            },
729            tail,
730        ))
731    }
732}
733
734impl<PS: ParseStrategy> Validate for ParsedPolicy<PS> {
735    /// A [`Policy`] may add context to underlying [`ValidateError`] values.
736    type Error = anyhow::Error;
737
738    fn validate(&self) -> Result<(), Self::Error> {
739        PS::deref(&self.magic)
740            .validate()
741            .map_err(Into::<anyhow::Error>::into)
742            .context("validating magic")?;
743        self.signature
744            .validate()
745            .map_err(Into::<anyhow::Error>::into)
746            .context("validating signature")?;
747        PS::deref(&self.policy_version)
748            .validate()
749            .map_err(Into::<anyhow::Error>::into)
750            .context("validating policy_version")?;
751        self.config.validate().map_err(Into::<anyhow::Error>::into).context("validating config")?;
752        PS::deref(&self.counts)
753            .validate()
754            .map_err(Into::<anyhow::Error>::into)
755            .context("validating counts")?;
756        self.policy_capabilities
757            .validate()
758            .map_err(Into::<anyhow::Error>::into)
759            .context("validating policy_capabilities")?;
760        self.permissive_map
761            .validate()
762            .map_err(Into::<anyhow::Error>::into)
763            .context("validating permissive_map")?;
764        self.common_symbols
765            .validate()
766            .map_err(Into::<anyhow::Error>::into)
767            .context("validating common_symbols")?;
768        self.classes
769            .validate()
770            .map_err(Into::<anyhow::Error>::into)
771            .context("validating classes")?;
772        self.roles.validate().map_err(Into::<anyhow::Error>::into).context("validating roles")?;
773        self.types.validate().map_err(Into::<anyhow::Error>::into).context("validating types")?;
774        self.users.validate().map_err(Into::<anyhow::Error>::into).context("validating users")?;
775        self.conditional_booleans
776            .validate()
777            .map_err(Into::<anyhow::Error>::into)
778            .context("validating conditional_booleans")?;
779        self.sensitivities
780            .validate()
781            .map_err(Into::<anyhow::Error>::into)
782            .context("validating sensitivities")?;
783        self.categories
784            .validate()
785            .map_err(Into::<anyhow::Error>::into)
786            .context("validating categories")?;
787        self.access_vector_rules
788            .validate()
789            .map_err(Into::<anyhow::Error>::into)
790            .context("validating access_vector_rules")?;
791        self.conditional_lists
792            .validate()
793            .map_err(Into::<anyhow::Error>::into)
794            .context("validating conditional_lists")?;
795        self.role_transitions
796            .validate()
797            .map_err(Into::<anyhow::Error>::into)
798            .context("validating role_transitions")?;
799        self.role_allowlist
800            .validate()
801            .map_err(Into::<anyhow::Error>::into)
802            .context("validating role_allowlist")?;
803        self.filename_transition_list
804            .validate()
805            .map_err(Into::<anyhow::Error>::into)
806            .context("validating filename_transition_list")?;
807        self.initial_sids
808            .validate()
809            .map_err(Into::<anyhow::Error>::into)
810            .context("validating initial_sids")?;
811        self.filesystems
812            .validate()
813            .map_err(Into::<anyhow::Error>::into)
814            .context("validating filesystems")?;
815        self.ports.validate().map_err(Into::<anyhow::Error>::into).context("validating ports")?;
816        self.network_interfaces
817            .validate()
818            .map_err(Into::<anyhow::Error>::into)
819            .context("validating network_interfaces")?;
820        self.nodes.validate().map_err(Into::<anyhow::Error>::into).context("validating nodes")?;
821        self.fs_uses
822            .validate()
823            .map_err(Into::<anyhow::Error>::into)
824            .context("validating fs_uses")?;
825        self.ipv6_nodes
826            .validate()
827            .map_err(Into::<anyhow::Error>::into)
828            .context("validating ipv6 nodes")?;
829        self.infinitiband_partition_keys
830            .validate()
831            .map_err(Into::<anyhow::Error>::into)
832            .context("validating infinitiband_partition_keys")?;
833        self.infinitiband_end_ports
834            .validate()
835            .map_err(Into::<anyhow::Error>::into)
836            .context("validating infinitiband_end_ports")?;
837        self.generic_fs_contexts
838            .validate()
839            .map_err(Into::<anyhow::Error>::into)
840            .context("validating generic_fs_contexts")?;
841        self.range_transitions
842            .validate()
843            .map_err(Into::<anyhow::Error>::into)
844            .context("validating range_transitions")?;
845        self.attribute_maps
846            .validate()
847            .map_err(Into::<anyhow::Error>::into)
848            .context("validating attribute_maps")?;
849
850        // Collate the sets of user, role, type, sensitivity and category Ids.
851        let user_ids: HashSet<UserId> = self.users.data.iter().map(|x| x.id()).collect();
852        let role_ids: HashSet<RoleId> = self.roles.data.iter().map(|x| x.id()).collect();
853        let class_ids: HashSet<ClassId> = self.classes.data.iter().map(|x| x.id()).collect();
854        let type_ids: HashSet<TypeId> = self.types.data.iter().map(|x| x.id()).collect();
855        let sensitivity_ids: HashSet<SensitivityId> =
856            self.sensitivities.data.iter().map(|x| x.id()).collect();
857        let category_ids: HashSet<CategoryId> =
858            self.categories.data.iter().map(|x| x.id()).collect();
859
860        // Validate that users use only defined sensitivities and categories, and that
861        // each user's MLS levels are internally consistent (i.e., the high level
862        // dominates the low level).
863        for user in &self.users.data {
864            self.validate_mls_range(
865                user.mls_range().low(),
866                user.mls_range().high(),
867                &sensitivity_ids,
868                &category_ids,
869            )?;
870        }
871
872        // Validate that initial contexts use only defined user, role, type, etc Ids.
873        // Check that all sensitivity and category IDs are defined and that MLS levels
874        // are internally consistent.
875        for initial_sid in &self.initial_sids.data {
876            let context = initial_sid.context();
877            validate_id(&user_ids, context.user_id(), "user")?;
878            validate_id(&role_ids, context.role_id(), "role")?;
879            validate_id(&type_ids, context.type_id(), "type")?;
880            self.validate_mls_range(
881                context.low_level(),
882                context.high_level(),
883                &sensitivity_ids,
884                &category_ids,
885            )?;
886        }
887
888        // Validate that contexts specified in filesystem labeling rules only use
889        // policy-defined Ids for their fields. Check that MLS levels are internally
890        // consistent.
891        for fs_use in &self.fs_uses.data {
892            let context = fs_use.context();
893            validate_id(&user_ids, context.user_id(), "user")?;
894            validate_id(&role_ids, context.role_id(), "role")?;
895            validate_id(&type_ids, context.type_id(), "type")?;
896            self.validate_mls_range(
897                context.low_level(),
898                context.high_level(),
899                &sensitivity_ids,
900                &category_ids,
901            )?;
902        }
903
904        // Validate that roles output by role- transitions & allows are defined.
905        for transition in PS::deref_slice(&self.role_transitions.data) {
906            validate_id(&role_ids, transition.current_role(), "current_role")?;
907            validate_id(&type_ids, transition.type_(), "type")?;
908            validate_id(&class_ids, transition.class(), "class")?;
909            validate_id(&role_ids, transition.new_role(), "new_role")?;
910        }
911        for allow in PS::deref_slice(&self.role_allowlist.data) {
912            validate_id(&role_ids, allow.source_role(), "source_role")?;
913            validate_id(&role_ids, allow.new_role(), "new_role")?;
914        }
915
916        // Validate that types output by access vector rules are defined.
917        for access_vector_rule in &self.access_vector_rules.data {
918            if let Some(type_id) = access_vector_rule.new_type() {
919                validate_id(&type_ids, type_id, "new_type")?;
920            }
921        }
922
923        // Validate that constraints are well-formed by evaluating against
924        // a source and target security context.
925        let initial_context = SecurityContext::new_from_policy_context(
926            self.initial_context(crate::InitialSid::Kernel),
927        );
928        for class in self.classes() {
929            for constraint in class.constraints() {
930                constraint
931                    .constraint_expr()
932                    .evaluate(&initial_context, &initial_context)
933                    .map_err(Into::<anyhow::Error>::into)
934                    .context("validating constraints")?;
935            }
936        }
937
938        // To-do comments for cross-policy validations yet to be implemented go here.
939        // TODO(b/356569876): Determine which "bounds" should be verified for correctness here.
940
941        Ok(())
942    }
943}
944
945fn validate_id<IdType: Debug + Eq + Hash>(
946    id_set: &HashSet<IdType>,
947    id: IdType,
948    debug_kind: &'static str,
949) -> Result<(), anyhow::Error> {
950    if !id_set.contains(&id) {
951        return Err(ValidateError::UnknownId { kind: debug_kind, id: format!("{:?}", id) }.into());
952    }
953    Ok(())
954}