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