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    #[allow(dead_code)]
405    // TODO(http://b/334968228): fn to be used again when checking role allow rules separately from
406    // SID calculation.
407    pub(super) fn role_allowlist(&self) -> &[RoleAllow] {
408        PS::deref_slice(&self.role_allowlist.data)
409    }
410
411    pub(super) fn role_transitions(&self) -> &[RoleTransition] {
412        PS::deref_slice(&self.role_transitions.data)
413    }
414
415    pub(super) fn range_transitions(&self) -> &RangeTransitions<PS> {
416        &self.range_transitions.data
417    }
418
419    pub(super) fn access_vector_rules(&self) -> &AccessVectorRules<PS> {
420        &self.access_vector_rules.data
421    }
422
423    pub(super) fn compute_filename_transition(
424        &self,
425        source_type: TypeId,
426        target_type: TypeId,
427        class: ClassId,
428        name: NullessByteStr<'_>,
429    ) -> Option<TypeId> {
430        match &self.filename_transition_list {
431            FilenameTransitionList::PolicyVersionGeq33(list) => {
432                let entry = list.data.iter().find(|transition| {
433                    transition.target_type() == target_type
434                        && transition.target_class() == class
435                        && transition.name_bytes() == name.as_bytes()
436                })?;
437                entry
438                    .outputs()
439                    .iter()
440                    .find(|entry| entry.has_source_type(source_type))
441                    .map(|x| x.out_type())
442            }
443            FilenameTransitionList::PolicyVersionLeq32(list) => list
444                .data
445                .iter()
446                .find(|transition| {
447                    transition.target_class() == class
448                        && transition.target_type() == target_type
449                        && transition.source_type() == source_type
450                        && transition.name_bytes() == name.as_bytes()
451                })
452                .map(|x| x.out_type()),
453        }
454    }
455
456    // Validate an MLS range statement against sets of defined sensitivity and category
457    // IDs:
458    // - Verify that all sensitivity and category IDs referenced in the MLS levels are
459    //   defined.
460    // - Verify that the range is internally consistent; i.e., the high level (if any)
461    //   dominates the low level.
462    fn validate_mls_range(
463        &self,
464        low_level: &MlsLevel<PS>,
465        high_level: &Option<MlsLevel<PS>>,
466        sensitivity_ids: &HashSet<SensitivityId>,
467        category_ids: &HashSet<CategoryId>,
468    ) -> Result<(), anyhow::Error> {
469        validate_id(sensitivity_ids, low_level.sensitivity(), "sensitivity")?;
470        for id in low_level.category_ids() {
471            validate_id(category_ids, id, "category")?;
472        }
473        if let Some(high) = high_level {
474            validate_id(sensitivity_ids, high.sensitivity(), "sensitivity")?;
475            for id in high.category_ids() {
476                validate_id(category_ids, id, "category")?;
477            }
478            if !high.dominates(low_level) {
479                return Err(ValidateError::InvalidMlsRange {
480                    low: low_level.serialize(self).into(),
481                    high: high.serialize(self).into(),
482                }
483                .into());
484            }
485        }
486        Ok(())
487    }
488}
489
490impl<PS: ParseStrategy> ParsedPolicy<PS>
491where
492    Self: Parse<PS>,
493{
494    /// Parses the binary policy stored in `bytes`. It is an error for `bytes` to have trailing
495    /// bytes after policy parsing completes.
496    pub(super) fn parse(bytes: PS) -> Result<(Self, PS::Input), anyhow::Error> {
497        let (policy, tail) =
498            <ParsedPolicy<PS> as Parse<PS>>::parse(bytes).map_err(Into::<anyhow::Error>::into)?;
499        let num_bytes = tail.len();
500        if num_bytes > 0 {
501            return Err(ParseError::TrailingBytes { num_bytes }.into());
502        }
503        Ok((policy, tail.into_inner()))
504    }
505}
506
507/// Parse a data structure from a prefix of a [`ParseStrategy`].
508impl<PS: ParseStrategy> Parse<PS> for ParsedPolicy<PS>
509where
510    Signature<PS>: Parse<PS>,
511    ExtensibleBitmap<PS>: Parse<PS>,
512    SymbolList<PS, CommonSymbol<PS>>: Parse<PS>,
513    SymbolList<PS, Class<PS>>: Parse<PS>,
514    SymbolList<PS, Role<PS>>: Parse<PS>,
515    SymbolList<PS, Type<PS>>: Parse<PS>,
516    SymbolList<PS, User<PS>>: Parse<PS>,
517    SymbolList<PS, ConditionalBoolean<PS>>: Parse<PS>,
518    SymbolList<PS, Sensitivity<PS>>: Parse<PS>,
519    SymbolList<PS, Category<PS>>: Parse<PS>,
520    SimpleArray<PS, AccessVectorRules<PS>>: Parse<PS>,
521    SimpleArray<PS, ConditionalNodes<PS>>: Parse<PS>,
522    RoleTransitions<PS>: Parse<PS>,
523    RoleAllows<PS>: Parse<PS>,
524    SimpleArray<PS, FilenameTransitions<PS>>: Parse<PS>,
525    SimpleArray<PS, DeprecatedFilenameTransitions<PS>>: Parse<PS>,
526    SimpleArray<PS, InitialSids<PS>>: Parse<PS>,
527    SimpleArray<PS, NamedContextPairs<PS>>: Parse<PS>,
528    SimpleArray<PS, Ports<PS>>: Parse<PS>,
529    SimpleArray<PS, NamedContextPairs<PS>>: Parse<PS>,
530    SimpleArray<PS, Nodes<PS>>: Parse<PS>,
531    SimpleArray<PS, FsUses<PS>>: Parse<PS>,
532    SimpleArray<PS, IPv6Nodes<PS>>: Parse<PS>,
533    SimpleArray<PS, InfinitiBandPartitionKeys<PS>>: Parse<PS>,
534    SimpleArray<PS, InfinitiBandEndPorts<PS>>: Parse<PS>,
535    SimpleArray<PS, GenericFsContexts<PS>>: Parse<PS>,
536    SimpleArray<PS, RangeTransitions<PS>>: Parse<PS>,
537{
538    /// A [`Policy`] may add context to underlying [`ParseError`] values.
539    type Error = anyhow::Error;
540
541    /// Parses an entire binary policy.
542    fn parse(bytes: PS) -> Result<(Self, PS), Self::Error> {
543        let tail = bytes;
544
545        let (magic, tail) = PS::parse::<Magic>(tail).context("parsing magic")?;
546
547        let (signature, tail) = Signature::parse(tail)
548            .map_err(Into::<anyhow::Error>::into)
549            .context("parsing signature")?;
550
551        let (policy_version, tail) =
552            PS::parse::<PolicyVersion>(tail).context("parsing policy version")?;
553        let policy_version_value = PS::deref(&policy_version).policy_version();
554
555        let (config, tail) = Config::parse(tail)
556            .map_err(Into::<anyhow::Error>::into)
557            .context("parsing policy config")?;
558
559        let (counts, tail) =
560            PS::parse::<Counts>(tail).context("parsing high-level policy object counts")?;
561
562        let (policy_capabilities, tail) = ExtensibleBitmap::parse(tail)
563            .map_err(Into::<anyhow::Error>::into)
564            .context("parsing policy capabilities")?;
565
566        let (permissive_map, tail) = ExtensibleBitmap::parse(tail)
567            .map_err(Into::<anyhow::Error>::into)
568            .context("parsing permissive map")?;
569
570        let (common_symbols, tail) = SymbolList::<PS, CommonSymbol<PS>>::parse(tail)
571            .map_err(Into::<anyhow::Error>::into)
572            .context("parsing common symbols")?;
573
574        let (classes, tail) = SymbolList::<PS, Class<PS>>::parse(tail)
575            .map_err(Into::<anyhow::Error>::into)
576            .context("parsing classes")?;
577
578        let (roles, tail) = SymbolList::<PS, Role<PS>>::parse(tail)
579            .map_err(Into::<anyhow::Error>::into)
580            .context("parsing roles")?;
581
582        let (types, tail) = SymbolList::<PS, Type<PS>>::parse(tail)
583            .map_err(Into::<anyhow::Error>::into)
584            .context("parsing types")?;
585
586        let (users, tail) = SymbolList::<PS, User<PS>>::parse(tail)
587            .map_err(Into::<anyhow::Error>::into)
588            .context("parsing users")?;
589
590        let (conditional_booleans, tail) = SymbolList::<PS, ConditionalBoolean<PS>>::parse(tail)
591            .map_err(Into::<anyhow::Error>::into)
592            .context("parsing conditional booleans")?;
593
594        let (sensitivities, tail) = SymbolList::<PS, Sensitivity<PS>>::parse(tail)
595            .map_err(Into::<anyhow::Error>::into)
596            .context("parsing sensitivites")?;
597
598        let (categories, tail) = SymbolList::<PS, Category<PS>>::parse(tail)
599            .map_err(Into::<anyhow::Error>::into)
600            .context("parsing categories")?;
601
602        let (access_vector_rules, tail) = SimpleArray::<PS, AccessVectorRules<PS>>::parse(tail)
603            .map_err(Into::<anyhow::Error>::into)
604            .context("parsing access vector rules")?;
605
606        let (conditional_lists, tail) = SimpleArray::<PS, ConditionalNodes<PS>>::parse(tail)
607            .map_err(Into::<anyhow::Error>::into)
608            .context("parsing conditional lists")?;
609
610        let (role_transitions, tail) = RoleTransitions::<PS>::parse(tail)
611            .map_err(Into::<anyhow::Error>::into)
612            .context("parsing role transitions")?;
613
614        let (role_allowlist, tail) = RoleAllows::<PS>::parse(tail)
615            .map_err(Into::<anyhow::Error>::into)
616            .context("parsing role allow rules")?;
617
618        let (filename_transition_list, tail) = if policy_version_value >= 33 {
619            let (filename_transition_list, tail) =
620                SimpleArray::<PS, FilenameTransitions<PS>>::parse(tail)
621                    .map_err(Into::<anyhow::Error>::into)
622                    .context("parsing standard filename transitions")?;
623            (FilenameTransitionList::PolicyVersionGeq33(filename_transition_list), tail)
624        } else {
625            let (filename_transition_list, tail) =
626                SimpleArray::<PS, DeprecatedFilenameTransitions<PS>>::parse(tail)
627                    .map_err(Into::<anyhow::Error>::into)
628                    .context("parsing deprecated filename transitions")?;
629            (FilenameTransitionList::PolicyVersionLeq32(filename_transition_list), tail)
630        };
631
632        let (initial_sids, tail) = SimpleArray::<PS, InitialSids<PS>>::parse(tail)
633            .map_err(Into::<anyhow::Error>::into)
634            .context("parsing initial sids")?;
635
636        let (filesystems, tail) = SimpleArray::<PS, NamedContextPairs<PS>>::parse(tail)
637            .map_err(Into::<anyhow::Error>::into)
638            .context("parsing filesystem contexts")?;
639
640        let (ports, tail) = SimpleArray::<PS, Ports<PS>>::parse(tail)
641            .map_err(Into::<anyhow::Error>::into)
642            .context("parsing ports")?;
643
644        let (network_interfaces, tail) = SimpleArray::<PS, NamedContextPairs<PS>>::parse(tail)
645            .map_err(Into::<anyhow::Error>::into)
646            .context("parsing network interfaces")?;
647
648        let (nodes, tail) = SimpleArray::<PS, Nodes<PS>>::parse(tail)
649            .map_err(Into::<anyhow::Error>::into)
650            .context("parsing nodes")?;
651
652        let (fs_uses, tail) = SimpleArray::<PS, FsUses<PS>>::parse(tail)
653            .map_err(Into::<anyhow::Error>::into)
654            .context("parsing fs uses")?;
655
656        let (ipv6_nodes, tail) = SimpleArray::<PS, IPv6Nodes<PS>>::parse(tail)
657            .map_err(Into::<anyhow::Error>::into)
658            .context("parsing ipv6 nodes")?;
659
660        let (infinitiband_partition_keys, infinitiband_end_ports, tail) =
661            if policy_version_value >= MIN_POLICY_VERSION_FOR_INFINITIBAND_PARTITION_KEY {
662                let (infinity_band_partition_keys, tail) =
663                    SimpleArray::<PS, InfinitiBandPartitionKeys<PS>>::parse(tail)
664                        .map_err(Into::<anyhow::Error>::into)
665                        .context("parsing infiniti band partition keys")?;
666                let (infinitiband_end_ports, tail) =
667                    SimpleArray::<PS, InfinitiBandEndPorts<PS>>::parse(tail)
668                        .map_err(Into::<anyhow::Error>::into)
669                        .context("parsing infiniti band end ports")?;
670                (Some(infinity_band_partition_keys), Some(infinitiband_end_ports), tail)
671            } else {
672                (None, None, tail)
673            };
674
675        let (generic_fs_contexts, tail) = SimpleArray::<PS, GenericFsContexts<PS>>::parse(tail)
676            .map_err(Into::<anyhow::Error>::into)
677            .context("parsing generic filesystem contexts")?;
678
679        let (range_transitions, tail) = SimpleArray::<PS, RangeTransitions<PS>>::parse(tail)
680            .map_err(Into::<anyhow::Error>::into)
681            .context("parsing range transitions")?;
682
683        let primary_names_count = PS::deref(&types.metadata).primary_names_count();
684        let mut attribute_maps = Vec::with_capacity(primary_names_count as usize);
685        let mut tail = tail;
686
687        for i in 0..primary_names_count {
688            let (item, next_tail) = ExtensibleBitmap::parse(tail)
689                .map_err(Into::<anyhow::Error>::into)
690                .with_context(|| format!("parsing {}th attribtue map", i))?;
691            attribute_maps.push(item);
692            tail = next_tail;
693        }
694        let tail = tail;
695        let attribute_maps = attribute_maps;
696
697        Ok((
698            Self {
699                magic,
700                signature,
701                policy_version,
702                config,
703                counts,
704                policy_capabilities,
705                permissive_map,
706                common_symbols,
707                classes,
708                roles,
709                types,
710                users,
711                conditional_booleans,
712                sensitivities,
713                categories,
714                access_vector_rules,
715                conditional_lists,
716                role_transitions,
717                role_allowlist,
718                filename_transition_list,
719                initial_sids,
720                filesystems,
721                ports,
722                network_interfaces,
723                nodes,
724                fs_uses,
725                ipv6_nodes,
726                infinitiband_partition_keys,
727                infinitiband_end_ports,
728                generic_fs_contexts,
729                range_transitions,
730                attribute_maps,
731            },
732            tail,
733        ))
734    }
735}
736
737impl<PS: ParseStrategy> Validate for ParsedPolicy<PS> {
738    /// A [`Policy`] may add context to underlying [`ValidateError`] values.
739    type Error = anyhow::Error;
740
741    fn validate(&self) -> Result<(), Self::Error> {
742        PS::deref(&self.magic)
743            .validate()
744            .map_err(Into::<anyhow::Error>::into)
745            .context("validating magic")?;
746        self.signature
747            .validate()
748            .map_err(Into::<anyhow::Error>::into)
749            .context("validating signature")?;
750        PS::deref(&self.policy_version)
751            .validate()
752            .map_err(Into::<anyhow::Error>::into)
753            .context("validating policy_version")?;
754        self.config.validate().map_err(Into::<anyhow::Error>::into).context("validating config")?;
755        PS::deref(&self.counts)
756            .validate()
757            .map_err(Into::<anyhow::Error>::into)
758            .context("validating counts")?;
759        self.policy_capabilities
760            .validate()
761            .map_err(Into::<anyhow::Error>::into)
762            .context("validating policy_capabilities")?;
763        self.permissive_map
764            .validate()
765            .map_err(Into::<anyhow::Error>::into)
766            .context("validating permissive_map")?;
767        self.common_symbols
768            .validate()
769            .map_err(Into::<anyhow::Error>::into)
770            .context("validating common_symbols")?;
771        self.classes
772            .validate()
773            .map_err(Into::<anyhow::Error>::into)
774            .context("validating classes")?;
775        self.roles.validate().map_err(Into::<anyhow::Error>::into).context("validating roles")?;
776        self.types.validate().map_err(Into::<anyhow::Error>::into).context("validating types")?;
777        self.users.validate().map_err(Into::<anyhow::Error>::into).context("validating users")?;
778        self.conditional_booleans
779            .validate()
780            .map_err(Into::<anyhow::Error>::into)
781            .context("validating conditional_booleans")?;
782        self.sensitivities
783            .validate()
784            .map_err(Into::<anyhow::Error>::into)
785            .context("validating sensitivities")?;
786        self.categories
787            .validate()
788            .map_err(Into::<anyhow::Error>::into)
789            .context("validating categories")?;
790        self.access_vector_rules
791            .validate()
792            .map_err(Into::<anyhow::Error>::into)
793            .context("validating access_vector_rules")?;
794        self.conditional_lists
795            .validate()
796            .map_err(Into::<anyhow::Error>::into)
797            .context("validating conditional_lists")?;
798        self.role_transitions
799            .validate()
800            .map_err(Into::<anyhow::Error>::into)
801            .context("validating role_transitions")?;
802        self.role_allowlist
803            .validate()
804            .map_err(Into::<anyhow::Error>::into)
805            .context("validating role_allowlist")?;
806        self.filename_transition_list
807            .validate()
808            .map_err(Into::<anyhow::Error>::into)
809            .context("validating filename_transition_list")?;
810        self.initial_sids
811            .validate()
812            .map_err(Into::<anyhow::Error>::into)
813            .context("validating initial_sids")?;
814        self.filesystems
815            .validate()
816            .map_err(Into::<anyhow::Error>::into)
817            .context("validating filesystems")?;
818        self.ports.validate().map_err(Into::<anyhow::Error>::into).context("validating ports")?;
819        self.network_interfaces
820            .validate()
821            .map_err(Into::<anyhow::Error>::into)
822            .context("validating network_interfaces")?;
823        self.nodes.validate().map_err(Into::<anyhow::Error>::into).context("validating nodes")?;
824        self.fs_uses
825            .validate()
826            .map_err(Into::<anyhow::Error>::into)
827            .context("validating fs_uses")?;
828        self.ipv6_nodes
829            .validate()
830            .map_err(Into::<anyhow::Error>::into)
831            .context("validating ipv6 nodes")?;
832        self.infinitiband_partition_keys
833            .validate()
834            .map_err(Into::<anyhow::Error>::into)
835            .context("validating infinitiband_partition_keys")?;
836        self.infinitiband_end_ports
837            .validate()
838            .map_err(Into::<anyhow::Error>::into)
839            .context("validating infinitiband_end_ports")?;
840        self.generic_fs_contexts
841            .validate()
842            .map_err(Into::<anyhow::Error>::into)
843            .context("validating generic_fs_contexts")?;
844        self.range_transitions
845            .validate()
846            .map_err(Into::<anyhow::Error>::into)
847            .context("validating range_transitions")?;
848        self.attribute_maps
849            .validate()
850            .map_err(Into::<anyhow::Error>::into)
851            .context("validating attribute_maps")?;
852
853        // Collate the sets of user, role, type, sensitivity and category Ids.
854        let user_ids: HashSet<UserId> = self.users.data.iter().map(|x| x.id()).collect();
855        let role_ids: HashSet<RoleId> = self.roles.data.iter().map(|x| x.id()).collect();
856        let type_ids: HashSet<TypeId> = self.types.data.iter().map(|x| x.id()).collect();
857        let sensitivity_ids: HashSet<SensitivityId> =
858            self.sensitivities.data.iter().map(|x| x.id()).collect();
859        let category_ids: HashSet<CategoryId> =
860            self.categories.data.iter().map(|x| x.id()).collect();
861
862        // Validate that users use only defined sensitivities and categories, and that
863        // each user's MLS levels are internally consistent (i.e., the high level
864        // dominates the low level).
865        for user in &self.users.data {
866            self.validate_mls_range(
867                user.mls_range().low(),
868                user.mls_range().high(),
869                &sensitivity_ids,
870                &category_ids,
871            )?;
872        }
873
874        // Validate that initial contexts use only defined user, role, type, etc Ids.
875        // Check that all sensitivity and category IDs are defined and that MLS levels
876        // are internally consistent.
877        for initial_sid in &self.initial_sids.data {
878            let context = initial_sid.context();
879            validate_id(&user_ids, context.user_id(), "user")?;
880            validate_id(&role_ids, context.role_id(), "role")?;
881            validate_id(&type_ids, context.type_id(), "type")?;
882            self.validate_mls_range(
883                context.low_level(),
884                context.high_level(),
885                &sensitivity_ids,
886                &category_ids,
887            )?;
888        }
889
890        // Validate that contexts specified in filesystem labeling rules only use
891        // policy-defined Ids for their fields. Check that MLS levels are internally
892        // consistent.
893        for fs_use in &self.fs_uses.data {
894            let context = fs_use.context();
895            validate_id(&user_ids, context.user_id(), "user")?;
896            validate_id(&role_ids, context.role_id(), "role")?;
897            validate_id(&type_ids, context.type_id(), "type")?;
898            self.validate_mls_range(
899                context.low_level(),
900                context.high_level(),
901                &sensitivity_ids,
902                &category_ids,
903            )?;
904        }
905
906        // Validate that roles output by role- transitions & allows are defined.
907        for transition in PS::deref_slice(&self.role_transitions.data) {
908            validate_id(&role_ids, transition.new_role(), "new_role")?;
909        }
910        for allow in PS::deref_slice(&self.role_allowlist.data) {
911            validate_id(&role_ids, allow.new_role(), "new_role")?;
912        }
913
914        // Validate that types output by access vector rules are defined.
915        for access_vector_rule in &self.access_vector_rules.data {
916            if let Some(type_id) = access_vector_rule.new_type() {
917                validate_id(&type_ids, type_id, "new_type")?;
918            }
919        }
920
921        // Validate that constraints are well-formed by evaluating against
922        // a source and target security context.
923        let initial_context = SecurityContext::new_from_policy_context(
924            self.initial_context(crate::InitialSid::Kernel),
925        );
926        for class in self.classes() {
927            for constraint in class.constraints() {
928                constraint
929                    .constraint_expr()
930                    .evaluate(&initial_context, &initial_context)
931                    .map_err(Into::<anyhow::Error>::into)
932                    .context("validating constraints")?;
933            }
934        }
935
936        // To-do comments for cross-policy validations yet to be implemented go here.
937        // TODO(b/356569876): Determine which "bounds" should be verified for correctness here.
938
939        Ok(())
940    }
941}
942
943fn validate_id<IdType: Debug + Eq + Hash>(
944    id_set: &HashSet<IdType>,
945    id: IdType,
946    debug_kind: &'static str,
947) -> Result<(), anyhow::Error> {
948    if !id_set.contains(&id) {
949        return Err(ValidateError::UnknownId { kind: debug_kind, id: format!("{:?}", id) }.into());
950    }
951    Ok(())
952}