1use super::arrays::{
6 ACCESS_VECTOR_RULE_TYPE_ALLOW, ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM,
7 ACCESS_VECTOR_RULE_TYPE_AUDITALLOW, ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM,
8 ACCESS_VECTOR_RULE_TYPE_DONTAUDIT, ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM, AccessVectorRule,
9 AccessVectorRuleMetadata, ConditionalNode, Context, DeprecatedFilenameTransition,
10 ExtendedPermissions, FilenameTransition, FilenameTransitionList, FsUse, GenericFsContext,
11 IPv6Node, InfinitiBandEndPort, InfinitiBandPartitionKey, InitialSid,
12 MIN_POLICY_VERSION_FOR_INFINITIBAND_PARTITION_KEY, NamedContextPair, Node, Port,
13 RangeTransition, RoleAllow, RoleAllows, RoleTransition, RoleTransitions, SimpleArray,
14 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES, XPERMS_TYPE_IOCTL_PREFIXES, XPERMS_TYPE_NLMSG,
15 XpermsBitmap,
16};
17use super::error::{ParseError, ValidateError};
18use super::extensible_bitmap::ExtensibleBitmap;
19
20use super::constraints::evaluate_constraint;
21use super::parser::{PolicyCursor, PolicyData};
22use super::security_context::SecurityContext;
23use super::view::{Hashable, HashedArrayView};
24use super::{
25 AccessDecision, AccessVector, CategoryId, ClassId, MlsLevel, Parse, PolicyValidationContext,
26 RoleId, SELINUX_AVD_FLAGS_PERMISSIVE, SensitivityId, TypeId, UserId, Validate,
27 XpermsAccessDecision, XpermsKind,
28};
29
30use crate::new_policy::traits::{HasPolicyId, PolicyId};
31use crate::new_policy::{Class, NewPolicy};
32use crate::policy::arrays::FsContext;
33use crate::policy::view::CustomKeyHashedView;
34use crate::{NullessByteStr, PolicyCap};
35use std::ops::Deref;
36use std::sync::Arc;
37
38use anyhow::Context as _;
39use itertools::Itertools;
40use std::collections::HashSet;
41use std::fmt::Debug;
42use std::hash::Hash;
43use std::iter::Iterator;
44use zerocopy::little_endian as le;
45
46const MAXIMUM_POLICY_SIZE: usize = 1 << 24;
48
49#[derive(Debug)]
51pub struct ParsedPolicy {
52 data: PolicyData,
54
55 new_policy: Arc<NewPolicy>,
57
58 access_vector_rules: HashedArrayView<AccessVectorRule>,
60 conditional_lists: SimpleArray<ConditionalNode>,
61 role_transitions: RoleTransitions,
63 role_allowlist: RoleAllows,
65 filename_transition_list: FilenameTransitionList,
66 initial_sids: SimpleArray<InitialSid>,
67 filesystems: SimpleArray<NamedContextPair>,
68 ports: SimpleArray<Port>,
69 network_interfaces: SimpleArray<NamedContextPair>,
70 nodes: SimpleArray<Node>,
71 fs_uses: SimpleArray<FsUse>,
72 ipv6_nodes: SimpleArray<IPv6Node>,
73 infinitiband_partition_keys: Option<SimpleArray<InfinitiBandPartitionKey>>,
74 infinitiband_end_ports: Option<SimpleArray<InfinitiBandEndPort>>,
75 generic_fs_contexts: CustomKeyHashedView<GenericFsContext>,
78 range_transitions: SimpleArray<RangeTransition>,
79 attribute_maps: Vec<ExtensibleBitmap>,
81}
82
83impl Deref for ParsedPolicy {
84 type Target = NewPolicy;
85 fn deref(&self) -> &Self::Target {
86 &self.new_policy
87 }
88}
89
90impl ParsedPolicy {
91 pub fn has_policycap(&self, policy_cap: PolicyCap) -> bool {
93 self.new_policy.policy_capabilities().is_set(policy_cap as u32)
94 }
95
96 pub(super) fn compute_access_decision(
108 &self,
109 source_context: &SecurityContext,
110 target_context: &SecurityContext,
111 target_class: &Class,
112 ) -> AccessDecision {
113 let mut access_decision = self.compute_explicitly_allowed(
114 source_context.type_(),
115 target_context.type_(),
116 target_class,
117 );
118 access_decision.allow -=
119 self.compute_denied_by_constraints(source_context, target_context, target_class);
120 access_decision
121 }
122
123 pub(super) fn compute_explicitly_allowed(
128 &self,
129 source_type: TypeId,
130 target_type: TypeId,
131 target_class: &Class,
132 ) -> AccessDecision {
133 let target_class_id = target_class.id();
134
135 let mut computed_access_vector = AccessVector::NONE;
136 let mut computed_audit_allow = AccessVector::NONE;
137 let mut computed_audit_deny = AccessVector::ALL;
138
139 let source_attribute_bitmap: &ExtensibleBitmap =
140 &self.attribute_maps[(source_type.as_u32() - 1) as usize];
141 let target_attribute_bitmap: &ExtensibleBitmap =
142 &self.attribute_maps[(target_type.as_u32() - 1) as usize];
143
144 for (source_bit_index, target_bit_index) in Itertools::cartesian_product(
145 source_attribute_bitmap.indices_of_set_bits(),
146 target_attribute_bitmap.indices_of_set_bits(),
147 ) {
148 let source_id = TypeId::from_u32((source_bit_index + 1) as u32).unwrap();
149 let target_id = TypeId::from_u32((target_bit_index + 1) as u32).unwrap();
150
151 if let Some(allow_rule) = self.access_vector_rules_find(
152 source_id,
153 target_id,
154 target_class_id,
155 ACCESS_VECTOR_RULE_TYPE_ALLOW,
156 ) {
157 computed_access_vector |= allow_rule.access_vector().unwrap();
159 }
160 if let Some(auditallow_rule) = self.access_vector_rules_find(
161 source_id,
162 target_id,
163 target_class_id,
164 ACCESS_VECTOR_RULE_TYPE_AUDITALLOW,
165 ) {
166 computed_audit_allow |= auditallow_rule.access_vector().unwrap();
168 }
169 if let Some(dontaudit_rule) = self.access_vector_rules_find(
170 source_id,
171 target_id,
172 target_class_id,
173 ACCESS_VECTOR_RULE_TYPE_DONTAUDIT,
174 ) {
175 computed_audit_deny &= dontaudit_rule.access_vector().unwrap();
177 }
178 }
179
180 if let Some(parent) = self.types().get_by_id(source_type).unwrap().bounded_by() {
184 let access = if source_type == target_type {
187 self.compute_explicitly_allowed(parent, parent, target_class)
188 } else {
189 self.compute_explicitly_allowed(parent, target_type, target_class)
190 };
191 computed_access_vector &= access.allow;
192 }
193
194 let mut flags = 0;
195 if self.permissive_map().contains(source_type) {
196 flags |= SELINUX_AVD_FLAGS_PERMISSIVE;
197 }
198 AccessDecision {
199 allow: computed_access_vector,
200 auditallow: computed_audit_allow,
201 auditdeny: computed_audit_deny,
202 flags,
203 todo_bug: None,
204 }
205 }
206
207 fn compute_denied_by_constraints(
209 &self,
210 source_context: &SecurityContext,
211 target_context: &SecurityContext,
212 target_class: &Class,
213 ) -> AccessVector {
214 let mut denied = AccessVector::NONE;
215 for constraint in target_class.constraints() {
216 if !evaluate_constraint(constraint.constraint_expr(), source_context, target_context) {
217 denied |= constraint.access_vector();
218 }
219 }
220 denied
221 }
222
223 pub(super) fn compute_xperms_access_decision(
226 &self,
227 xperms_kind: XpermsKind,
228 source_context: &SecurityContext,
229 target_context: &SecurityContext,
230 target_class: &Class,
231 xperms_prefix: u8,
232 ) -> XpermsAccessDecision {
233 let target_class_id = target_class.id();
234
235 let mut explicit_allow: Option<XpermsBitmap> = None;
236 let mut auditallow = XpermsBitmap::NONE;
237 let mut auditdeny = XpermsBitmap::ALL;
238
239 let xperms_types = match xperms_kind {
240 XpermsKind::Ioctl => {
241 [XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES, XPERMS_TYPE_IOCTL_PREFIXES].as_slice()
242 }
243 XpermsKind::Nlmsg => [XPERMS_TYPE_NLMSG].as_slice(),
244 };
245 let bitmap_if_prefix_matches =
246 |xperms_prefix: u8, xperms: &ExtendedPermissions| match xperms_kind {
247 XpermsKind::Ioctl => match xperms.xperms_type {
248 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES => (xperms.xperms_optional_prefix
249 == xperms_prefix)
250 .then_some(xperms.xperms_bitmap),
251 XPERMS_TYPE_IOCTL_PREFIXES => {
252 xperms.xperms_bitmap.contains(xperms_prefix).then_some(XpermsBitmap::ALL)
253 }
254 _ => None,
255 },
256 XpermsKind::Nlmsg => match xperms.xperms_type {
257 XPERMS_TYPE_NLMSG => (xperms.xperms_optional_prefix == xperms_prefix)
258 .then_some(xperms.xperms_bitmap),
259 _ => None,
260 },
261 };
262
263 let source_attribute_bitmap: &ExtensibleBitmap =
264 &self.attribute_maps[(source_context.type_().as_u32() - 1) as usize];
265 let target_attribute_bitmap: &ExtensibleBitmap =
266 &self.attribute_maps[(target_context.type_().as_u32() - 1) as usize];
267
268 for (source_bit_index, target_bit_index) in Itertools::cartesian_product(
269 source_attribute_bitmap.indices_of_set_bits(),
270 target_attribute_bitmap.indices_of_set_bits(),
271 ) {
272 let source_id = TypeId::from_u32((source_bit_index + 1) as u32).unwrap();
273 let target_id = TypeId::from_u32((target_bit_index + 1) as u32).unwrap();
274
275 for xperms_allow_rule in self.access_vector_rules_find_all(
276 source_id,
277 target_id,
278 target_class_id,
279 ACCESS_VECTOR_RULE_TYPE_ALLOWXPERM,
280 ) {
281 let xperms = xperms_allow_rule.extended_permissions().unwrap();
282
283 if xperms_types.contains(&xperms.xperms_type) {
287 explicit_allow.get_or_insert(XpermsBitmap::NONE);
288 }
289
290 if let Some(ref xperms_bitmap) = bitmap_if_prefix_matches(xperms_prefix, xperms) {
291 (*explicit_allow.get_or_insert(XpermsBitmap::NONE)) |= xperms_bitmap;
292 }
293 }
294
295 for xperms_auditallow_rule in self.access_vector_rules_find_all(
296 source_id,
297 target_id,
298 target_class_id,
299 ACCESS_VECTOR_RULE_TYPE_AUDITALLOWXPERM,
300 ) {
301 let xperms = xperms_auditallow_rule.extended_permissions().unwrap();
302 if let Some(ref xperms_bitmap) = bitmap_if_prefix_matches(xperms_prefix, xperms) {
303 auditallow |= xperms_bitmap;
304 }
305 }
306
307 for xperms_dontaudit_rule in self.access_vector_rules_find_all(
308 source_id,
309 target_id,
310 target_class_id,
311 ACCESS_VECTOR_RULE_TYPE_DONTAUDITXPERM,
312 ) {
313 let xperms = xperms_dontaudit_rule.extended_permissions().unwrap();
314 if let Some(ref xperms_bitmap) = bitmap_if_prefix_matches(xperms_prefix, xperms) {
315 auditdeny -= xperms_bitmap;
316 }
317 }
318 }
319 let allow = explicit_allow.unwrap_or(XpermsBitmap::ALL);
320 XpermsAccessDecision { allow, auditallow, auditdeny }
321 }
322
323 pub(super) fn initial_context(&self, mut id: crate::InitialSid) -> &Context {
325 if id == crate::InitialSid::Init && !self.has_policycap(PolicyCap::UserspaceInitialContext)
327 {
328 id = crate::InitialSid::Kernel
329 }
330
331 let id = le::U32::from(id as u32);
333 &self.initial_sids.data.iter().find(|initial| initial.id() == id).unwrap().context()
334 }
335
336 pub(super) fn fs_uses(&self) -> &[FsUse] {
337 &self.fs_uses.data
338 }
339
340 pub(super) fn genfscon_find_all(&self, fs_type: &str) -> impl Iterator<Item = FsContext> {
341 let query = GenericFsContext::for_query(fs_type);
342 self.generic_fs_contexts.find_all(query, &self.data)
343 }
344
345 pub(super) fn role_allowlist(&self) -> &[RoleAllow] {
346 &self.role_allowlist.data
347 }
348
349 pub(super) fn role_transitions(&self) -> &[RoleTransition] {
350 &self.role_transitions.data
351 }
352
353 pub(super) fn range_transitions(&self) -> &[RangeTransition] {
354 &self.range_transitions.data
355 }
356
357 pub(super) fn access_vector_rules_find(
358 &self,
359 source: TypeId,
360 target: TypeId,
361 class: ClassId,
362 rule_type: u16,
363 ) -> Option<AccessVectorRule> {
364 let query = AccessVectorRuleMetadata::for_query(source, target, class, rule_type);
365 self.access_vector_rules.find(query, &self.data)
366 }
367
368 pub(super) fn access_vector_rules_find_all(
369 &self,
370 source: TypeId,
371 target: TypeId,
372 class: ClassId,
373 rule_type: u16,
374 ) -> impl Iterator<Item = AccessVectorRule> {
375 let query = AccessVectorRuleMetadata::for_query(source, target, class, rule_type);
376 self.access_vector_rules.find_all(query, &self.data)
377 }
378
379 #[cfg(test)]
380 pub(super) fn access_vector_rules_for_test(
381 &self,
382 ) -> impl Iterator<Item = AccessVectorRule> + use<'_> {
383 use super::arrays::testing::access_vector_rule_ordering;
384 use itertools::Itertools;
385
386 self.access_vector_rules
387 .iter(&self.data)
388 .map(|view| view.parse(&self.data))
389 .sorted_by(access_vector_rule_ordering)
390 }
391
392 pub(super) fn compute_filename_transition(
393 &self,
394 source_type: TypeId,
395 target_type: TypeId,
396 class: ClassId,
397 name: NullessByteStr<'_>,
398 ) -> Option<TypeId> {
399 match &self.filename_transition_list {
400 FilenameTransitionList::PolicyVersionGeq33(list) => {
401 let entry = list.data.iter().find(|transition| {
402 transition.target_type() == target_type
403 && transition.target_class() == class
404 && transition.name_bytes() == name.as_bytes()
405 })?;
406 entry
407 .outputs()
408 .iter()
409 .find(|entry| entry.has_source_type(source_type))
410 .map(|x| x.out_type())
411 }
412 FilenameTransitionList::PolicyVersionLeq32(list) => list
413 .data
414 .iter()
415 .find(|transition| {
416 transition.target_class() == class
417 && transition.target_type() == target_type
418 && transition.source_type() == source_type
419 && transition.name_bytes() == name.as_bytes()
420 })
421 .map(|x| x.out_type()),
422 }
423 }
424
425 fn validate_mls_level(
428 &self,
429 level: &MlsLevel,
430 sensitivity_ids: &HashSet<SensitivityId>,
431 category_ids: &HashSet<CategoryId>,
432 ) -> Result<(), anyhow::Error> {
433 validate_id(sensitivity_ids, level.sensitivity(), "sensitivity")?;
434 for id in level.category_ids() {
435 validate_id(category_ids, id, "category")?;
436 }
437 Ok(())
438 }
439
440 fn validate_mls_range(
447 &self,
448 low_level: &MlsLevel,
449 high_level: &Option<MlsLevel>,
450 sensitivity_ids: &HashSet<SensitivityId>,
451 category_ids: &HashSet<CategoryId>,
452 ) -> Result<(), anyhow::Error> {
453 self.validate_mls_level(low_level, sensitivity_ids, category_ids)?;
454 if let Some(high) = high_level {
455 self.validate_mls_level(high, sensitivity_ids, category_ids)?;
456 if !high.dominates(low_level) {
457 return Err(ValidateError::InvalidMlsRange {
458 low: low_level.to_string(self).into(),
459 high: high.to_string(self).into(),
460 }
461 .into());
462 }
463 }
464 Ok(())
465 }
466
467 fn validate_context(
468 &self,
469 context: &Context,
470 user_ids: &HashSet<UserId>,
471 role_ids: &HashSet<RoleId>,
472 type_ids: &HashSet<TypeId>,
473 sensitivity_ids: &HashSet<SensitivityId>,
474 category_ids: &HashSet<CategoryId>,
475 ) -> Result<(), anyhow::Error> {
476 validate_id(user_ids, context.user_id(), "user")?;
477 validate_id(role_ids, context.role_id(), "role")?;
478 validate_id(type_ids, context.type_id(), "type")?;
479 self.validate_mls_range(
480 context.low_level(),
481 context.high_level(),
482 sensitivity_ids,
483 category_ids,
484 )?;
485 Ok(())
486 }
487}
488
489impl ParsedPolicy {
490 pub(super) fn parse(data: PolicyData) -> Result<Self, anyhow::Error> {
493 let policy_size = data.len();
494 if MAXIMUM_POLICY_SIZE <= policy_size {
495 return Err(anyhow::Error::from(ParseError::UnsupportedlyLarge {
496 observed: policy_size,
497 limit: MAXIMUM_POLICY_SIZE,
498 }));
499 }
500 let new_policy =
501 NewPolicy::parse(&data).map_err(|e| anyhow::anyhow!("new parser failed: {:?}", e))?;
502 new_policy.validate().context("validating new policy structure")?;
503
504 let rest_data = new_policy.rest_bytes();
505 let (policy, excess_bytes) = parse_policy_remaining(new_policy, rest_data)?;
506 if excess_bytes > 0 {
507 return Err(anyhow::Error::from(ParseError::TrailingBytes { num_bytes: excess_bytes }));
508 }
509 Ok(policy)
510 }
511}
512
513fn parse_policy_remaining(
515 new_policy: NewPolicy,
516 rest_data: PolicyData,
517) -> Result<(ParsedPolicy, usize), anyhow::Error> {
518 let tail = PolicyCursor::new(&rest_data);
519
520 let (access_vector_rules, tail) = HashedArrayView::<AccessVectorRule>::parse(tail)
521 .map_err(Into::<anyhow::Error>::into)
522 .context("parsing access vector rules")?;
523
524 let (conditional_lists, tail) = SimpleArray::<ConditionalNode>::parse(tail)
525 .map_err(Into::<anyhow::Error>::into)
526 .context("parsing conditional lists")?;
527
528 let (role_transitions, tail) = RoleTransitions::parse(tail)
529 .map_err(Into::<anyhow::Error>::into)
530 .context("parsing role transitions")?;
531
532 let (role_allowlist, tail) = RoleAllows::parse(tail)
533 .map_err(Into::<anyhow::Error>::into)
534 .context("parsing role allow rules")?;
535
536 let (filename_transition_list, tail) = if new_policy.policy_version() >= 33 {
537 let (filename_transition_list, tail) = SimpleArray::<FilenameTransition>::parse(tail)
538 .map_err(Into::<anyhow::Error>::into)
539 .context("parsing standard filename transitions")?;
540 (FilenameTransitionList::PolicyVersionGeq33(filename_transition_list), tail)
541 } else {
542 let (filename_transition_list, tail) =
543 SimpleArray::<DeprecatedFilenameTransition>::parse(tail)
544 .map_err(Into::<anyhow::Error>::into)
545 .context("parsing deprecated filename transitions")?;
546 (FilenameTransitionList::PolicyVersionLeq32(filename_transition_list), tail)
547 };
548
549 let (initial_sids, tail) = SimpleArray::<InitialSid>::parse(tail)
550 .map_err(Into::<anyhow::Error>::into)
551 .context("parsing initial sids")?;
552
553 let (filesystems, tail) = SimpleArray::<NamedContextPair>::parse(tail)
554 .map_err(Into::<anyhow::Error>::into)
555 .context("parsing filesystem contexts")?;
556
557 let (ports, tail) = SimpleArray::<Port>::parse(tail)
558 .map_err(Into::<anyhow::Error>::into)
559 .context("parsing ports")?;
560
561 let (network_interfaces, tail) = SimpleArray::<NamedContextPair>::parse(tail)
562 .map_err(Into::<anyhow::Error>::into)
563 .context("parsing network interfaces")?;
564
565 let (nodes, tail) = SimpleArray::<Node>::parse(tail)
566 .map_err(Into::<anyhow::Error>::into)
567 .context("parsing nodes")?;
568
569 let (fs_uses, tail) = SimpleArray::<FsUse>::parse(tail)
570 .map_err(Into::<anyhow::Error>::into)
571 .context("parsing fs uses")?;
572
573 let (ipv6_nodes, tail) = SimpleArray::<IPv6Node>::parse(tail)
574 .map_err(Into::<anyhow::Error>::into)
575 .context("parsing ipv6 nodes")?;
576
577 let (infinitiband_partition_keys, infinitiband_end_ports, tail) =
578 if new_policy.policy_version() >= MIN_POLICY_VERSION_FOR_INFINITIBAND_PARTITION_KEY {
579 let (infinity_band_partition_keys, tail) =
580 SimpleArray::<InfinitiBandPartitionKey>::parse(tail)
581 .map_err(Into::<anyhow::Error>::into)
582 .context("parsing infiniti band partition keys")?;
583 let (infinitiband_end_ports, tail) = SimpleArray::<InfinitiBandEndPort>::parse(tail)
584 .map_err(Into::<anyhow::Error>::into)
585 .context("parsing infiniti band end ports")?;
586 (Some(infinity_band_partition_keys), Some(infinitiband_end_ports), tail)
587 } else {
588 (None, None, tail)
589 };
590
591 let (generic_fs_contexts, tail) = CustomKeyHashedView::<GenericFsContext>::parse(tail)
592 .map_err(Into::<anyhow::Error>::into)
593 .context("parsing generic filesystem contexts")?;
594
595 let (range_transitions, tail) = SimpleArray::<RangeTransition>::parse(tail)
596 .map_err(Into::<anyhow::Error>::into)
597 .context("parsing range transitions")?;
598
599 let primary_names_count = new_policy.types().primary_names_count();
600 let mut attribute_maps = Vec::with_capacity(primary_names_count as usize);
601 let mut tail = tail;
602
603 for i in 0..primary_names_count {
604 let (item, next_tail) = ExtensibleBitmap::parse(tail)
605 .map_err(Into::<anyhow::Error>::into)
606 .with_context(|| format!("parsing {}th attribute map", i))?;
607 attribute_maps.push(item);
608 tail = next_tail;
609 }
610 let tail = tail;
611 let attribute_maps = attribute_maps;
612
613 let excess_bytes = rest_data.len() - tail.offset() as usize;
614
615 Ok((
616 ParsedPolicy {
617 data: rest_data,
618 new_policy: Arc::new(new_policy),
619
620 access_vector_rules,
621 conditional_lists,
622 role_transitions,
623 role_allowlist,
624 filename_transition_list,
625 initial_sids,
626 filesystems,
627 ports,
628 network_interfaces,
629 nodes,
630 fs_uses,
631 ipv6_nodes,
632 infinitiband_partition_keys,
633 infinitiband_end_ports,
634 generic_fs_contexts,
635 range_transitions,
636 attribute_maps,
637 },
638 excess_bytes,
639 ))
640}
641
642impl ParsedPolicy {
643 pub fn validate(&self) -> Result<(), anyhow::Error> {
644 let need_init_sid = self.has_policycap(PolicyCap::UserspaceInitialContext);
645 let context = PolicyValidationContext {
646 data: self.data.clone(),
647 need_init_sid,
648 new_policy: self.new_policy.clone(),
649 };
650
651 self.access_vector_rules
652 .validate(&context)
653 .map_err(Into::<anyhow::Error>::into)
654 .context("validating access_vector_rules")?;
655 self.conditional_lists
656 .validate(&context)
657 .map_err(Into::<anyhow::Error>::into)
658 .context("validating conditional_lists")?;
659 self.role_transitions
660 .validate(&context)
661 .map_err(Into::<anyhow::Error>::into)
662 .context("validating role_transitions")?;
663 self.role_allowlist
664 .validate(&context)
665 .map_err(Into::<anyhow::Error>::into)
666 .context("validating role_allowlist")?;
667 self.filename_transition_list
668 .validate(&context)
669 .map_err(Into::<anyhow::Error>::into)
670 .context("validating filename_transition_list")?;
671 self.initial_sids
672 .validate(&context)
673 .map_err(Into::<anyhow::Error>::into)
674 .context("validating initial_sids")?;
675 self.filesystems
676 .validate(&context)
677 .map_err(Into::<anyhow::Error>::into)
678 .context("validating filesystems")?;
679 self.ports
680 .validate(&context)
681 .map_err(Into::<anyhow::Error>::into)
682 .context("validating ports")?;
683 self.network_interfaces
684 .validate(&context)
685 .map_err(Into::<anyhow::Error>::into)
686 .context("validating network_interfaces")?;
687 self.nodes
688 .validate(&context)
689 .map_err(Into::<anyhow::Error>::into)
690 .context("validating nodes")?;
691 self.fs_uses
692 .validate(&context)
693 .map_err(Into::<anyhow::Error>::into)
694 .context("validating fs_uses")?;
695 self.ipv6_nodes
696 .validate(&context)
697 .map_err(Into::<anyhow::Error>::into)
698 .context("validating ipv6 nodes")?;
699 self.infinitiband_partition_keys
700 .validate(&context)
701 .map_err(Into::<anyhow::Error>::into)
702 .context("validating infinitiband_partition_keys")?;
703 self.infinitiband_end_ports
704 .validate(&context)
705 .map_err(Into::<anyhow::Error>::into)
706 .context("validating infinitiband_end_ports")?;
707 self.generic_fs_contexts
708 .validate(&context)
709 .map_err(Into::<anyhow::Error>::into)
710 .context("validating generic_fs_contexts")?;
711 self.range_transitions
712 .validate(&context)
713 .map_err(Into::<anyhow::Error>::into)
714 .context("validating range_transitions")?;
715 self.attribute_maps
716 .validate(&context)
717 .map_err(Into::<anyhow::Error>::into)
718 .context("validating attribute_maps")?;
719
720 let user_ids: HashSet<UserId> = self.new_policy.users().iter().map(|x| x.id()).collect();
722 let role_ids: HashSet<RoleId> = self.roles().iter().map(|x| x.id()).collect();
723 let class_ids: HashSet<ClassId> = self.classes().iter().map(|x| x.id()).collect();
724 let type_ids: HashSet<TypeId> = self.new_policy.types().iter().map(|t| t.id()).collect();
725 let sensitivity_ids: HashSet<SensitivityId> =
726 self.new_policy.sensitivities().iter().map(|x| x.id()).collect();
727 let category_ids: HashSet<CategoryId> =
728 self.new_policy.categories().iter().map(|x| x.id()).collect();
729
730 for initial_sid in &self.initial_sids.data {
734 self.validate_context(
735 initial_sid.context(),
736 &user_ids,
737 &role_ids,
738 &type_ids,
739 &sensitivity_ids,
740 &category_ids,
741 )?;
742 }
743
744 for fs_use in &self.fs_uses.data {
748 self.validate_context(
749 fs_use.context(),
750 &user_ids,
751 &role_ids,
752 &type_ids,
753 &sensitivity_ids,
754 &category_ids,
755 )?;
756 }
757
758 for entry in self.generic_fs_contexts.iter(&self.data) {
762 let entry = entry?;
763 for fs_context_view in entry.values().data().iter(&self.data) {
764 let fs_context = fs_context_view.parse(&self.data);
765 self.validate_context(
766 fs_context.context(),
767 &user_ids,
768 &role_ids,
769 &type_ids,
770 &sensitivity_ids,
771 &category_ids,
772 )?;
773 }
774 }
775
776 for transition in &self.role_transitions.data {
778 validate_id(&role_ids, transition.current_role(), "current_role")?;
779 validate_id(&type_ids, transition.type_(), "type")?;
780 validate_id(&class_ids, transition.class(), "class")?;
781 validate_id(&role_ids, transition.new_role(), "new_role")?;
782 }
783 for allow in &self.role_allowlist.data {
784 validate_id(&role_ids, allow.source_role(), "source_role")?;
785 validate_id(&role_ids, allow.new_role(), "new_role")?;
786 }
787
788 for access_vector_rule_view in self.access_vector_rules.iter(&self.data) {
790 let access_vector_rule = access_vector_rule_view.parse(&self.data);
791 if let Some(type_id) = access_vector_rule.new_type() {
792 validate_id(&type_ids, type_id, "new_type")?;
793 }
794 }
795
796 Ok(())
800 }
801}
802
803fn validate_id<IdType: Debug + Eq + Hash>(
804 id_set: &HashSet<IdType>,
805 id: IdType,
806 debug_kind: &'static str,
807) -> Result<(), anyhow::Error> {
808 if !id_set.contains(&id) {
809 return Err(ValidateError::UnknownId { kind: debug_kind, id: format!("{:?}", id) }.into());
810 }
811 Ok(())
812}