1use crate::access_vector_cache::{AccessVectorCache, Query};
6use crate::policy::{AccessVector, KernelAccessDecision, SELINUX_AVD_FLAGS_PERMISSIVE, XpermsKind};
7use crate::security_server::{PolicySeqNo, SecurityServer};
8use crate::{ClassPermission, FdPermission, KernelClass, KernelPermission, SecurityId};
9
10use std::num::NonZeroU32;
11
12pub use crate::local_cache::PerThreadCache;
13
14#[derive(Clone, Debug, PartialEq)]
16pub struct PermissionCheckResult {
17 pub granted: bool,
19
20 pub audit: bool,
25
26 pub permissive: bool,
29
30 pub todo_bug: Option<NonZeroU32>,
33}
34
35impl PermissionCheckResult {
36 pub fn permit(&self) -> bool {
38 self.granted || self.permissive
39 }
40}
41
42pub struct PermissionCheck<'a> {
46 security_server: &'a SecurityServer,
47 access_vector_cache: &'a AccessVectorCache,
48 local_cache: &'a PerThreadCache,
49}
50
51impl<'a> PermissionCheck<'a> {
52 pub(crate) fn new(
53 security_server: &'a SecurityServer,
54 access_vector_cache: &'a AccessVectorCache,
55 local_cache: &'a PerThreadCache,
56 ) -> Self {
57 Self { security_server, access_vector_cache, local_cache }
58 }
59
60 pub fn has_permission<P: ClassPermission + Into<KernelPermission> + Clone + 'static>(
64 &self,
65 source_sid: SecurityId,
66 target_sid: SecurityId,
67 permission: P,
68 ) -> PermissionCheckResult {
69 let policy_seqno = self.security_server.policy_seqno();
70 let result = has_permission(
71 self.local_cache,
72 self.access_vector_cache,
73 policy_seqno,
74 source_sid,
75 target_sid,
76 permission.into(),
77 );
78 self.apply_enforcement(result)
79 }
80
81 pub fn has_extended_permission<
95 P: ClassPermission + Into<KernelPermission> + Clone + 'static,
96 >(
97 &self,
98 xperms_kind: XpermsKind,
99 source_sid: SecurityId,
100 target_sid: SecurityId,
101 permission: P,
102 xperm: u16,
103 ) -> PermissionCheckResult {
104 let permission: KernelPermission = permission.into();
105 let policy_seqno = self.security_server.policy_seqno();
106 let result = self.local_cache.check_xperm(
107 policy_seqno,
108 xperms_kind,
109 source_sid,
110 target_sid,
111 permission,
112 xperm,
113 || {
114 has_extended_permission(
115 self.access_vector_cache,
116 xperms_kind,
117 source_sid,
118 target_sid,
119 permission,
120 xperm,
121 )
122 },
123 );
124 self.apply_enforcement(result)
125 }
126
127 fn apply_enforcement(&self, mut result: PermissionCheckResult) -> PermissionCheckResult {
128 if !result.granted {
129 if !self.security_server.is_enforcing() {
130 result.permissive = true;
131 result.todo_bug = None;
132 } else if result.todo_bug.is_some() {
133 result.granted = true;
134 }
135 } else {
136 result.todo_bug = None;
137 }
138 result
139 }
140
141 pub fn security_server(&self) -> &SecurityServer {
144 self.security_server
145 }
146
147 pub fn compute_create_sid(
152 &self,
153 source_sid: SecurityId,
154 target_sid: SecurityId,
155 target_class: KernelClass,
156 name: &[u8],
157 ) -> Result<SecurityId, anyhow::Error> {
158 self.access_vector_cache.compute_create_sid(source_sid, target_sid, target_class, name)
159 }
160
161 pub fn compute_access_decision(
163 &self,
164 source_sid: SecurityId,
165 target_sid: SecurityId,
166 target_class: KernelClass,
167 ) -> KernelAccessDecision {
168 self.local_cache.lookup_access_decision(
169 self.security_server.policy_seqno(),
170 source_sid,
171 target_sid,
172 target_class,
173 || {
174 self.access_vector_cache.compute_access_decision(
175 source_sid,
176 target_sid,
177 target_class,
178 )
179 },
180 )
181 }
182}
183
184fn has_permission(
186 local_cache: &PerThreadCache,
187 query: &impl Query,
188 policy_seqno: PolicySeqNo,
189 source_sid: SecurityId,
190 target_sid: SecurityId,
191 permission: KernelPermission,
192) -> PermissionCheckResult {
193 let permission_access_vector = permission.as_access_vector();
194
195 if permission == KernelPermission::Fd(FdPermission::Use) {
196 return local_cache.lookup_fd_use(policy_seqno, source_sid, target_sid, || {
198 let decision = query.compute_access_decision(source_sid, target_sid, KernelClass::Fd);
199 access_decision_to_permission_check_result(permission_access_vector, decision)
200 });
201 }
202
203 let decision = local_cache.lookup_access_decision(
204 policy_seqno,
205 source_sid,
206 target_sid,
207 permission.class(),
208 || query.compute_access_decision(source_sid, target_sid, permission.class()),
209 );
210 access_decision_to_permission_check_result(permission_access_vector, decision)
211}
212
213fn access_decision_to_permission_check_result(
214 permission_access_vector: AccessVector,
215 decision: KernelAccessDecision,
216) -> PermissionCheckResult {
217 let permissive = decision.flags & SELINUX_AVD_FLAGS_PERMISSIVE != 0;
218 let granted = permission_access_vector & decision.allow == permission_access_vector;
219 let audit = permission_access_vector & decision.audit != AccessVector::NONE;
220 PermissionCheckResult { granted, audit, permissive, todo_bug: decision.todo_bug }
221}
222
223fn has_extended_permission(
225 query: &impl Query,
226 xperms_kind: XpermsKind,
227 source_sid: SecurityId,
228 target_sid: SecurityId,
229 permission: KernelPermission,
230 xperm: u16,
231) -> PermissionCheckResult {
232 let [xperms_postfix, xperms_prefix] = xperm.to_le_bytes();
233 let xperms_decision = query.compute_xperms_access_decision(
234 xperms_kind,
235 source_sid,
236 target_sid,
237 permission,
238 xperms_prefix,
239 );
240
241 let granted = xperms_decision.allow.contains(xperms_postfix);
242 let audit = xperms_decision.audit.contains(xperms_postfix);
243 let permissive = xperms_decision.permissive;
244 let mut result = PermissionCheckResult { granted, audit, permissive, todo_bug: None };
245
246 if !result.permit() && xperms_decision.has_todo {
247 let base_decision =
250 query.compute_access_decision(source_sid, target_sid, permission.class());
251 result.todo_bug = base_decision.todo_bug;
252 }
253
254 result
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260 use crate::access_vector_cache::KernelXpermsAccessDecision;
261 use crate::policy::{
262 AccessDecision, AccessVector, AccessVectorComputer, KernelAccessDecision, XpermsBitmap,
263 };
264 use crate::{CommonFsNodePermission, FileClass, ForClass, KernelClass, ProcessPermission};
265
266 use std::num::NonZeroU32;
267 use std::sync::LazyLock;
268 use std::sync::atomic::{AtomicU32, Ordering};
269
270 static A_TEST_SID: LazyLock<SecurityId> = LazyLock::new(unique_sid);
272
273 fn unique_sid() -> SecurityId {
275 static NEXT_ID: AtomicU32 = AtomicU32::new(1000);
276 SecurityId(NonZeroU32::new(NEXT_ID.fetch_add(1, Ordering::AcqRel)).unwrap())
277 }
278
279 fn access_decision_to_kernel_access_decision(
281 _class: KernelClass,
282 decision: AccessDecision,
283 ) -> KernelAccessDecision {
284 KernelAccessDecision {
285 allow: decision.allow,
286 audit: (decision.allow & decision.auditallow) | (!decision.allow & decision.auditdeny),
287 todo_bug: decision.todo_bug,
288 flags: decision.flags,
289 }
290 }
291
292 #[derive(Default)]
293 pub struct DenyAllPermissions;
294
295 impl Query for DenyAllPermissions {
296 fn compute_access_decision(
297 &self,
298 _source_sid: SecurityId,
299 _target_sid: SecurityId,
300 _target_class: KernelClass,
301 ) -> KernelAccessDecision {
302 KernelAccessDecision {
303 allow: AccessVector::NONE,
304 audit: AccessVector::ALL,
305 flags: 0,
306 todo_bug: None,
307 }
308 }
309
310 fn compute_create_sid(
311 &self,
312 _source_sid: SecurityId,
313 _target_sid: SecurityId,
314 _target_class: KernelClass,
315 _name: &[u8],
316 ) -> Result<SecurityId, anyhow::Error> {
317 unreachable!();
318 }
319
320 fn compute_xperms_access_decision(
321 &self,
322 _xperms_kind: XpermsKind,
323 _source_sid: SecurityId,
324 _target_sid: SecurityId,
325 _permission: KernelPermission,
326 _xperms_prefix: u8,
327 ) -> KernelXpermsAccessDecision {
328 KernelXpermsAccessDecision {
329 allow: XpermsBitmap::NONE,
330 audit: XpermsBitmap::ALL,
331 permissive: false,
332 has_todo: false,
333 }
334 }
335 }
336
337 impl AccessVectorComputer for DenyAllPermissions {
338 fn access_decision_to_kernel_access_decision(
339 &self,
340 class: KernelClass,
341 av: AccessDecision,
342 ) -> KernelAccessDecision {
343 access_decision_to_kernel_access_decision(class, av)
344 }
345 }
346
347 #[derive(Default)]
349 struct AllowAllPermissions;
350
351 impl Query for AllowAllPermissions {
352 fn compute_access_decision(
353 &self,
354 _source_sid: SecurityId,
355 _target_sid: SecurityId,
356 _target_class: KernelClass,
357 ) -> KernelAccessDecision {
358 KernelAccessDecision {
359 allow: AccessVector::ALL,
360 audit: AccessVector::NONE,
361 flags: 0,
362 todo_bug: None,
363 }
364 }
365
366 fn compute_create_sid(
367 &self,
368 _source_sid: SecurityId,
369 _target_sid: SecurityId,
370 _target_class: KernelClass,
371 _name: &[u8],
372 ) -> Result<SecurityId, anyhow::Error> {
373 unreachable!();
374 }
375
376 fn compute_xperms_access_decision(
377 &self,
378 _xperms_kind: XpermsKind,
379 _source_sid: SecurityId,
380 _target_sid: SecurityId,
381 _permission: KernelPermission,
382 _xperms_prefix: u8,
383 ) -> KernelXpermsAccessDecision {
384 KernelXpermsAccessDecision {
385 allow: XpermsBitmap::ALL,
386 audit: XpermsBitmap::NONE,
387 permissive: false,
388 has_todo: false,
389 }
390 }
391 }
392
393 impl AccessVectorComputer for AllowAllPermissions {
394 fn access_decision_to_kernel_access_decision(
395 &self,
396 class: KernelClass,
397 av: AccessDecision,
398 ) -> KernelAccessDecision {
399 access_decision_to_kernel_access_decision(class, av)
400 }
401 }
402
403 #[test]
404 fn has_permission_both() {
405 let deny_all = DenyAllPermissions::default();
406 let allow_all = AllowAllPermissions::default();
407
408 let permissions = [ProcessPermission::Fork, ProcessPermission::Transition];
411 for permission in permissions {
412 let local_cache1 = PerThreadCache::default();
413 let result = has_permission(
415 &local_cache1,
416 &deny_all,
417 PolicySeqNo::INITIAL,
418 *A_TEST_SID,
419 *A_TEST_SID,
420 permission.into(),
421 );
422 assert_eq!(
423 result,
424 PermissionCheckResult {
425 granted: false,
426 audit: true,
427 permissive: false,
428 todo_bug: None
429 }
430 );
431 assert!(!result.permit());
432
433 let local_cache2 = PerThreadCache::default();
434 let result = has_permission(
436 &local_cache2,
437 &allow_all,
438 PolicySeqNo::INITIAL,
439 *A_TEST_SID,
440 *A_TEST_SID,
441 permission.into(),
442 );
443 assert_eq!(
444 result,
445 PermissionCheckResult {
446 granted: true,
447 audit: false,
448 permissive: false,
449 todo_bug: None
450 }
451 );
452 assert!(result.permit());
453 }
454 }
455
456 #[test]
457 fn has_ioctl_permission_enforcing() {
458 let deny_all = DenyAllPermissions::default();
459 let allow_all = AllowAllPermissions::default();
460 let permission = CommonFsNodePermission::Ioctl.for_class(FileClass::File);
461
462 let result = has_extended_permission(
464 &deny_all,
465 XpermsKind::Ioctl,
466 *A_TEST_SID,
467 *A_TEST_SID,
468 permission.into(),
469 0xabcd,
470 );
471 assert_eq!(
472 result,
473 PermissionCheckResult {
474 granted: false,
475 audit: true,
476 permissive: false,
477 todo_bug: None
478 }
479 );
480 assert!(!result.permit());
481
482 let result = has_extended_permission(
484 &allow_all,
485 XpermsKind::Ioctl,
486 *A_TEST_SID,
487 *A_TEST_SID,
488 permission.into(),
489 0xabcd,
490 );
491 assert_eq!(
492 result,
493 PermissionCheckResult {
494 granted: true,
495 audit: false,
496 permissive: false,
497 todo_bug: None
498 }
499 );
500 assert!(result.permit());
501 }
502
503 fn security_server_with_tests_policy() -> std::sync::Arc<SecurityServer> {
504 const POLICY: &[u8] =
505 include_bytes!("../testdata/micro_policies/security_server_tests_policy");
506 let security_server = SecurityServer::new_default();
507 assert!(security_server.load_policy(POLICY.into()).is_ok());
508 security_server
509 }
510
511 #[test]
512 fn has_ioctl_permission_not_enforcing() {
513 let security_server = security_server_with_tests_policy();
514 let enforcing_values = [true, false];
515 for enforcing in enforcing_values {
516 security_server.set_enforcing(enforcing);
517
518 let sid =
519 security_server.security_context_to_sid("user0:object_r:type0:s0".into()).unwrap();
520 let local_cache = PerThreadCache::default();
521 let permission_check = security_server.as_permission_check(&local_cache);
522
523 let permission = CommonFsNodePermission::Ioctl.for_class(FileClass::File);
524
525 let result = permission_check.has_extended_permission(
529 XpermsKind::Ioctl,
530 sid,
531 sid,
532 permission,
533 0xabcd,
534 );
535 assert_eq!(
536 result,
537 PermissionCheckResult {
538 granted: false,
539 audit: true,
540 permissive: !enforcing,
541 todo_bug: None
542 }
543 );
544 assert_eq!(result.permit(), !enforcing);
545 }
546 }
547}