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