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