Skip to main content

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