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 _, 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>,
35 permissions: HashMap<crate::Permission, 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::ObjectClass::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::Permission::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::ObjectClass) -> Option<&'a Class<PS>> {
114 self.classes.get(object_class).map(|offset| &self.parsed_policy.classes()[*offset])
115 }
116
117 pub fn permission<'a>(&'a self, permission: &crate::Permission) -> Option<&'a Permission<PS>> {
118 let target_class = self.class(&permission.class())?;
119 self.permissions.get(permission).map(|p| match p {
120 PermissionIndex::Class { permission_index } => {
121 &target_class.permissions()[*permission_index]
122 }
123 PermissionIndex::Common { common_symbol_index, permission_index } => {
124 let common_symbol = &self.parsed_policy().common_symbols()[*common_symbol_index];
125 &common_symbol.permissions()[*permission_index]
126 }
127 })
128 }
129
130 pub fn new_file_security_context(
135 &self,
136 source: &SecurityContext,
137 target: &SecurityContext,
138 class: &crate::FsNodeClass,
139 ) -> SecurityContext {
140 let object_class = crate::ObjectClass::from(class.clone());
141 self.new_security_context(
142 source,
143 target,
144 &object_class,
145 self.cached_object_r_role,
147 target.type_(),
150 source.low_level(),
153 None,
154 )
155 }
156
157 pub fn new_file_security_context_by_name(
163 &self,
164 source: &SecurityContext,
165 target: &SecurityContext,
166 class: &crate::FsNodeClass,
167 name: NullessByteStr<'_>,
168 ) -> Option<SecurityContext> {
169 let object_class = crate::ObjectClass::from(class.clone());
170 let policy_class = self.class(&object_class)?;
171 let type_id = self.type_transition_new_type_with_name(
172 source.type_(),
173 target.type_(),
174 policy_class,
175 name,
176 )?;
177 Some(self.new_security_context_internal(
178 source,
179 target,
180 &object_class,
181 self.cached_object_r_role,
183 target.type_(),
186 source.low_level(),
189 None,
190 Some(type_id),
192 ))
193 }
194
195 pub fn new_security_context(
215 &self,
216 source: &SecurityContext,
217 target: &SecurityContext,
218 class: &crate::ObjectClass,
219 default_role: RoleId,
220 default_type: TypeId,
221 default_low_level: &SecurityLevel,
222 default_high_level: Option<&SecurityLevel>,
223 ) -> SecurityContext {
224 self.new_security_context_internal(
225 source,
226 target,
227 class,
228 default_role,
229 default_type,
230 default_low_level,
231 default_high_level,
232 None,
233 )
234 }
235
236 fn new_security_context_internal(
242 &self,
243 source: &SecurityContext,
244 target: &SecurityContext,
245 class: &crate::ObjectClass,
246 default_role: RoleId,
247 default_type: TypeId,
248 default_low_level: &SecurityLevel,
249 default_high_level: Option<&SecurityLevel>,
250 override_type: Option<TypeId>,
251 ) -> SecurityContext {
252 let (user, role, type_, low_level, high_level) = if let Some(policy_class) =
253 self.class(&class)
254 {
255 let class_defaults = policy_class.defaults();
256
257 let user = match class_defaults.user() {
258 ClassDefault::Source => source.user(),
259 ClassDefault::Target => target.user(),
260 _ => source.user(),
261 };
262
263 let role =
264 match self.role_transition_new_role(source.role(), target.type_(), policy_class) {
265 Some(new_role) => new_role,
266 None => match class_defaults.role() {
267 ClassDefault::Source => source.role(),
268 ClassDefault::Target => target.role(),
269 _ => default_role,
270 },
271 };
272
273 let type_ = override_type.unwrap_or_else(|| {
274 match self.type_transition_new_type(source.type_(), target.type_(), policy_class) {
275 Some(new_type) => new_type,
276 None => match class_defaults.type_() {
277 ClassDefault::Source => source.type_(),
278 ClassDefault::Target => target.type_(),
279 _ => default_type,
280 },
281 }
282 });
283
284 let (low_level, high_level) =
285 match self.range_transition_new_range(source.type_(), target.type_(), policy_class)
286 {
287 Some((low_level, high_level)) => (low_level, high_level),
288 None => match class_defaults.range() {
289 ClassDefaultRange::SourceLow => (source.low_level().clone(), None),
290 ClassDefaultRange::SourceHigh => (
291 source.high_level().unwrap_or_else(|| source.low_level()).clone(),
292 None,
293 ),
294 ClassDefaultRange::SourceLowHigh => {
295 (source.low_level().clone(), source.high_level().map(Clone::clone))
296 }
297 ClassDefaultRange::TargetLow => (target.low_level().clone(), None),
298 ClassDefaultRange::TargetHigh => (
299 target.high_level().unwrap_or_else(|| target.low_level()).clone(),
300 None,
301 ),
302 ClassDefaultRange::TargetLowHigh => {
303 (target.low_level().clone(), target.high_level().map(Clone::clone))
304 }
305 _ => (default_low_level.clone(), default_high_level.map(Clone::clone)),
306 },
307 };
308
309 (user, role, type_, low_level, high_level)
310 } else {
311 (
314 source.user(),
315 default_role,
316 default_type,
317 default_low_level.clone(),
318 default_high_level.map(Clone::clone),
319 )
320 };
321
322 SecurityContext::new(user, role, type_, low_level, high_level)
324
325 }
327
328 pub(super) fn object_role(&self) -> RoleId {
331 self.cached_object_r_role
332 }
333
334 pub(super) fn parsed_policy(&self) -> &ParsedPolicy<PS> {
335 &self.parsed_policy
336 }
337
338 pub(super) fn initial_context(&self, id: crate::InitialSid) -> SecurityContext {
341 self.resolve_initial_context(id)
343 }
344
345 pub(super) fn fs_use_label_and_type(
348 &self,
349 fs_type: NullessByteStr<'_>,
350 ) -> Option<FsUseLabelAndType> {
351 self.parsed_policy
352 .fs_uses()
353 .iter()
354 .find(|fs_use| fs_use.fs_type() == fs_type.as_bytes())
355 .map(|fs_use| FsUseLabelAndType {
356 context: SecurityContext::new_from_policy_context(fs_use.context()),
357 use_type: fs_use.behavior(),
358 })
359 }
360
361 pub(super) fn genfscon_label_for_fs_and_path(
366 &self,
367 fs_type: NullessByteStr<'_>,
368 node_path: NullessByteStr<'_>,
369 class_id: Option<ClassId>,
370 ) -> Option<SecurityContext> {
371 let fs_contexts = self
373 .parsed_policy
374 .generic_fs_contexts()
375 .iter()
376 .find(|genfscon| genfscon.fs_type() == fs_type.as_bytes())?
377 .contexts();
378
379 let mut result: Option<&FsContext<PS>> = None;
392 for fs_context in fs_contexts {
393 if node_path.0.starts_with(fs_context.partial_path()) {
394 if result.is_none()
395 || result.unwrap().partial_path().len() < fs_context.partial_path().len()
396 {
397 if class_id.is_none()
398 || fs_context
399 .class()
400 .map(|other| other == class_id.unwrap())
401 .unwrap_or(true)
402 {
403 result = Some(fs_context);
404 }
405 }
406 }
407 }
408
409 result.and_then(|fs_context| {
412 Some(SecurityContext::new_from_policy_context(fs_context.context()))
413 })
414 }
415
416 fn resolve_initial_context(&self, id: crate::InitialSid) -> SecurityContext {
418 SecurityContext::new_from_policy_context(self.parsed_policy().initial_context(id))
419 }
420
421 fn role_transition_new_role(
422 &self,
423 current_role: RoleId,
424 type_: TypeId,
425 class: &Class<PS>,
426 ) -> Option<RoleId> {
427 self.parsed_policy
428 .role_transitions()
429 .iter()
430 .find(|role_transition| {
431 role_transition.current_role() == current_role
432 && role_transition.type_() == type_
433 && role_transition.class() == class.id()
434 })
435 .map(|x| x.new_role())
436 }
437
438 #[allow(dead_code)]
439 fn role_transition_is_explicitly_allowed(&self, source_role: RoleId, new_role: RoleId) -> bool {
442 self.parsed_policy
443 .role_allowlist()
444 .iter()
445 .find(|role_allow| {
446 role_allow.source_role() == source_role && role_allow.new_role() == new_role
447 })
448 .is_some()
449 }
450
451 fn type_transition_new_type(
452 &self,
453 source_type: TypeId,
454 target_type: TypeId,
455 class: &Class<PS>,
456 ) -> Option<TypeId> {
457 self.parsed_policy
460 .access_vector_rules()
461 .iter()
462 .find(|access_vector_rule| {
463 access_vector_rule.is_type_transition()
464 && access_vector_rule.source_type() == source_type
465 && access_vector_rule.target_type() == target_type
466 && access_vector_rule.target_class() == class.id()
467 })
468 .map(|x| x.new_type().unwrap())
469 }
470
471 fn type_transition_new_type_with_name(
472 &self,
473 source_type: TypeId,
474 target_type: TypeId,
475 class: &Class<PS>,
476 name: NullessByteStr<'_>,
477 ) -> Option<TypeId> {
478 self.parsed_policy.compute_filename_transition(source_type, target_type, class.id(), name)
479 }
480
481 fn range_transition_new_range(
482 &self,
483 source_type: TypeId,
484 target_type: TypeId,
485 class: &Class<PS>,
486 ) -> Option<(SecurityLevel, Option<SecurityLevel>)> {
487 for range_transition in self.parsed_policy.range_transitions() {
488 if range_transition.source_type() == source_type
489 && range_transition.target_type() == target_type
490 && range_transition.target_class() == class.id()
491 {
492 let mls_range = range_transition.mls_range();
493 let low_level = SecurityLevel::new_from_mls_level(mls_range.low());
494 let high_level = mls_range
495 .high()
496 .as_ref()
497 .map(|high_level| SecurityLevel::new_from_mls_level(high_level));
498 return Some((low_level, high_level));
499 }
500 }
501
502 None
503 }
504}
505
506#[derive(Debug)]
519enum PermissionIndex {
520 Class { permission_index: usize },
522 Common { common_symbol_index: usize, permission_index: usize },
525}
526
527fn get_class_index_by_name<'a, PS: ParseStrategy>(
528 classes: &'a Classes<PS>,
529 name: &str,
530) -> Option<usize> {
531 let name_bytes = name.as_bytes();
532 for i in 0..classes.len() {
533 if classes[i].name_bytes() == name_bytes {
534 return Some(i);
535 }
536 }
537
538 None
539}
540
541fn get_common_symbol_index_by_name_bytes<'a, PS: ParseStrategy>(
542 common_symbols: &'a CommonSymbols<PS>,
543 name_bytes: &[u8],
544) -> Option<usize> {
545 for i in 0..common_symbols.len() {
546 if common_symbols[i].name_bytes() == name_bytes {
547 return Some(i);
548 }
549 }
550
551 None
552}
553
554fn get_permission_index_by_name<'a, PS: ParseStrategy>(
555 common_symbols: &'a CommonSymbols<PS>,
556 class: &'a Class<PS>,
557 name: &str,
558) -> Option<PermissionIndex> {
559 if let Some(permission_index) = get_class_permission_index_by_name(class, name) {
560 Some(PermissionIndex::Class { permission_index })
561 } else if let Some(common_symbol_index) =
562 get_common_symbol_index_by_name_bytes(common_symbols, class.common_name_bytes())
563 {
564 let common_symbol = &common_symbols[common_symbol_index];
565 if let Some(permission_index) = get_common_permission_index_by_name(common_symbol, name) {
566 Some(PermissionIndex::Common { common_symbol_index, permission_index })
567 } else {
568 None
569 }
570 } else {
571 None
572 }
573}
574
575fn get_class_permission_index_by_name<'a, PS: ParseStrategy>(
576 class: &'a Class<PS>,
577 name: &str,
578) -> Option<usize> {
579 let name_bytes = name.as_bytes();
580 let permissions = class.permissions();
581 for i in 0..permissions.len() {
582 if permissions[i].name_bytes() == name_bytes {
583 return Some(i);
584 }
585 }
586
587 None
588}
589
590fn get_common_permission_index_by_name<'a, PS: ParseStrategy>(
591 common_symbol: &'a CommonSymbol<PS>,
592 name: &str,
593) -> Option<usize> {
594 let name_bytes = name.as_bytes();
595 let permissions = common_symbol.permissions();
596 for i in 0..permissions.len() {
597 if permissions[i].name_bytes() == name_bytes {
598 return Some(i);
599 }
600 }
601
602 None
603}