1use super::rules::{
6 ExtendedPermissions, HasRuleKey, RuleKind, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES,
7 XPERMS_TYPE_IOCTL_PREFIXES, XPERMS_TYPE_NLMSG, XpermsBitmap,
8};
9use super::traits::{HasName, HasPolicyId};
10use super::{
11 AccessDecision, AccessVector, CategorySet, Class, ClassDefault, ClassDefaultRange, ClassId,
12 FsUseType, GenfsConPath, MlsLevel, OBJECT_R_ROLE_ID, PermissionId, Policy, PolicyCap, RoleId,
13 SELINUX_AVD_FLAGS_PERMISSIVE, SecurityContext, TypeId,
14};
15use crate::{InitialSid, NullessByteStr};
16
17#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
20pub enum XpermsKind {
21 Ioctl,
22 Nlmsg,
23}
24
25#[derive(Debug, Clone, PartialEq)]
31pub struct XpermsAccessDecision {
32 pub allow: XpermsBitmap,
33 pub auditallow: XpermsBitmap,
34 pub auditdeny: XpermsBitmap,
35}
36
37impl XpermsAccessDecision {
38 pub const DENY_ALL: Self = Self {
39 allow: XpermsBitmap::NONE,
40 auditallow: XpermsBitmap::NONE,
41 auditdeny: XpermsBitmap::ALL,
42 };
43 #[cfg(test)]
44 pub const ALLOW_ALL: Self = Self {
45 allow: XpermsBitmap::ALL,
46 auditallow: XpermsBitmap::NONE,
47 auditdeny: XpermsBitmap::ALL,
48 };
49}
50
51#[derive(Clone, Debug, Eq, PartialEq)]
53pub struct FsUseLabelAndType {
54 pub context: SecurityContext,
55 pub use_type: FsUseType,
56}
57
58impl Policy {
59 pub fn has_policycap(&self, policy_cap: PolicyCap) -> bool {
61 self.policy_capabilities().contains(policy_cap)
62 }
63
64 pub fn is_bounded_by(&self, bounded: TypeId, parent: TypeId) -> bool {
66 self.types().get_by_id(bounded).unwrap().bounded_by() == Some(parent)
67 }
68
69 pub fn is_permissive(&self, type_: TypeId) -> bool {
71 self.permissive_map().contains(type_)
72 }
73
74 pub(super) fn object_role(&self) -> RoleId {
77 OBJECT_R_ROLE_ID
78 }
79
80 pub fn initial_context(&self, mut id: InitialSid) -> &SecurityContext {
86 let need_init_sid = self.has_policycap(PolicyCap::UserspaceInitialContext);
87 if id == InitialSid::Init && !need_init_sid {
88 id = InitialSid::Kernel;
89 }
90 self.initial_sids()
91 .get_by_id(id as u32)
92 .expect("initial SID must be present in validated policy")
93 }
94
95 pub fn find_class_permissions_by_name(
99 &self,
100 class_name: &str,
101 ) -> Result<Vec<(PermissionId, Vec<u8>)>, ()> {
102 let classes = self.classes();
103 let class = classes.get_by_name(class_name.as_bytes()).ok_or(())?;
104 let owned_permissions = class.permissions();
105
106 let mut result: Vec<_> = owned_permissions
107 .iter()
108 .map(|permission| (permission.id(), permission.name().to_vec()))
109 .collect();
110
111 if class.common_name().is_empty() {
113 return Ok(result);
114 }
115
116 let common_symbol_permissions =
117 self.common_symbols().get_by_name(class.common_name()).ok_or(())?.permissions();
118
119 result.extend(
120 common_symbol_permissions
121 .iter()
122 .map(|permission| (permission.id(), permission.name().to_vec())),
123 );
124
125 Ok(result)
126 }
127
128 pub fn find_permission_id_by_name(&self, class: &Class, name: &str) -> Option<PermissionId> {
131 let name = name.as_bytes();
132 if let Some(permission) = class.permissions().get_by_name(name) {
133 return Some(permission.id());
134 }
135 let common_name = class.common_name();
136 if !common_name.is_empty() {
137 let common_symbol = self.common_symbols().get_by_name(common_name)?;
138 let permission = common_symbol.permissions().get_by_name(name)?;
139 return Some(permission.id());
140 }
141 None
142 }
143
144 pub fn fs_use_label_and_type(&self, fs_type: NullessByteStr<'_>) -> Option<FsUseLabelAndType> {
147 self.object_contexts()
148 .fs_uses()
149 .iter()
150 .find(|fs_use| fs_use.fs_type() == fs_type.as_bytes())
151 .map(|fs_use| FsUseLabelAndType {
152 context: fs_use.context().clone(),
153 use_type: fs_use.behavior(),
154 })
155 }
156
157 fn genfscon_find_all<'a>(
160 &'a self,
161 fs_type: &'a [u8],
162 ) -> impl Iterator<Item = &'a GenfsConPath> {
163 self.generic_fs_contexts()
164 .iter()
165 .filter(move |entry| entry.fs_type() == fs_type)
166 .flat_map(|entry| entry.paths().iter())
167 }
168
169 pub fn genfscon_label_for_fs_and_path(
174 &self,
175 fs_type: NullessByteStr<'_>,
176 node_path: NullessByteStr<'_>,
177 class: Option<ClassId>,
178 ) -> Option<SecurityContext> {
179 let fs_contexts = self.genfscon_find_all(fs_type.as_bytes());
181
182 #[derive(PartialEq)]
183 enum OrderType {
184 Alphabetic,
185 ByLength,
186 Unknown,
187 }
188 let mut result: Option<&GenfsConPath> = None;
201 let mut order_type = OrderType::Unknown;
202 let mut prev_path_bytes: Option<Vec<u8>> = None;
203 for fs_context in fs_contexts {
204 let path = fs_context.partial_path();
206 if order_type == OrderType::Unknown {
207 if let Some(prev) = &prev_path_bytes {
208 if path.len() > prev.len() {
209 order_type = OrderType::Alphabetic;
210 } else if path < prev.as_slice() {
211 order_type = OrderType::ByLength;
212 }
213 }
214 prev_path_bytes = Some(path.to_vec());
215 }
216
217 let class_matches = class.is_none()
219 || fs_context.class().map(|other| other == class.unwrap()).unwrap_or(true);
220 if !class_matches {
221 continue;
222 }
223
224 if order_type == OrderType::Alphabetic
225 && fs_context.partial_path() > node_path.as_bytes()
226 {
227 break;
232 }
233
234 if node_path.as_bytes().starts_with(fs_context.partial_path()) {
235 if result
236 .as_ref()
237 .map_or(true, |c| c.partial_path().len() < fs_context.partial_path().len())
238 {
239 result = Some(fs_context);
241 if order_type == OrderType::ByLength {
242 break;
243 }
244 }
245 }
246 }
247
248 Some(result?.context().clone())
251 }
252
253 pub fn compute_create_context(
269 &self,
270 source: &SecurityContext,
271 target: &SecurityContext,
272 class: Option<&Class>,
273 name: &[u8],
274 ) -> SecurityContext {
275 let override_type = if !name.is_empty() {
276 class.and_then(|class| {
277 self.filename_transitions().compute_filename_transition(
278 source.type_(),
279 target.type_(),
280 class.id(),
281 name,
282 )
283 })
284 } else {
285 None
286 };
287 self.compute_create_context_internal(source, target, class, override_type)
288 }
289
290 fn compute_create_context_internal(
296 &self,
297 source: &SecurityContext,
298 target: &SecurityContext,
299 class: Option<&Class>,
300 override_type: Option<TypeId>,
301 ) -> SecurityContext {
302 let Some(class) = class else {
303 return SecurityContext::new(
306 source.user(),
307 self.object_role(),
308 target.type_(),
309 source.low_level().clone(),
310 None,
311 );
312 };
313
314 let is_process_or_socket = class.name() == b"process" || class.common_name() == b"socket";
315 let (unspecified_role, unspecified_type, unspecified_low, unspecified_high) =
316 if is_process_or_socket {
317 (source.role(), source.type_(), source.low_level(), source.high_level())
318 } else {
319 (self.object_role(), target.type_(), source.low_level(), None)
320 };
321 let defaults = class.defaults();
322
323 let user = match defaults.user() {
324 ClassDefault::Source => source.user(),
325 ClassDefault::Target => target.user(),
326 ClassDefault::Unspecified => source.user(),
327 };
328
329 let role = match self.role_transition_new_role(source.role(), target.type_(), class) {
330 Some(new_role) => new_role,
331 None => match defaults.role() {
332 ClassDefault::Source => source.role(),
333 ClassDefault::Target => target.role(),
334 ClassDefault::Unspecified => unspecified_role,
335 },
336 };
337
338 let type_ = override_type.unwrap_or_else(|| {
339 let transition = self
340 .access_vector_rules()
341 .find_type_rules(source.type_(), target.type_(), class.id())
342 .find(|rule| rule.kind() == RuleKind::TypeTransition)
343 .map(|rule| rule.new_type());
344 match transition {
345 Some(new_type) => new_type,
346 None => match defaults.type_() {
347 ClassDefault::Source => source.type_(),
348 ClassDefault::Target => target.type_(),
349 ClassDefault::Unspecified => unspecified_type,
350 },
351 }
352 });
353
354 let (low_level, high_level) =
355 match self.range_transition_new_range(source.type_(), target.type_(), class) {
356 Some((low_level, high_level)) => (low_level, high_level),
357 None => match defaults.range() {
358 ClassDefaultRange::SourceLow => (source.low_level().clone(), None),
359 ClassDefaultRange::SourceHigh => (source.effective_high_level().clone(), None),
360 ClassDefaultRange::SourceLowHigh => {
361 (source.low_level().clone(), source.high_level().cloned())
362 }
363 ClassDefaultRange::TargetLow => (target.low_level().clone(), None),
364 ClassDefaultRange::TargetHigh => (target.effective_high_level().clone(), None),
365 ClassDefaultRange::TargetLowHigh => {
366 (target.low_level().clone(), target.high_level().cloned())
367 }
368 ClassDefaultRange::Unspecified => {
369 (unspecified_low.clone(), unspecified_high.cloned())
370 }
371 ClassDefaultRange::Glblub => glblub_range(source, target),
372 },
373 };
374
375 SecurityContext::new(user, role, type_, low_level, high_level)
377 }
378
379 pub fn compute_access_decision(
389 &self,
390 source: &SecurityContext,
391 target: &SecurityContext,
392 class: &Class,
393 ) -> AccessDecision {
394 let mut access_decision =
395 self.compute_explicitly_allowed(source.type_(), target.type_(), class);
396 access_decision.allow -= self.compute_denied_by_constraints(source, target, class);
397 access_decision
398 }
399
400 pub(super) fn compute_explicitly_allowed(
405 &self,
406 source: TypeId,
407 target: TypeId,
408 class: &Class,
409 ) -> AccessDecision {
410 let mut computed_access_vector = AccessVector::NONE;
411 let mut computed_audit_allow = AccessVector::NONE;
412 let mut computed_audit_deny = AccessVector::ALL;
413
414 let source_attributes = &self.type_attribute_maps()[source];
415 let target_attributes = &self.type_attribute_maps()[target];
416
417 for source in source_attributes.iter() {
418 for target in target_attributes.iter() {
419 for rule in self.access_vector_rules().find_av_rules(source, target, class.id()) {
420 match rule.kind() {
421 RuleKind::Allow => computed_access_vector |= rule.access_vector(),
422 RuleKind::AuditAllow => computed_audit_allow |= rule.access_vector(),
423 RuleKind::DontAudit => computed_audit_deny &= rule.access_vector(),
424 _ => {}
425 }
426 }
427 }
428 }
429
430 if let Some(parent) = self.types().get_by_id(source).unwrap().bounded_by() {
434 let access = if source == target {
437 self.compute_explicitly_allowed(parent, parent, class)
438 } else {
439 self.compute_explicitly_allowed(parent, target, class)
440 };
441 computed_access_vector &= access.allow;
442 }
443
444 let mut flags = 0;
445 if self.permissive_map().contains(source) {
446 flags |= SELINUX_AVD_FLAGS_PERMISSIVE;
447 }
448 AccessDecision {
449 allow: computed_access_vector,
450 auditallow: computed_audit_allow,
451 auditdeny: computed_audit_deny,
452 flags,
453 todo_bug: None,
454 }
455 }
456
457 fn compute_denied_by_constraints(
459 &self,
460 source: &SecurityContext,
461 target: &SecurityContext,
462 class: &Class,
463 ) -> AccessVector {
464 let mut denied = AccessVector::NONE;
465 for constraint in class.constraints() {
466 if !constraint.evaluate(source, target) {
467 denied |= constraint.access_vector();
468 }
469 }
470 denied
471 }
472
473 pub fn compute_xperms_access_decision(
476 &self,
477 kind: XpermsKind,
478 source: &SecurityContext,
479 target: &SecurityContext,
480 class: &Class,
481 prefix: u8,
482 ) -> XpermsAccessDecision {
483 let mut explicit_allow: Option<XpermsBitmap> = None;
484 let mut auditallow = XpermsBitmap::NONE;
485 let mut auditdeny = XpermsBitmap::ALL;
486
487 let xperms_types = match kind {
488 XpermsKind::Ioctl => {
489 [XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES, XPERMS_TYPE_IOCTL_PREFIXES].as_slice()
490 }
491 XpermsKind::Nlmsg => [XPERMS_TYPE_NLMSG].as_slice(),
492 };
493 let bitmap_if_prefix_matches = |prefix: u8, xperms: &ExtendedPermissions| match kind {
494 XpermsKind::Ioctl => match xperms.xperms_type() {
495 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES => {
496 (xperms.xperms_optional_prefix() == prefix).then_some(*xperms.xperms_bitmap())
497 }
498 XPERMS_TYPE_IOCTL_PREFIXES => {
499 xperms.xperms_bitmap().contains(prefix).then_some(XpermsBitmap::ALL)
500 }
501 _ => None,
502 },
503 XpermsKind::Nlmsg => match xperms.xperms_type() {
504 XPERMS_TYPE_NLMSG => {
505 (xperms.xperms_optional_prefix() == prefix).then_some(*xperms.xperms_bitmap())
506 }
507 _ => None,
508 },
509 };
510
511 let source_attributes = &self.type_attribute_maps()[source.type_()];
512 let target_attributes = &self.type_attribute_maps()[target.type_()];
513
514 for source in source_attributes.iter() {
515 for target in target_attributes.iter() {
516 for rule in self.access_vector_rules().find_xperm_rules(source, target, class.id())
517 {
518 let xperms = rule.extended_permissions();
519 if rule.kind() == RuleKind::AllowXperm
520 && xperms_types.contains(&xperms.xperms_type())
521 {
522 explicit_allow.get_or_insert(XpermsBitmap::NONE);
523 }
524
525 if let Some(xperms_bitmap) = bitmap_if_prefix_matches(prefix, xperms) {
526 match rule.kind() {
527 RuleKind::AllowXperm => {
528 (*explicit_allow.get_or_insert(XpermsBitmap::NONE)) |=
529 xperms_bitmap;
530 }
531 RuleKind::AuditAllowXperm => auditallow |= xperms_bitmap,
532 RuleKind::DontAuditXperm => auditdeny -= xperms_bitmap,
533 _ => {}
534 }
535 }
536 }
537 }
538 }
539 let allow = explicit_allow.unwrap_or(XpermsBitmap::ALL);
540 XpermsAccessDecision { allow, auditallow, auditdeny }
541 }
542
543 fn role_transition_new_role(
544 &self,
545 current_role: RoleId,
546 type_: TypeId,
547 class: &Class,
548 ) -> Option<RoleId> {
549 self.role_transitions()
550 .iter()
551 .find(|role_transition| {
552 role_transition.current_role() == current_role
553 && role_transition.type_() == type_
554 && role_transition.class() == class.id()
555 })
556 .map(|x| x.new_role())
557 }
558
559 pub fn role_transition_is_explicitly_allowed(&self, source: RoleId, new: RoleId) -> bool {
562 self.role_allowlist()
563 .iter()
564 .any(|role_allow| role_allow.source_role() == source && role_allow.new_role() == new)
565 }
566
567 fn range_transition_new_range(
568 &self,
569 source: TypeId,
570 target: TypeId,
571 class: &Class,
572 ) -> Option<(MlsLevel, Option<MlsLevel>)> {
573 for range_transition in self.range_transitions() {
574 if range_transition.source_type() == source
575 && range_transition.target_type() == target
576 && range_transition.target_class() == class.id()
577 {
578 let mls_range = range_transition.mls_range();
579 let low_level = mls_range.low().clone();
580 let high_level = mls_range.high().cloned();
581 return Some((low_level, high_level));
582 }
583 }
584
585 None
586 }
587}
588
589fn intersect_categories(left: &MlsLevel, right: &MlsLevel) -> CategorySet {
591 let right_categories = right.categories();
592 CategorySet::from_ids(left.categories().iter().filter(|id| right_categories.contains(*id)))
593}
594
595fn glblub_range(
601 source: &SecurityContext,
602 target: &SecurityContext,
603) -> (MlsLevel, Option<MlsLevel>) {
604 let source_low = source.low_level();
605 let source_high = source.effective_high_level();
606 let target_low = target.low_level();
607 let target_high = target.effective_high_level();
608
609 let low_level = MlsLevel::new(
610 std::cmp::max(source_low.sensitivity(), target_low.sensitivity()),
611 intersect_categories(source_low, target_low),
612 );
613 let high_level = MlsLevel::new(
614 std::cmp::min(source_high.sensitivity(), target_high.sensitivity()),
615 intersect_categories(source_high, target_high),
616 );
617 (low_level, Some(high_level))
618}