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;
199 let mut order_type = OrderType::Unknown;
200 let mut prev_path_bytes: Option<Vec<u8>> = None;
201 for fs_context in fs_contexts {
202 let path = fs_context.partial_path();
204 if order_type == OrderType::Unknown {
205 if let Some(prev) = &prev_path_bytes {
206 if path.len() > prev.len() {
207 order_type = OrderType::Alphabetic;
208 } else if path < prev.as_slice() {
209 order_type = OrderType::ByLength;
210 }
211 }
212 prev_path_bytes = Some(path.to_vec());
213 }
214
215 let class_matches = class.is_none()
217 || fs_context.class().map(|other| other == class.unwrap()).unwrap_or(true);
218 if !class_matches {
219 continue;
220 }
221
222 if order_type == OrderType::Alphabetic
223 && fs_context.partial_path() > node_path.as_bytes()
224 {
225 break;
230 }
231
232 if node_path.as_bytes().starts_with(fs_context.partial_path()) {
233 if result
234 .as_ref()
235 .map_or(true, |c| c.partial_path().len() < fs_context.partial_path().len())
236 {
237 result = Some(fs_context);
239 if order_type == OrderType::ByLength {
240 break;
241 }
242 }
243 }
244 }
245
246 Some(result?.context().clone())
249 }
250
251 pub fn compute_create_context(
267 &self,
268 source: &SecurityContext,
269 target: &SecurityContext,
270 class: Option<&Class>,
271 name: &[u8],
272 ) -> SecurityContext {
273 let override_type = if !name.is_empty() {
274 class.and_then(|class| {
275 self.filename_transitions().compute_filename_transition(
276 source.type_(),
277 target.type_(),
278 class.id(),
279 name,
280 )
281 })
282 } else {
283 None
284 };
285 self.compute_create_context_internal(source, target, class, override_type)
286 }
287
288 fn compute_create_context_internal(
294 &self,
295 source: &SecurityContext,
296 target: &SecurityContext,
297 class: Option<&Class>,
298 override_type: Option<TypeId>,
299 ) -> SecurityContext {
300 let Some(class) = class else {
301 return SecurityContext::new(
304 source.user(),
305 self.object_role(),
306 target.type_(),
307 source.low_level().clone(),
308 None,
309 );
310 };
311
312 let is_process_or_socket = class.name() == b"process" || class.common_name() == b"socket";
313 let (unspecified_role, unspecified_type, unspecified_low, unspecified_high) =
314 if is_process_or_socket {
315 (source.role(), source.type_(), source.low_level(), source.high_level())
316 } else {
317 (self.object_role(), target.type_(), source.low_level(), None)
318 };
319 let defaults = class.defaults();
320
321 let user = match defaults.user() {
322 ClassDefault::Source => source.user(),
323 ClassDefault::Target => target.user(),
324 ClassDefault::Unspecified => source.user(),
325 };
326
327 let role = match self.role_transition_new_role(source.role(), target.type_(), class) {
328 Some(new_role) => new_role,
329 None => match defaults.role() {
330 ClassDefault::Source => source.role(),
331 ClassDefault::Target => target.role(),
332 ClassDefault::Unspecified => unspecified_role,
333 },
334 };
335
336 let type_ = override_type.unwrap_or_else(|| {
337 let transition = self
338 .access_vector_rules()
339 .find_type_rules(source.type_(), target.type_(), class.id())
340 .find(|rule| rule.kind() == RuleKind::TypeTransition)
341 .map(|rule| rule.new_type());
342 match transition {
343 Some(new_type) => new_type,
344 None => match defaults.type_() {
345 ClassDefault::Source => source.type_(),
346 ClassDefault::Target => target.type_(),
347 ClassDefault::Unspecified => unspecified_type,
348 },
349 }
350 });
351
352 let (low_level, high_level) =
353 match self.range_transition_new_range(source.type_(), target.type_(), class) {
354 Some((low_level, high_level)) => (low_level, high_level),
355 None => match defaults.range() {
356 ClassDefaultRange::SourceLow => (source.low_level().clone(), None),
357 ClassDefaultRange::SourceHigh => (source.effective_high_level().clone(), None),
358 ClassDefaultRange::SourceLowHigh => {
359 (source.low_level().clone(), source.high_level().cloned())
360 }
361 ClassDefaultRange::TargetLow => (target.low_level().clone(), None),
362 ClassDefaultRange::TargetHigh => (target.effective_high_level().clone(), None),
363 ClassDefaultRange::TargetLowHigh => {
364 (target.low_level().clone(), target.high_level().cloned())
365 }
366 ClassDefaultRange::Unspecified => {
367 (unspecified_low.clone(), unspecified_high.cloned())
368 }
369 ClassDefaultRange::Glblub => glblub_range(source, target),
370 },
371 };
372
373 SecurityContext::new(user, role, type_, low_level, high_level)
374 }
375
376 pub fn compute_access_decision(
386 &self,
387 source: &SecurityContext,
388 target: &SecurityContext,
389 class: &Class,
390 ) -> AccessDecision {
391 let mut access_decision =
392 self.compute_explicitly_allowed(source.type_(), target.type_(), class);
393 access_decision.allow -= self.compute_denied_by_constraints(source, target, class);
394 access_decision
395 }
396
397 pub(super) fn compute_explicitly_allowed(
402 &self,
403 source: TypeId,
404 target: TypeId,
405 class: &Class,
406 ) -> AccessDecision {
407 let mut computed_access_vector = AccessVector::NONE;
408 let mut computed_audit_allow = AccessVector::NONE;
409 let mut computed_audit_deny = AccessVector::ALL;
410
411 let source_attributes = &self.type_attribute_maps()[source];
412 let target_attributes = &self.type_attribute_maps()[target];
413
414 for source in source_attributes.iter() {
415 for target in target_attributes.iter() {
416 for rule in self.access_vector_rules().find_av_rules(source, target, class.id()) {
417 match rule.kind() {
418 RuleKind::Allow => computed_access_vector |= rule.access_vector(),
419 RuleKind::AuditAllow => computed_audit_allow |= rule.access_vector(),
420 RuleKind::DontAudit => computed_audit_deny &= rule.access_vector(),
421 _ => {}
422 }
423 }
424 }
425 }
426
427 if let Some(parent) = self.types().get_by_id(source).unwrap().bounded_by() {
431 let access = if source == target {
434 self.compute_explicitly_allowed(parent, parent, class)
435 } else {
436 self.compute_explicitly_allowed(parent, target, class)
437 };
438 computed_access_vector &= access.allow;
439 }
440
441 let mut flags = 0;
442 if self.permissive_map().contains(source) {
443 flags |= SELINUX_AVD_FLAGS_PERMISSIVE;
444 }
445 AccessDecision {
446 allow: computed_access_vector,
447 auditallow: computed_audit_allow,
448 auditdeny: computed_audit_deny,
449 flags,
450 todo_bug: None,
451 }
452 }
453
454 fn compute_denied_by_constraints(
456 &self,
457 source: &SecurityContext,
458 target: &SecurityContext,
459 class: &Class,
460 ) -> AccessVector {
461 let mut denied = AccessVector::NONE;
462 for constraint in class.constraints() {
463 if !constraint.evaluate(source, target) {
464 denied |= constraint.access_vector();
465 }
466 }
467 denied
468 }
469
470 pub fn compute_xperms_access_decision(
473 &self,
474 kind: XpermsKind,
475 source: &SecurityContext,
476 target: &SecurityContext,
477 class: &Class,
478 prefix: u8,
479 ) -> XpermsAccessDecision {
480 let mut explicit_allow: Option<XpermsBitmap> = None;
481 let mut auditallow = XpermsBitmap::NONE;
482 let mut auditdeny = XpermsBitmap::ALL;
483
484 let xperms_types = match kind {
485 XpermsKind::Ioctl => {
486 [XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES, XPERMS_TYPE_IOCTL_PREFIXES].as_slice()
487 }
488 XpermsKind::Nlmsg => [XPERMS_TYPE_NLMSG].as_slice(),
489 };
490 let bitmap_if_prefix_matches = |prefix: u8, xperms: &ExtendedPermissions| match kind {
491 XpermsKind::Ioctl => match xperms.xperms_type() {
492 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES => {
493 (xperms.xperms_optional_prefix() == prefix).then_some(*xperms.xperms_bitmap())
494 }
495 XPERMS_TYPE_IOCTL_PREFIXES => {
496 xperms.xperms_bitmap().contains(prefix).then_some(XpermsBitmap::ALL)
497 }
498 _ => None,
499 },
500 XpermsKind::Nlmsg => match xperms.xperms_type() {
501 XPERMS_TYPE_NLMSG => {
502 (xperms.xperms_optional_prefix() == prefix).then_some(*xperms.xperms_bitmap())
503 }
504 _ => None,
505 },
506 };
507
508 let source_attributes = &self.type_attribute_maps()[source.type_()];
509 let target_attributes = &self.type_attribute_maps()[target.type_()];
510
511 for source in source_attributes.iter() {
512 for target in target_attributes.iter() {
513 for rule in self.access_vector_rules().find_xperm_rules(source, target, class.id())
514 {
515 let xperms = rule.extended_permissions();
516 if rule.kind() == RuleKind::AllowXperm
517 && xperms_types.contains(&xperms.xperms_type())
518 {
519 explicit_allow.get_or_insert(XpermsBitmap::NONE);
520 }
521
522 if let Some(xperms_bitmap) = bitmap_if_prefix_matches(prefix, xperms) {
523 match rule.kind() {
524 RuleKind::AllowXperm => {
525 (*explicit_allow.get_or_insert(XpermsBitmap::NONE)) |=
526 xperms_bitmap;
527 }
528 RuleKind::AuditAllowXperm => auditallow |= xperms_bitmap,
529 RuleKind::DontAuditXperm => auditdeny -= xperms_bitmap,
530 _ => {}
531 }
532 }
533 }
534 }
535 }
536 let allow = explicit_allow.unwrap_or(XpermsBitmap::ALL);
537 XpermsAccessDecision { allow, auditallow, auditdeny }
538 }
539
540 fn role_transition_new_role(
541 &self,
542 current_role: RoleId,
543 type_: TypeId,
544 class: &Class,
545 ) -> Option<RoleId> {
546 self.role_transitions()
547 .iter()
548 .find(|role_transition| {
549 role_transition.current_role() == current_role
550 && role_transition.type_() == type_
551 && role_transition.class() == class.id()
552 })
553 .map(|x| x.new_role())
554 }
555
556 pub fn role_transition_is_explicitly_allowed(&self, source: RoleId, new: RoleId) -> bool {
559 self.role_allowlist()
560 .iter()
561 .any(|role_allow| role_allow.source_role() == source && role_allow.new_role() == new)
562 }
563
564 fn range_transition_new_range(
565 &self,
566 source: TypeId,
567 target: TypeId,
568 class: &Class,
569 ) -> Option<(MlsLevel, Option<MlsLevel>)> {
570 for range_transition in self.range_transitions() {
571 if range_transition.source_type() == source
572 && range_transition.target_type() == target
573 && range_transition.target_class() == class.id()
574 {
575 let mls_range = range_transition.mls_range();
576 let low_level = mls_range.low().clone();
577 let high_level = mls_range.high().cloned();
578 return Some((low_level, high_level));
579 }
580 }
581
582 None
583 }
584}
585
586fn intersect_categories(left: &MlsLevel, right: &MlsLevel) -> CategorySet {
588 let right_categories = right.categories();
589 CategorySet::from_ids(left.categories().iter().filter(|id| right_categories.contains(*id)))
590}
591
592fn glblub_range(
598 source: &SecurityContext,
599 target: &SecurityContext,
600) -> (MlsLevel, Option<MlsLevel>) {
601 let source_low = source.low_level();
602 let source_high = source.effective_high_level();
603 let target_low = target.low_level();
604 let target_high = target.effective_high_level();
605
606 let low_level = MlsLevel::new(
607 std::cmp::max(source_low.sensitivity(), target_low.sensitivity()),
608 intersect_categories(source_low, target_low),
609 );
610 let high_level = MlsLevel::new(
611 std::cmp::min(source_high.sensitivity(), target_high.sensitivity()),
612 intersect_categories(source_high, target_high),
613 );
614 (low_level, Some(high_level))
615}