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