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