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