1use super::arrays::{FsContext, FsUseType};
6use super::metadata::HandleUnknown;
7use super::parser::ParseStrategy;
8use super::security_context::{SecurityContext, SecurityLevel};
9use super::symbols::{
10 Class, ClassDefault, ClassDefaultRange, Classes, CommonSymbol, CommonSymbols, Permission,
11};
12use super::{ClassId, ParsedPolicy, RoleId, TypeId};
13
14use crate::{ClassPermission as _, FileClass, FsNodeClass, NullessByteStr};
15use std::collections::HashMap;
16
17pub struct FsUseLabelAndType {
19 pub context: SecurityContext,
20 pub use_type: FsUseType,
21}
22
23#[derive(Debug)]
31pub(super) struct PolicyIndex<PS: ParseStrategy> {
32 classes: HashMap<crate::KernelClass, usize>,
35 permissions: HashMap<crate::KernelPermission, PermissionIndex>,
38 parsed_policy: ParsedPolicy<PS>,
40 cached_object_r_role: RoleId,
42}
43
44impl<PS: ParseStrategy> PolicyIndex<PS> {
45 pub fn new(parsed_policy: ParsedPolicy<PS>) -> Result<Self, anyhow::Error> {
52 let policy_classes = parsed_policy.classes();
53 let common_symbols = parsed_policy.common_symbols();
54
55 let mut classes = HashMap::new();
58 for known_class in crate::KernelClass::all_variants().into_iter() {
59 match get_class_index_by_name(policy_classes, known_class.name()) {
60 Some(class_index) => {
61 classes.insert(known_class, class_index);
62 }
63 None => {
64 if parsed_policy.handle_unknown() == HandleUnknown::Reject {
65 return Err(anyhow::anyhow!("missing object class {:?}", known_class,));
66 }
67 }
68 }
69 }
70
71 let mut permissions = HashMap::new();
74 for known_permission in crate::KernelPermission::all_variants().into_iter() {
75 let object_class = known_permission.class();
76 if let Some(class_index) = classes.get(&object_class) {
77 let class = &policy_classes[*class_index];
78 if let Some(permission_index) =
79 get_permission_index_by_name(common_symbols, class, known_permission.name())
80 {
81 permissions.insert(known_permission, permission_index);
82 } else if parsed_policy.handle_unknown() == HandleUnknown::Reject {
83 return Err(anyhow::anyhow!(
84 "missing permission {:?}:{:?}",
85 object_class.name(),
86 known_permission.name(),
87 ));
88 }
89 }
90 }
91
92 let cached_object_r_role = parsed_policy
94 .role_by_name("object_r".into())
95 .ok_or_else(|| anyhow::anyhow!("missing 'object_r' role"))?
96 .id();
97
98 let index = Self { classes, permissions, parsed_policy, cached_object_r_role };
99
100 for id in crate::InitialSid::all_variants() {
102 index.resolve_initial_context(id);
103 }
104
105 for fs_use in index.parsed_policy.fs_uses() {
107 SecurityContext::new_from_policy_context(fs_use.context());
108 }
109
110 Ok(index)
111 }
112
113 pub fn class<'a>(&'a self, object_class: &crate::KernelClass) -> Option<&'a Class<PS>> {
114 self.classes.get(object_class).map(|offset| &self.parsed_policy.classes()[*offset])
115 }
116
117 pub fn permission<'a>(
118 &'a self,
119 permission: &crate::KernelPermission,
120 ) -> Option<&'a Permission<PS>> {
121 let target_class = self.class(&permission.class())?;
122 self.permissions.get(permission).map(|p| match p {
123 PermissionIndex::Class { permission_index } => {
124 &target_class.permissions()[*permission_index]
125 }
126 PermissionIndex::Common { common_symbol_index, permission_index } => {
127 let common_symbol = &self.parsed_policy().common_symbols()[*common_symbol_index];
128 &common_symbol.permissions()[*permission_index]
129 }
130 })
131 }
132
133 pub fn new_file_security_context(
138 &self,
139 source: &SecurityContext,
140 target: &SecurityContext,
141 class: &crate::FsNodeClass,
142 ) -> SecurityContext {
143 let object_class = crate::KernelClass::from(class.clone());
144 let default_role = match class {
145 FsNodeClass::Socket(_) => source.role(),
147 FsNodeClass::File(file) if *file == FileClass::Fifo => source.role(),
148 FsNodeClass::File(_) => self.cached_object_r_role,
151 };
152 self.new_security_context(
153 source,
154 target,
155 &object_class,
156 default_role,
157 target.type_(),
160 source.low_level(),
163 None,
164 )
165 }
166
167 pub fn new_file_security_context_by_name(
173 &self,
174 source: &SecurityContext,
175 target: &SecurityContext,
176 class: &crate::FsNodeClass,
177 name: NullessByteStr<'_>,
178 ) -> Option<SecurityContext> {
179 let object_class = crate::KernelClass::from(class.clone());
180 let policy_class = self.class(&object_class)?;
181 let type_id = self.type_transition_new_type_with_name(
182 source.type_(),
183 target.type_(),
184 policy_class,
185 name,
186 )?;
187 Some(self.new_security_context_internal(
188 source,
189 target,
190 &object_class,
191 self.cached_object_r_role,
193 target.type_(),
196 source.low_level(),
199 None,
200 Some(type_id),
202 ))
203 }
204
205 pub fn new_security_context(
225 &self,
226 source: &SecurityContext,
227 target: &SecurityContext,
228 class: &crate::KernelClass,
229 default_role: RoleId,
230 default_type: TypeId,
231 default_low_level: &SecurityLevel,
232 default_high_level: Option<&SecurityLevel>,
233 ) -> SecurityContext {
234 self.new_security_context_internal(
235 source,
236 target,
237 class,
238 default_role,
239 default_type,
240 default_low_level,
241 default_high_level,
242 None,
243 )
244 }
245
246 fn new_security_context_internal(
252 &self,
253 source: &SecurityContext,
254 target: &SecurityContext,
255 class: &crate::KernelClass,
256 default_role: RoleId,
257 default_type: TypeId,
258 default_low_level: &SecurityLevel,
259 default_high_level: Option<&SecurityLevel>,
260 override_type: Option<TypeId>,
261 ) -> SecurityContext {
262 let (user, role, type_, low_level, high_level) = if let Some(policy_class) =
263 self.class(&class)
264 {
265 let class_defaults = policy_class.defaults();
266
267 let user = match class_defaults.user() {
268 ClassDefault::Source => source.user(),
269 ClassDefault::Target => target.user(),
270 _ => source.user(),
271 };
272
273 let role =
274 match self.role_transition_new_role(source.role(), target.type_(), policy_class) {
275 Some(new_role) => new_role,
276 None => match class_defaults.role() {
277 ClassDefault::Source => source.role(),
278 ClassDefault::Target => target.role(),
279 _ => default_role,
280 },
281 };
282
283 let type_ = override_type.unwrap_or_else(|| {
284 match self.type_transition_new_type(source.type_(), target.type_(), policy_class) {
285 Some(new_type) => new_type,
286 None => match class_defaults.type_() {
287 ClassDefault::Source => source.type_(),
288 ClassDefault::Target => target.type_(),
289 _ => default_type,
290 },
291 }
292 });
293
294 let (low_level, high_level) =
295 match self.range_transition_new_range(source.type_(), target.type_(), policy_class)
296 {
297 Some((low_level, high_level)) => (low_level, high_level),
298 None => match class_defaults.range() {
299 ClassDefaultRange::SourceLow => (source.low_level().clone(), None),
300 ClassDefaultRange::SourceHigh => (
301 source.high_level().unwrap_or_else(|| source.low_level()).clone(),
302 None,
303 ),
304 ClassDefaultRange::SourceLowHigh => {
305 (source.low_level().clone(), source.high_level().map(Clone::clone))
306 }
307 ClassDefaultRange::TargetLow => (target.low_level().clone(), None),
308 ClassDefaultRange::TargetHigh => (
309 target.high_level().unwrap_or_else(|| target.low_level()).clone(),
310 None,
311 ),
312 ClassDefaultRange::TargetLowHigh => {
313 (target.low_level().clone(), target.high_level().map(Clone::clone))
314 }
315 _ => (default_low_level.clone(), default_high_level.map(Clone::clone)),
316 },
317 };
318
319 (user, role, type_, low_level, high_level)
320 } else {
321 (
324 source.user(),
325 default_role,
326 default_type,
327 default_low_level.clone(),
328 default_high_level.map(Clone::clone),
329 )
330 };
331
332 SecurityContext::new(user, role, type_, low_level, high_level)
334
335 }
337
338 pub(super) fn object_role(&self) -> RoleId {
341 self.cached_object_r_role
342 }
343
344 pub(super) fn parsed_policy(&self) -> &ParsedPolicy<PS> {
345 &self.parsed_policy
346 }
347
348 pub(super) fn initial_context(&self, id: crate::InitialSid) -> SecurityContext {
351 self.resolve_initial_context(id)
353 }
354
355 pub(super) fn fs_use_label_and_type(
358 &self,
359 fs_type: NullessByteStr<'_>,
360 ) -> Option<FsUseLabelAndType> {
361 self.parsed_policy
362 .fs_uses()
363 .iter()
364 .find(|fs_use| fs_use.fs_type() == fs_type.as_bytes())
365 .map(|fs_use| FsUseLabelAndType {
366 context: SecurityContext::new_from_policy_context(fs_use.context()),
367 use_type: fs_use.behavior(),
368 })
369 }
370
371 pub(super) fn genfscon_label_for_fs_and_path(
376 &self,
377 fs_type: NullessByteStr<'_>,
378 node_path: NullessByteStr<'_>,
379 class_id: Option<ClassId>,
380 ) -> Option<SecurityContext> {
381 let fs_contexts = self
383 .parsed_policy
384 .generic_fs_contexts()
385 .iter()
386 .find(|genfscon| genfscon.fs_type() == fs_type.as_bytes())?
387 .contexts();
388
389 let mut result: Option<&FsContext<PS>> = None;
402 for fs_context in fs_contexts {
403 if node_path.0.starts_with(fs_context.partial_path()) {
404 if result.is_none()
405 || result.unwrap().partial_path().len() < fs_context.partial_path().len()
406 {
407 if class_id.is_none()
408 || fs_context
409 .class()
410 .map(|other| other == class_id.unwrap())
411 .unwrap_or(true)
412 {
413 result = Some(fs_context);
414 }
415 }
416 }
417 }
418
419 result.and_then(|fs_context| {
422 Some(SecurityContext::new_from_policy_context(fs_context.context()))
423 })
424 }
425
426 fn resolve_initial_context(&self, id: crate::InitialSid) -> SecurityContext {
428 SecurityContext::new_from_policy_context(self.parsed_policy().initial_context(id))
429 }
430
431 fn role_transition_new_role(
432 &self,
433 current_role: RoleId,
434 type_: TypeId,
435 class: &Class<PS>,
436 ) -> Option<RoleId> {
437 self.parsed_policy
438 .role_transitions()
439 .iter()
440 .find(|role_transition| {
441 role_transition.current_role() == current_role
442 && role_transition.type_() == type_
443 && role_transition.class() == class.id()
444 })
445 .map(|x| x.new_role())
446 }
447
448 #[allow(dead_code)]
449 fn role_transition_is_explicitly_allowed(&self, source_role: RoleId, new_role: RoleId) -> bool {
452 self.parsed_policy
453 .role_allowlist()
454 .iter()
455 .find(|role_allow| {
456 role_allow.source_role() == source_role && role_allow.new_role() == new_role
457 })
458 .is_some()
459 }
460
461 fn type_transition_new_type(
462 &self,
463 source_type: TypeId,
464 target_type: TypeId,
465 class: &Class<PS>,
466 ) -> Option<TypeId> {
467 self.parsed_policy
470 .access_vector_rules()
471 .iter()
472 .find(|access_vector_rule| {
473 access_vector_rule.is_type_transition()
474 && access_vector_rule.source_type() == source_type
475 && access_vector_rule.target_type() == target_type
476 && access_vector_rule.target_class() == class.id()
477 })
478 .map(|x| x.new_type().unwrap())
479 }
480
481 fn type_transition_new_type_with_name(
482 &self,
483 source_type: TypeId,
484 target_type: TypeId,
485 class: &Class<PS>,
486 name: NullessByteStr<'_>,
487 ) -> Option<TypeId> {
488 self.parsed_policy.compute_filename_transition(source_type, target_type, class.id(), name)
489 }
490
491 fn range_transition_new_range(
492 &self,
493 source_type: TypeId,
494 target_type: TypeId,
495 class: &Class<PS>,
496 ) -> Option<(SecurityLevel, Option<SecurityLevel>)> {
497 for range_transition in self.parsed_policy.range_transitions() {
498 if range_transition.source_type() == source_type
499 && range_transition.target_type() == target_type
500 && range_transition.target_class() == class.id()
501 {
502 let mls_range = range_transition.mls_range();
503 let low_level = SecurityLevel::new_from_mls_level(mls_range.low());
504 let high_level = mls_range
505 .high()
506 .as_ref()
507 .map(|high_level| SecurityLevel::new_from_mls_level(high_level));
508 return Some((low_level, high_level));
509 }
510 }
511
512 None
513 }
514}
515
516#[derive(Debug)]
529enum PermissionIndex {
530 Class { permission_index: usize },
532 Common { common_symbol_index: usize, permission_index: usize },
535}
536
537fn get_class_index_by_name<'a, PS: ParseStrategy>(
538 classes: &'a Classes<PS>,
539 name: &str,
540) -> Option<usize> {
541 let name_bytes = name.as_bytes();
542 for i in 0..classes.len() {
543 if classes[i].name_bytes() == name_bytes {
544 return Some(i);
545 }
546 }
547
548 None
549}
550
551fn get_common_symbol_index_by_name_bytes<'a, PS: ParseStrategy>(
552 common_symbols: &'a CommonSymbols<PS>,
553 name_bytes: &[u8],
554) -> Option<usize> {
555 for i in 0..common_symbols.len() {
556 if common_symbols[i].name_bytes() == name_bytes {
557 return Some(i);
558 }
559 }
560
561 None
562}
563
564fn get_permission_index_by_name<'a, PS: ParseStrategy>(
565 common_symbols: &'a CommonSymbols<PS>,
566 class: &'a Class<PS>,
567 name: &str,
568) -> Option<PermissionIndex> {
569 if let Some(permission_index) = get_class_permission_index_by_name(class, name) {
570 Some(PermissionIndex::Class { permission_index })
571 } else if let Some(common_symbol_index) =
572 get_common_symbol_index_by_name_bytes(common_symbols, class.common_name_bytes())
573 {
574 let common_symbol = &common_symbols[common_symbol_index];
575 if let Some(permission_index) = get_common_permission_index_by_name(common_symbol, name) {
576 Some(PermissionIndex::Common { common_symbol_index, permission_index })
577 } else {
578 None
579 }
580 } else {
581 None
582 }
583}
584
585fn get_class_permission_index_by_name<'a, PS: ParseStrategy>(
586 class: &'a Class<PS>,
587 name: &str,
588) -> Option<usize> {
589 let name_bytes = name.as_bytes();
590 let permissions = class.permissions();
591 for i in 0..permissions.len() {
592 if permissions[i].name_bytes() == name_bytes {
593 return Some(i);
594 }
595 }
596
597 None
598}
599
600fn get_common_permission_index_by_name<'a, PS: ParseStrategy>(
601 common_symbol: &'a CommonSymbol<PS>,
602 name: &str,
603) -> Option<usize> {
604 let name_bytes = name.as_bytes();
605 let permissions = common_symbol.permissions();
606 for i in 0..permissions.len() {
607 if permissions[i].name_bytes() == name_bytes {
608 return Some(i);
609 }
610 }
611
612 None
613}