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::ObjectClass, usize>,
38 permissions: HashMap<crate::KernelPermission, PermissionIndex>,
41 parsed_policy: ParsedPolicy<PS>,
43 cached_object_r_role: RoleId,
45}
46
47impl<PS: ParseStrategy> PolicyIndex<PS> {
48 pub fn new(parsed_policy: ParsedPolicy<PS>) -> Result<Self, anyhow::Error> {
55 let policy_classes = parsed_policy.classes();
56 let common_symbols = parsed_policy.common_symbols();
57
58 let mut classes = HashMap::with_capacity(policy_classes.len() * 2);
62
63 for known_class in crate::KernelClass::all_variants().into_iter() {
67 match get_class_index_by_name(policy_classes, known_class.name()) {
68 Some(class_index) => {
69 classes.insert(known_class.into(), class_index);
70 }
71 None => {
72 if parsed_policy.handle_unknown() == HandleUnknown::Reject {
73 return Err(anyhow::anyhow!("missing object class {:?}", known_class,));
74 }
75 }
76 }
77 }
78
79 for index in 0..policy_classes.len() {
81 let class = &policy_classes[index];
82 classes.insert(class.id().into(), index);
83 }
84
85 classes.shrink_to_fit();
87
88 let kernel_permissions = crate::KernelPermission::all_variants();
92 let mut permissions = HashMap::with_capacity(kernel_permissions.len());
93 for known_permission in kernel_permissions.into_iter() {
94 let object_class = known_permission.class();
95 if let Some(class_index) = classes.get(&object_class.into()) {
96 let class = &policy_classes[*class_index];
97 if let Some(permission_index) =
98 get_permission_index_by_name(common_symbols, class, known_permission.name())
99 {
100 permissions.insert(known_permission, permission_index);
101 } else if parsed_policy.handle_unknown() == HandleUnknown::Reject {
102 return Err(anyhow::anyhow!(
103 "missing permission {:?}:{:?}",
104 object_class.name(),
105 known_permission.name(),
106 ));
107 }
108 }
109 }
110 permissions.shrink_to_fit();
111
112 let cached_object_r_role = parsed_policy
114 .role_by_name("object_r".into())
115 .ok_or_else(|| anyhow::anyhow!("missing 'object_r' role"))?
116 .id();
117
118 let index = Self { classes, permissions, parsed_policy, cached_object_r_role };
119
120 for id in crate::InitialSid::all_variants() {
122 index.resolve_initial_context(id);
123 }
124
125 for fs_use in index.parsed_policy.fs_uses() {
127 SecurityContext::new_from_policy_context(fs_use.context());
128 }
129
130 Ok(index)
131 }
132
133 pub fn class<'a>(&'a self, object_class: crate::ObjectClass) -> Option<&'a Class<PS>> {
136 let index = self.classes.get(&object_class)?;
137 Some(&self.parsed_policy.classes()[*index])
138 }
139
140 pub fn permission<'a>(
142 &'a self,
143 permission: &crate::KernelPermission,
144 ) -> Option<&'a Permission<PS>> {
145 let target_class = self.class(permission.class().into())?;
146 self.permissions.get(permission).map(|p| match p {
147 PermissionIndex::Class { permission_index } => {
148 &target_class.permissions()[*permission_index]
149 }
150 PermissionIndex::Common { common_symbol_index, permission_index } => {
151 let common_symbol = &self.parsed_policy().common_symbols()[*common_symbol_index];
152 &common_symbol.permissions()[*permission_index]
153 }
154 })
155 }
156
157 pub fn new_file_security_context(
162 &self,
163 source: &SecurityContext,
164 target: &SecurityContext,
165 class: crate::FsNodeClass,
166 ) -> SecurityContext {
167 let default_role = match class {
168 FsNodeClass::Socket(_) => source.role(),
170 FsNodeClass::File(file) if file == FileClass::Fifo => source.role(),
171 FsNodeClass::File(_) => self.cached_object_r_role,
174 };
175 self.new_security_context(
176 source,
177 target,
178 class.into(),
179 default_role,
180 target.type_(),
183 source.low_level(),
186 None,
187 )
188 }
189
190 pub fn new_file_security_context_by_name(
196 &self,
197 source: &SecurityContext,
198 target: &SecurityContext,
199 class: crate::FsNodeClass,
200 name: NullessByteStr<'_>,
201 ) -> Option<SecurityContext> {
202 let object_class = class.into();
203 let policy_class = self.class(object_class)?;
204 let type_id = self.type_transition_new_type_with_name(
205 source.type_(),
206 target.type_(),
207 policy_class,
208 name,
209 )?;
210 Some(self.new_security_context_internal(
211 source,
212 target,
213 object_class,
214 self.cached_object_r_role,
216 target.type_(),
219 source.low_level(),
222 None,
223 Some(type_id),
225 ))
226 }
227
228 pub fn new_security_context(
248 &self,
249 source: &SecurityContext,
250 target: &SecurityContext,
251 class: crate::ObjectClass,
252 default_role: RoleId,
253 default_type: TypeId,
254 default_low_level: &SecurityLevel,
255 default_high_level: Option<&SecurityLevel>,
256 ) -> SecurityContext {
257 self.new_security_context_internal(
258 source,
259 target,
260 class,
261 default_role,
262 default_type,
263 default_low_level,
264 default_high_level,
265 None,
266 )
267 }
268
269 fn new_security_context_internal(
275 &self,
276 source: &SecurityContext,
277 target: &SecurityContext,
278 target_class: crate::ObjectClass,
279 default_role: RoleId,
280 default_type: TypeId,
281 default_low_level: &SecurityLevel,
282 default_high_level: Option<&SecurityLevel>,
283 override_type: Option<TypeId>,
284 ) -> SecurityContext {
285 let (user, role, type_, low_level, high_level) = if let Some(policy_class) =
286 self.class(target_class)
287 {
288 let class_defaults = policy_class.defaults();
289
290 let user = match class_defaults.user() {
291 ClassDefault::Source => source.user(),
292 ClassDefault::Target => target.user(),
293 _ => source.user(),
294 };
295
296 let role =
297 match self.role_transition_new_role(source.role(), target.type_(), policy_class) {
298 Some(new_role) => new_role,
299 None => match class_defaults.role() {
300 ClassDefault::Source => source.role(),
301 ClassDefault::Target => target.role(),
302 _ => default_role,
303 },
304 };
305
306 let type_ = override_type.unwrap_or_else(|| {
307 match self.type_transition_new_type(source.type_(), target.type_(), policy_class) {
308 Some(new_type) => new_type,
309 None => match class_defaults.type_() {
310 ClassDefault::Source => source.type_(),
311 ClassDefault::Target => target.type_(),
312 _ => default_type,
313 },
314 }
315 });
316
317 let (low_level, high_level) =
318 match self.range_transition_new_range(source.type_(), target.type_(), policy_class)
319 {
320 Some((low_level, high_level)) => (low_level, high_level),
321 None => match class_defaults.range() {
322 ClassDefaultRange::SourceLow => (source.low_level().clone(), None),
323 ClassDefaultRange::SourceHigh => (
324 source.high_level().unwrap_or_else(|| source.low_level()).clone(),
325 None,
326 ),
327 ClassDefaultRange::SourceLowHigh => {
328 (source.low_level().clone(), source.high_level().map(Clone::clone))
329 }
330 ClassDefaultRange::TargetLow => (target.low_level().clone(), None),
331 ClassDefaultRange::TargetHigh => (
332 target.high_level().unwrap_or_else(|| target.low_level()).clone(),
333 None,
334 ),
335 ClassDefaultRange::TargetLowHigh => {
336 (target.low_level().clone(), target.high_level().map(Clone::clone))
337 }
338 _ => (default_low_level.clone(), default_high_level.map(Clone::clone)),
339 },
340 };
341
342 (user, role, type_, low_level, high_level)
343 } else {
344 (
347 source.user(),
348 default_role,
349 default_type,
350 default_low_level.clone(),
351 default_high_level.map(Clone::clone),
352 )
353 };
354
355 SecurityContext::new(user, role, type_, low_level, high_level)
357
358 }
360
361 pub(super) fn object_role(&self) -> RoleId {
364 self.cached_object_r_role
365 }
366
367 pub(super) fn parsed_policy(&self) -> &ParsedPolicy<PS> {
368 &self.parsed_policy
369 }
370
371 pub(super) fn initial_context(&self, id: crate::InitialSid) -> SecurityContext {
374 self.resolve_initial_context(id)
376 }
377
378 pub(super) fn fs_use_label_and_type(
381 &self,
382 fs_type: NullessByteStr<'_>,
383 ) -> Option<FsUseLabelAndType> {
384 self.parsed_policy
385 .fs_uses()
386 .iter()
387 .find(|fs_use| fs_use.fs_type() == fs_type.as_bytes())
388 .map(|fs_use| FsUseLabelAndType {
389 context: SecurityContext::new_from_policy_context(fs_use.context()),
390 use_type: fs_use.behavior(),
391 })
392 }
393
394 pub(super) fn genfscon_label_for_fs_and_path(
399 &self,
400 fs_type: NullessByteStr<'_>,
401 node_path: NullessByteStr<'_>,
402 class_id: Option<ClassId>,
403 ) -> Option<SecurityContext> {
404 let fs_contexts = self
406 .parsed_policy
407 .generic_fs_contexts()
408 .iter()
409 .find(|genfscon| genfscon.fs_type() == fs_type.as_bytes())?
410 .contexts();
411
412 let mut result: Option<&FsContext<PS>> = None;
425 for fs_context in fs_contexts {
426 if node_path.0.starts_with(fs_context.partial_path()) {
427 if result.is_none()
428 || result.unwrap().partial_path().len() < fs_context.partial_path().len()
429 {
430 if class_id.is_none()
431 || fs_context
432 .class()
433 .map(|other| other == class_id.unwrap())
434 .unwrap_or(true)
435 {
436 result = Some(fs_context);
437 }
438 }
439 }
440 }
441
442 result.and_then(|fs_context| {
445 Some(SecurityContext::new_from_policy_context(fs_context.context()))
446 })
447 }
448
449 fn resolve_initial_context(&self, id: crate::InitialSid) -> SecurityContext {
451 SecurityContext::new_from_policy_context(self.parsed_policy().initial_context(id))
452 }
453
454 fn role_transition_new_role(
455 &self,
456 current_role: RoleId,
457 type_: TypeId,
458 class: &Class<PS>,
459 ) -> Option<RoleId> {
460 self.parsed_policy
461 .role_transitions()
462 .iter()
463 .find(|role_transition| {
464 role_transition.current_role() == current_role
465 && role_transition.type_() == type_
466 && role_transition.class() == class.id()
467 })
468 .map(|x| x.new_role())
469 }
470
471 #[allow(dead_code)]
472 fn role_transition_is_explicitly_allowed(&self, source_role: RoleId, new_role: RoleId) -> bool {
475 self.parsed_policy
476 .role_allowlist()
477 .iter()
478 .find(|role_allow| {
479 role_allow.source_role() == source_role && role_allow.new_role() == new_role
480 })
481 .is_some()
482 }
483
484 fn type_transition_new_type(
485 &self,
486 source_type: TypeId,
487 target_type: TypeId,
488 class: &Class<PS>,
489 ) -> Option<TypeId> {
490 self.parsed_policy
493 .access_vector_rules()
494 .iter()
495 .find(|access_vector_rule| {
496 access_vector_rule.is_type_transition()
497 && access_vector_rule.source_type() == source_type
498 && access_vector_rule.target_type() == target_type
499 && access_vector_rule.target_class() == class.id()
500 })
501 .map(|x| x.new_type().unwrap())
502 }
503
504 fn type_transition_new_type_with_name(
505 &self,
506 source_type: TypeId,
507 target_type: TypeId,
508 class: &Class<PS>,
509 name: NullessByteStr<'_>,
510 ) -> Option<TypeId> {
511 self.parsed_policy.compute_filename_transition(source_type, target_type, class.id(), name)
512 }
513
514 fn range_transition_new_range(
515 &self,
516 source_type: TypeId,
517 target_type: TypeId,
518 class: &Class<PS>,
519 ) -> Option<(SecurityLevel, Option<SecurityLevel>)> {
520 for range_transition in self.parsed_policy.range_transitions() {
521 if range_transition.source_type() == source_type
522 && range_transition.target_type() == target_type
523 && range_transition.target_class() == class.id()
524 {
525 let mls_range = range_transition.mls_range();
526 let low_level = SecurityLevel::new_from_mls_level(mls_range.low());
527 let high_level = mls_range
528 .high()
529 .as_ref()
530 .map(|high_level| SecurityLevel::new_from_mls_level(high_level));
531 return Some((low_level, high_level));
532 }
533 }
534
535 None
536 }
537}
538
539#[derive(Debug)]
552enum PermissionIndex {
553 Class { permission_index: usize },
555 Common { common_symbol_index: usize, permission_index: usize },
558}
559
560fn get_class_index_by_name<'a, PS: ParseStrategy>(
561 classes: &'a Classes<PS>,
562 name: &str,
563) -> Option<usize> {
564 let name_bytes = name.as_bytes();
565 for i in 0..classes.len() {
566 if classes[i].name_bytes() == name_bytes {
567 return Some(i);
568 }
569 }
570
571 None
572}
573
574fn get_common_symbol_index_by_name_bytes<'a, PS: ParseStrategy>(
575 common_symbols: &'a CommonSymbols<PS>,
576 name_bytes: &[u8],
577) -> Option<usize> {
578 for i in 0..common_symbols.len() {
579 if common_symbols[i].name_bytes() == name_bytes {
580 return Some(i);
581 }
582 }
583
584 None
585}
586
587fn get_permission_index_by_name<'a, PS: ParseStrategy>(
588 common_symbols: &'a CommonSymbols<PS>,
589 class: &'a Class<PS>,
590 name: &str,
591) -> Option<PermissionIndex> {
592 if let Some(permission_index) = get_class_permission_index_by_name(class, name) {
593 Some(PermissionIndex::Class { permission_index })
594 } else if let Some(common_symbol_index) =
595 get_common_symbol_index_by_name_bytes(common_symbols, class.common_name_bytes())
596 {
597 let common_symbol = &common_symbols[common_symbol_index];
598 if let Some(permission_index) = get_common_permission_index_by_name(common_symbol, name) {
599 Some(PermissionIndex::Common { common_symbol_index, permission_index })
600 } else {
601 None
602 }
603 } else {
604 None
605 }
606}
607
608fn get_class_permission_index_by_name<'a, PS: ParseStrategy>(
609 class: &'a Class<PS>,
610 name: &str,
611) -> Option<usize> {
612 let name_bytes = name.as_bytes();
613 let permissions = class.permissions();
614 for i in 0..permissions.len() {
615 if permissions[i].name_bytes() == name_bytes {
616 return Some(i);
617 }
618 }
619
620 None
621}
622
623fn get_common_permission_index_by_name<'a, PS: ParseStrategy>(
624 common_symbol: &'a CommonSymbol<PS>,
625 name: &str,
626) -> Option<usize> {
627 let name_bytes = name.as_bytes();
628 let permissions = common_symbol.permissions();
629 for i in 0..permissions.len() {
630 if permissions[i].name_bytes() == name_bytes {
631 return Some(i);
632 }
633 }
634
635 None
636}