1use super::arrays::{FsContext, FsUseType};
6use super::metadata::HandleUnknown;
7use super::security_context::{SecurityContext, SecurityLevel};
8use super::symbols::{
9 Class, ClassDefault, ClassDefaultRange, Classes, CommonSymbol, CommonSymbols, Permission,
10};
11use super::{ClassId, ParsedPolicy, RoleId, TypeId};
12
13use crate::{ClassPermission as _, NullessByteStr};
14use std::collections::HashMap;
15
16pub struct FsUseLabelAndType {
18 pub context: SecurityContext,
19 pub use_type: FsUseType,
20}
21
22#[derive(Debug)]
30pub(super) struct PolicyIndex {
31 classes: HashMap<crate::ObjectClass, usize>,
37 permissions: HashMap<crate::KernelPermission, PermissionIndex>,
40 parsed_policy: ParsedPolicy,
42 cached_object_r_role: RoleId,
44}
45
46impl PolicyIndex {
47 pub fn new(parsed_policy: ParsedPolicy) -> Result<Self, anyhow::Error> {
54 let policy_classes = parsed_policy.classes();
55 let common_symbols = parsed_policy.common_symbols();
56
57 let mut classes = HashMap::with_capacity(policy_classes.len() * 2);
61
62 for known_class in crate::KernelClass::all_variants() {
66 match get_class_index_by_name(policy_classes, known_class.name()) {
67 Some(class_index) => {
68 classes.insert(known_class.into(), class_index);
69 }
70 None => {
71 if parsed_policy.handle_unknown() == HandleUnknown::Reject {
72 return Err(anyhow::anyhow!("missing object class {:?}", known_class,));
73 }
74 }
75 }
76 }
77
78 for index in 0..policy_classes.len() {
80 let class = &policy_classes[index];
81 classes.insert(class.id().into(), index);
82 }
83
84 classes.shrink_to_fit();
86
87 let mut permissions =
91 HashMap::with_capacity(crate::KernelPermission::all_variants().count());
92 for known_permission in crate::KernelPermission::all_variants() {
93 let object_class = known_permission.class();
94 if let Some(class_index) = classes.get(&object_class.into()) {
95 let class = &policy_classes[*class_index];
96 if let Some(permission_index) =
97 get_permission_index_by_name(common_symbols, class, known_permission.name())
98 {
99 permissions.insert(known_permission, permission_index);
100 } else if parsed_policy.handle_unknown() == HandleUnknown::Reject {
101 return Err(anyhow::anyhow!(
102 "missing permission {:?}:{:?}",
103 object_class.name(),
104 known_permission.name(),
105 ));
106 }
107 }
108 }
109 permissions.shrink_to_fit();
110
111 let cached_object_r_role = parsed_policy
113 .role_by_name("object_r".into())
114 .ok_or_else(|| anyhow::anyhow!("missing 'object_r' role"))?
115 .id();
116
117 let index = Self { classes, permissions, parsed_policy, cached_object_r_role };
118
119 for initial_sids in crate::InitialSid::all_variants() {
121 index.resolve_initial_context(*initial_sids);
122 }
123
124 for fs_use in index.parsed_policy.fs_uses() {
126 SecurityContext::new_from_policy_context(fs_use.context());
127 }
128
129 Ok(index)
130 }
131
132 pub fn class<'a>(&'a self, object_class: crate::ObjectClass) -> Option<&'a Class> {
135 let index = self.classes.get(&object_class)?;
136 Some(&self.parsed_policy.classes()[*index])
137 }
138
139 pub fn permission<'a>(
141 &'a self,
142 permission: &crate::KernelPermission,
143 ) -> Option<&'a Permission> {
144 let target_class = self.class(permission.class().into())?;
145 self.permissions.get(permission).map(|p| match p {
146 PermissionIndex::Class { permission_index } => {
147 &target_class.permissions()[*permission_index]
148 }
149 PermissionIndex::Common { common_symbol_index, permission_index } => {
150 let common_symbol = &self.parsed_policy().common_symbols()[*common_symbol_index];
151 &common_symbol.permissions()[*permission_index]
152 }
153 })
154 }
155
156 pub fn compute_create_context_with_name(
164 &self,
165 source: &SecurityContext,
166 target: &SecurityContext,
167 class: crate::ObjectClass,
168 name: NullessByteStr<'_>,
169 ) -> Option<SecurityContext> {
170 let policy_class = self.class(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 class,
181 Some(type_id),
183 ))
184 }
185
186 pub fn compute_create_context(
201 &self,
202 source: &SecurityContext,
203 target: &SecurityContext,
204 class: crate::ObjectClass,
205 ) -> SecurityContext {
206 self.new_security_context_internal(source, target, class, None)
207 }
208
209 fn new_security_context_internal(
215 &self,
216 source: &SecurityContext,
217 target: &SecurityContext,
218 target_class: crate::ObjectClass,
219 override_type: Option<TypeId>,
220 ) -> SecurityContext {
221 let Some(policy_class) = self.class(target_class) else {
222 return SecurityContext::new(
227 source.user(),
228 self.cached_object_r_role,
229 target.type_(),
230 source.low_level().clone(),
231 None,
232 );
233 };
234
235 let is_process_or_socket = policy_class.name_bytes() == b"process"
236 || policy_class.common_name_bytes() == b"socket";
237 let (unspecified_role, unspecified_type, unspecified_low, unspecified_high) =
238 if is_process_or_socket {
239 (source.role(), source.type_(), source.low_level(), source.high_level())
240 } else {
241 (self.cached_object_r_role, target.type_(), source.low_level(), None)
242 };
243 let class_defaults = policy_class.defaults();
244
245 let user = match class_defaults.user() {
246 ClassDefault::Source => source.user(),
247 ClassDefault::Target => target.user(),
248 ClassDefault::Unspecified => source.user(),
249 };
250
251 let role = match self.role_transition_new_role(source.role(), target.type_(), policy_class)
252 {
253 Some(new_role) => new_role,
254 None => match class_defaults.role() {
255 ClassDefault::Source => source.role(),
256 ClassDefault::Target => target.role(),
257 ClassDefault::Unspecified => unspecified_role,
258 },
259 };
260
261 let type_ = override_type.unwrap_or_else(|| {
262 match self.type_transition_new_type(source.type_(), target.type_(), policy_class) {
263 Some(new_type) => new_type,
264 None => match class_defaults.type_() {
265 ClassDefault::Source => source.type_(),
266 ClassDefault::Target => target.type_(),
267 ClassDefault::Unspecified => unspecified_type,
268 },
269 }
270 });
271
272 let (low_level, high_level) =
273 match self.range_transition_new_range(source.type_(), target.type_(), policy_class) {
274 Some((low_level, high_level)) => (low_level, high_level),
275 None => match class_defaults.range() {
276 ClassDefaultRange::SourceLow => (source.low_level().clone(), None),
277 ClassDefaultRange::SourceHigh => {
278 (source.high_level().unwrap_or_else(|| source.low_level()).clone(), None)
279 }
280 ClassDefaultRange::SourceLowHigh => {
281 (source.low_level().clone(), source.high_level().cloned())
282 }
283 ClassDefaultRange::TargetLow => (target.low_level().clone(), None),
284 ClassDefaultRange::TargetHigh => {
285 (target.high_level().unwrap_or_else(|| target.low_level()).clone(), None)
286 }
287 ClassDefaultRange::TargetLowHigh => {
288 (target.low_level().clone(), target.high_level().cloned())
289 }
290 ClassDefaultRange::Unspecified => {
291 (unspecified_low.clone(), unspecified_high.cloned())
292 }
293 },
294 };
295
296 SecurityContext::new(user, role, type_, low_level, high_level)
298 }
299
300 pub(super) fn object_role(&self) -> RoleId {
303 self.cached_object_r_role
304 }
305
306 pub(super) fn parsed_policy(&self) -> &ParsedPolicy {
307 &self.parsed_policy
308 }
309
310 pub(super) fn initial_context(&self, id: crate::InitialSid) -> SecurityContext {
313 self.resolve_initial_context(id)
315 }
316
317 pub(super) fn fs_use_label_and_type(
320 &self,
321 fs_type: NullessByteStr<'_>,
322 ) -> Option<FsUseLabelAndType> {
323 self.parsed_policy
324 .fs_uses()
325 .iter()
326 .find(|fs_use| fs_use.fs_type() == fs_type.as_bytes())
327 .map(|fs_use| FsUseLabelAndType {
328 context: SecurityContext::new_from_policy_context(fs_use.context()),
329 use_type: fs_use.behavior(),
330 })
331 }
332
333 pub(super) fn genfscon_label_for_fs_and_path(
338 &self,
339 fs_type: NullessByteStr<'_>,
340 node_path: NullessByteStr<'_>,
341 class_id: Option<ClassId>,
342 ) -> Option<SecurityContext> {
343 let fs_contexts = self
345 .parsed_policy
346 .generic_fs_contexts()
347 .iter()
348 .find(|genfscon| genfscon.fs_type() == fs_type.as_bytes())?
349 .contexts();
350
351 let mut result: Option<&FsContext> = None;
364 for fs_context in fs_contexts {
365 if node_path.0.starts_with(fs_context.partial_path()) {
366 if result.is_none()
367 || result.unwrap().partial_path().len() < fs_context.partial_path().len()
368 {
369 if class_id.is_none()
370 || fs_context
371 .class()
372 .map(|other| other == class_id.unwrap())
373 .unwrap_or(true)
374 {
375 result = Some(fs_context);
376 }
377 }
378 }
379 }
380
381 result.and_then(|fs_context| {
384 Some(SecurityContext::new_from_policy_context(fs_context.context()))
385 })
386 }
387
388 fn resolve_initial_context(&self, id: crate::InitialSid) -> SecurityContext {
390 SecurityContext::new_from_policy_context(self.parsed_policy().initial_context(id))
391 }
392
393 fn role_transition_new_role(
394 &self,
395 current_role: RoleId,
396 type_: TypeId,
397 class: &Class,
398 ) -> Option<RoleId> {
399 self.parsed_policy
400 .role_transitions()
401 .iter()
402 .find(|role_transition| {
403 role_transition.current_role() == current_role
404 && role_transition.type_() == type_
405 && role_transition.class() == class.id()
406 })
407 .map(|x| x.new_role())
408 }
409
410 #[allow(dead_code)]
411 fn role_transition_is_explicitly_allowed(&self, source_role: RoleId, new_role: RoleId) -> bool {
414 self.parsed_policy
415 .role_allowlist()
416 .iter()
417 .find(|role_allow| {
418 role_allow.source_role() == source_role && role_allow.new_role() == new_role
419 })
420 .is_some()
421 }
422
423 fn type_transition_new_type(
424 &self,
425 source_type: TypeId,
426 target_type: TypeId,
427 class: &Class,
428 ) -> Option<TypeId> {
429 self.parsed_policy
432 .access_vector_rules()
433 .iter()
434 .find(|access_vector_rule| {
435 access_vector_rule.is_type_transition()
436 && access_vector_rule.source_type() == source_type
437 && access_vector_rule.target_type() == target_type
438 && access_vector_rule.target_class() == class.id()
439 })
440 .map(|x| x.new_type().unwrap())
441 }
442
443 fn type_transition_new_type_with_name(
444 &self,
445 source_type: TypeId,
446 target_type: TypeId,
447 class: &Class,
448 name: NullessByteStr<'_>,
449 ) -> Option<TypeId> {
450 self.parsed_policy.compute_filename_transition(source_type, target_type, class.id(), name)
451 }
452
453 fn range_transition_new_range(
454 &self,
455 source_type: TypeId,
456 target_type: TypeId,
457 class: &Class,
458 ) -> Option<(SecurityLevel, Option<SecurityLevel>)> {
459 for range_transition in self.parsed_policy.range_transitions() {
460 if range_transition.source_type() == source_type
461 && range_transition.target_type() == target_type
462 && range_transition.target_class() == class.id()
463 {
464 let mls_range = range_transition.mls_range();
465 let low_level = SecurityLevel::new_from_mls_level(mls_range.low());
466 let high_level = mls_range
467 .high()
468 .as_ref()
469 .map(|high_level| SecurityLevel::new_from_mls_level(high_level));
470 return Some((low_level, high_level));
471 }
472 }
473
474 None
475 }
476}
477
478#[derive(Debug)]
491enum PermissionIndex {
492 Class { permission_index: usize },
494 Common { common_symbol_index: usize, permission_index: usize },
497}
498
499fn get_class_index_by_name<'a>(classes: &'a Classes, name: &str) -> Option<usize> {
500 let name_bytes = name.as_bytes();
501 for i in 0..classes.len() {
502 if classes[i].name_bytes() == name_bytes {
503 return Some(i);
504 }
505 }
506
507 None
508}
509
510fn get_common_symbol_index_by_name_bytes<'a>(
511 common_symbols: &'a CommonSymbols,
512 name_bytes: &[u8],
513) -> Option<usize> {
514 for i in 0..common_symbols.len() {
515 if common_symbols[i].name_bytes() == name_bytes {
516 return Some(i);
517 }
518 }
519
520 None
521}
522
523fn get_permission_index_by_name<'a>(
524 common_symbols: &'a CommonSymbols,
525 class: &'a Class,
526 name: &str,
527) -> Option<PermissionIndex> {
528 if let Some(permission_index) = get_class_permission_index_by_name(class, name) {
529 Some(PermissionIndex::Class { permission_index })
530 } else if let Some(common_symbol_index) =
531 get_common_symbol_index_by_name_bytes(common_symbols, class.common_name_bytes())
532 {
533 let common_symbol = &common_symbols[common_symbol_index];
534 if let Some(permission_index) = get_common_permission_index_by_name(common_symbol, name) {
535 Some(PermissionIndex::Common { common_symbol_index, permission_index })
536 } else {
537 None
538 }
539 } else {
540 None
541 }
542}
543
544fn get_class_permission_index_by_name<'a>(class: &'a Class, name: &str) -> Option<usize> {
545 let name_bytes = name.as_bytes();
546 let permissions = class.permissions();
547 for i in 0..permissions.len() {
548 if permissions[i].name_bytes() == name_bytes {
549 return Some(i);
550 }
551 }
552
553 None
554}
555
556fn get_common_permission_index_by_name<'a>(
557 common_symbol: &'a CommonSymbol,
558 name: &str,
559) -> Option<usize> {
560 let name_bytes = name.as_bytes();
561 let permissions = common_symbol.permissions();
562 for i in 0..permissions.len() {
563 if permissions[i].name_bytes() == name_bytes {
564 return Some(i);
565 }
566 }
567
568 None
569}