Skip to main content

selinux/
security_server.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::access_vector_cache::{
6    AccessVectorCache, CacheStats, KernelXpermsAccessDecision, Query,
7};
8use crate::exceptions_config::ExceptionsConfig;
9use crate::permission_check::{PerThreadCache, PermissionCheck};
10use crate::policy::metadata::HandleUnknown;
11use crate::policy::parser::PolicyData;
12use crate::policy::{
13    AccessDecision, AccessVector, AccessVectorComputer, ClassId, ClassPermissionId,
14    FsUseLabelAndType, FsUseType, KernelAccessDecision, Policy, SELINUX_AVD_FLAGS_PERMISSIVE,
15    SecurityContext, XpermsBitmap, XpermsKind, parse_policy_by_value,
16};
17use crate::sid_table::SidTable;
18use crate::sync::RwLock;
19use crate::{
20    ClassPermission, FileSystemLabel, FileSystemLabelingScheme, FileSystemMountOptions,
21    FileSystemMountSids, FsNodeClass, InitialSid, KernelClass, KernelPermission, NullessByteStr,
22    ObjectClass, PolicyCap, SeLinuxStatus, SeLinuxStatusPublisher, SecurityId,
23};
24use anyhow::Context as _;
25use std::collections::HashMap;
26use std::ops::DerefMut;
27use std::sync::Arc;
28use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
29
30const ROOT_PATH: &'static str = "/";
31
32struct ActivePolicy {
33    /// Parsed policy structure.
34    parsed: Arc<Policy>,
35
36    /// The binary policy that was previously passed to `load_policy()`.
37    binary: PolicyData,
38
39    /// Allocates and maintains the mapping between `SecurityId`s (SIDs) and Security Contexts.
40    sid_table: SidTable,
41
42    /// Describes access checks that should be granted, with associated bug Ids.
43    exceptions: ExceptionsConfig,
44}
45
46#[derive(Default)]
47struct SeLinuxBooleans {
48    /// Active values for all of the booleans defined by the policy.
49    /// Entries are created at policy load for each policy-defined conditional.
50    active: HashMap<String, bool>,
51    /// Pending values for any booleans modified since the last commit.
52    pending: HashMap<String, bool>,
53}
54
55impl SeLinuxBooleans {
56    fn reset(&mut self, booleans: Vec<(String, bool)>) {
57        self.active = HashMap::from_iter(booleans);
58        self.pending.clear();
59    }
60    fn names(&self) -> Vec<String> {
61        self.active.keys().cloned().collect()
62    }
63    fn set_pending(&mut self, name: &str, value: bool) -> Result<(), ()> {
64        if !self.active.contains_key(name) {
65            return Err(());
66        }
67        self.pending.insert(name.into(), value);
68        Ok(())
69    }
70    fn get(&self, name: &str) -> Result<(bool, bool), ()> {
71        let active = self.active.get(name).ok_or(())?;
72        let pending = self.pending.get(name).unwrap_or(active);
73        Ok((*active, *pending))
74    }
75    fn commit_pending(&mut self) {
76        self.active.extend(self.pending.drain());
77    }
78}
79
80struct SecurityServerState {
81    /// Describes the currently active policy.
82    active_policy: Option<ActivePolicy>,
83
84    /// Holds active and pending states for each boolean defined by policy.
85    booleans: SeLinuxBooleans,
86
87    /// Write-only interface to the data stored in the selinuxfs status file.
88    status_publisher: Option<Box<dyn SeLinuxStatusPublisher>>,
89}
90
91impl SecurityServerState {
92    fn deny_unknown(&self) -> bool {
93        self.active_policy
94            .as_ref()
95            .map_or(true, |p| p.parsed.handle_unknown() != HandleUnknown::Allow)
96    }
97    fn reject_unknown(&self) -> bool {
98        self.active_policy
99            .as_ref()
100            .map_or(false, |p| p.parsed.handle_unknown() == HandleUnknown::Reject)
101    }
102
103    fn expect_active_policy(&self) -> &ActivePolicy {
104        &self.active_policy.as_ref().expect("policy should be loaded")
105    }
106
107    fn expect_active_policy_mut(&mut self) -> &mut ActivePolicy {
108        self.active_policy.as_mut().expect("policy should be loaded")
109    }
110
111    fn compute_access_decision_raw(
112        &self,
113        source_sid: SecurityId,
114        target_sid: SecurityId,
115        target_class: ObjectClass,
116    ) -> AccessDecision {
117        let Some(active_policy) = self.active_policy.as_ref() else {
118            // All permissions are allowed when no policy is loaded, regardless of enforcing state.
119            return AccessDecision::allow(AccessVector::ALL);
120        };
121
122        let source_context = active_policy.sid_table.sid_to_security_context(source_sid);
123        let target_context = active_policy.sid_table.sid_to_security_context(target_sid);
124
125        let mut decision = active_policy.parsed.compute_access_decision(
126            &source_context,
127            &target_context,
128            target_class,
129        );
130
131        decision.todo_bug = active_policy.exceptions.lookup(
132            source_context.type_(),
133            target_context.type_(),
134            target_class,
135        );
136
137        decision
138    }
139}
140
141pub(crate) struct SecurityServerBackend {
142    /// The mutable state of the security server.
143    state: RwLock<SecurityServerState>,
144
145    /// True if the security server is enforcing, rather than permissive.
146    /// Only modified with the `state` lock taken.
147    is_enforcing: AtomicBool,
148
149    /// Count of changes to the active policy.  Changes include both loads
150    /// of complete new policies, and modifications to a previously loaded
151    /// policy, e.g. by committing new values to conditional booleans in it.
152    /// Only modified with the `state` lock taken.
153    policy_change_count: AtomicU32,
154}
155
156pub struct SecurityServer {
157    /// The access vector cache that is shared between threads subject to access control by this
158    /// security server.
159    access_vector_cache: AccessVectorCache,
160
161    /// A shared reference to the security server's state.
162    backend: Arc<SecurityServerBackend>,
163
164    /// Optional set of exceptions to apply to access checks, via `ExceptionsConfig`.
165    exceptions: Vec<String>,
166}
167
168impl SecurityServer {
169    /// Returns an instance with default configuration and no exceptions.
170    pub fn new_default() -> Arc<Self> {
171        Self::new(String::new(), Vec::new())
172    }
173
174    /// Returns an instance with the specified options and exceptions configured.
175    pub fn new(options: String, exceptions: Vec<String>) -> Arc<Self> {
176        // No options are currently supported.
177        assert_eq!(options, String::new());
178
179        let backend = Arc::new(SecurityServerBackend {
180            state: RwLock::new(SecurityServerState {
181                active_policy: None,
182                booleans: SeLinuxBooleans::default(),
183                status_publisher: None,
184            }),
185            is_enforcing: AtomicBool::new(false),
186            policy_change_count: AtomicU32::new(0),
187        });
188
189        let access_vector_cache = AccessVectorCache::new(backend.clone());
190
191        Arc::new(Self { access_vector_cache, backend, exceptions })
192    }
193
194    /// Converts a shared pointer to [`SecurityServer`] to a [`PermissionCheck`] without consuming
195    /// the pointer.
196    pub fn as_permission_check<'a>(
197        self: &'a Self,
198        local_cache: &'a PerThreadCache,
199    ) -> PermissionCheck<'a> {
200        PermissionCheck::new(self, &self.access_vector_cache, local_cache)
201    }
202
203    /// Returns the security ID mapped to `security_context`, creating it if it does not exist.
204    ///
205    /// All objects with the same security context will have the same SID associated.
206    pub fn security_context_to_sid(
207        &self,
208        security_context: NullessByteStr<'_>,
209    ) -> Result<SecurityId, anyhow::Error> {
210        self.backend.compute_sid(|active_policy| {
211            active_policy
212                .parsed
213                .parse_security_context(security_context)
214                .map_err(anyhow::Error::from)
215        })
216    }
217
218    /// Returns the Security Context string for the requested `sid`.
219    /// This is used only where Contexts need to be stringified to expose to userspace, as
220    /// is the case for e.g. the `/proc/*/attr/` filesystem and `security.selinux` extended
221    /// attribute values.
222    pub fn sid_to_security_context(&self, sid: SecurityId) -> Option<Vec<u8>> {
223        let locked_state = self.backend.state.read();
224        let active_policy = locked_state.active_policy.as_ref()?;
225        let context = active_policy.sid_table.try_sid_to_security_context(sid)?;
226        Some(active_policy.parsed.serialize_security_context(context))
227    }
228
229    /// Returns the Security Context for the requested `sid` with a terminating NUL.
230    pub fn sid_to_security_context_with_nul(&self, sid: SecurityId) -> Option<Vec<u8>> {
231        self.sid_to_security_context(sid).map(|mut context| {
232            context.push(0u8);
233            context
234        })
235    }
236
237    /// Applies the supplied policy to the security server.
238    pub fn load_policy(&self, binary_policy: Vec<u8>) -> Result<(), anyhow::Error> {
239        // Parse the supplied policy, and reject the load operation if it is
240        // malformed or invalid.
241        let unvalidated_policy = parse_policy_by_value(binary_policy)?;
242        let parsed = Arc::new(unvalidated_policy.validate()?);
243        let binary = parsed.binary().clone();
244
245        let exceptions = self.exceptions.iter().map(String::as_str).collect::<Vec<&str>>();
246        let exceptions = ExceptionsConfig::new(&parsed, &exceptions)?;
247
248        // Replace any existing policy and push update to `state.status_publisher`.
249        self.with_mut_state_and_update_status(|state| {
250            let sid_table = if let Some(previous_active_policy) = &state.active_policy {
251                SidTable::new_from_previous(parsed.clone(), &previous_active_policy.sid_table)
252            } else {
253                SidTable::new(parsed.clone())
254            };
255
256            // TODO(b/324265752): Determine whether SELinux booleans need to be retained across
257            // policy (re)loads.
258            state.booleans.reset(
259                parsed
260                    .conditional_booleans()
261                    .iter()
262                    // TODO(b/324392507): Relax the UTF8 requirement on policy strings.
263                    .map(|(name, value)| (String::from_utf8((*name).to_vec()).unwrap(), *value))
264                    .collect(),
265            );
266
267            state.active_policy = Some(ActivePolicy { parsed, binary, sid_table, exceptions });
268            self.backend.policy_change_count.fetch_add(1, Ordering::Relaxed);
269        });
270
271        Ok(())
272    }
273
274    /// Returns the active policy in binary form, or `None` if no policy has yet been loaded.
275    pub fn get_binary_policy(&self) -> Option<PolicyData> {
276        self.backend.state.read().active_policy.as_ref().map(|p| p.binary.clone())
277    }
278
279    /// Set to enforcing mode if `enforce` is true, permissive mode otherwise.
280    pub fn set_enforcing(&self, enforcing: bool) {
281        self.with_mut_state_and_update_status(|_| {
282            self.backend.is_enforcing.store(enforcing, Ordering::Release);
283        });
284    }
285
286    pub fn is_enforcing(&self) -> bool {
287        self.backend.is_enforcing.load(Ordering::Acquire)
288    }
289
290    /// Returns true if the policy requires unknown class / permissions to be
291    /// denied. Defaults to true until a policy is loaded.
292    pub fn deny_unknown(&self) -> bool {
293        self.backend.state.read().deny_unknown()
294    }
295
296    /// Returns true if the policy requires unknown class / permissions to be
297    /// rejected. Defaults to false until a policy is loaded.
298    pub fn reject_unknown(&self) -> bool {
299        self.backend.state.read().reject_unknown()
300    }
301
302    /// Returns the list of names of boolean conditionals defined by the
303    /// loaded policy.
304    pub fn conditional_booleans(&self) -> Vec<String> {
305        self.backend.state.read().booleans.names()
306    }
307
308    /// Returns the active and pending values of a policy boolean, if it exists.
309    pub fn get_boolean(&self, name: &str) -> Result<(bool, bool), ()> {
310        self.backend.state.read().booleans.get(name)
311    }
312
313    /// Sets the pending value of a boolean, if it is defined in the policy.
314    pub fn set_pending_boolean(&self, name: &str, value: bool) -> Result<(), ()> {
315        self.backend.state.write().booleans.set_pending(name, value)
316    }
317
318    /// Commits all pending changes to conditional booleans.
319    pub fn commit_pending_booleans(&self) {
320        // TODO(b/324264149): Commit values into the stored policy itself.
321        self.with_mut_state_and_update_status(|state| {
322            state.booleans.commit_pending();
323            self.backend.policy_change_count.fetch_add(1, Ordering::Relaxed);
324        });
325    }
326
327    /// Returns whether a standard policy capability is enabled in the loaded policy.
328    pub fn is_policycap_enabled(&self, policy_cap: PolicyCap) -> bool {
329        let locked_state = self.backend.state.read();
330        let Some(policy) = &locked_state.active_policy else {
331            return false;
332        };
333        policy.parsed.has_policycap(policy_cap)
334    }
335
336    /// Returns a snapshot of the AVC usage statistics.
337    pub fn avc_cache_stats(&self) -> CacheStats {
338        self.access_vector_cache.cache_stats()
339    }
340
341    /// Returns the current policy change count.
342    pub fn policy_change_count(&self) -> u32 {
343        self.backend.policy_change_count.load(Ordering::Relaxed)
344    }
345
346    /// Returns the list of all class names.
347    pub fn class_names(&self) -> Result<Vec<Vec<u8>>, ()> {
348        let locked_state = self.backend.state.read();
349        let names = locked_state
350            .expect_active_policy()
351            .parsed
352            .classes()
353            .iter()
354            .map(|class| class.class_name.to_vec())
355            .collect();
356        Ok(names)
357    }
358
359    /// Returns the class identifier of a class, if it exists.
360    pub fn class_id_by_name(&self, name: &str) -> Result<ClassId, ()> {
361        let locked_state = self.backend.state.read();
362        Ok(locked_state
363            .expect_active_policy()
364            .parsed
365            .classes()
366            .iter()
367            .find(|class| *(class.class_name) == *(name.as_bytes()))
368            .ok_or(())?
369            .class_id)
370    }
371
372    /// Returns the set of permissions associated with a class. Each permission
373    /// is represented as a tuple of the permission ID (in the scope of its
374    /// associated class) and the permission name.
375    pub fn class_permissions_by_name(
376        &self,
377        name: &str,
378    ) -> Result<Vec<(ClassPermissionId, Vec<u8>)>, ()> {
379        let locked_state = self.backend.state.read();
380        locked_state.expect_active_policy().parsed.find_class_permissions_by_name(name)
381    }
382
383    /// Determines the appropriate [`FileSystemLabel`] for a mounted filesystem given this security
384    /// server's loaded policy, the name of the filesystem type ("ext4" or "tmpfs", for example),
385    /// and the security-relevant mount options passed for the mount operation.
386    pub fn resolve_fs_label(
387        &self,
388        fs_type: NullessByteStr<'_>,
389        mount_options: &FileSystemMountOptions,
390    ) -> Result<FileSystemLabel, anyhow::Error> {
391        let mut locked_state = self.backend.state.write();
392        let active_policy = locked_state.expect_active_policy_mut();
393
394        let mount_sids = FileSystemMountSids {
395            context: sid_from_mount_option(active_policy, &mount_options.context)?,
396            fs_context: sid_from_mount_option(active_policy, &mount_options.fs_context)?,
397            def_context: sid_from_mount_option(active_policy, &mount_options.def_context)?,
398            root_context: sid_from_mount_option(active_policy, &mount_options.root_context)?,
399        };
400        let label = if let Some(mountpoint_sid) = mount_sids.context {
401            // `mount_options` has `context` set, so the file-system and the nodes it contains are
402            // labeled with that value, which is not modifiable. The `fs_context` option, if set,
403            // overrides the file-system label.
404            FileSystemLabel {
405                sid: mount_sids.fs_context.unwrap_or(mountpoint_sid),
406                scheme: FileSystemLabelingScheme::Mountpoint { sid: mountpoint_sid },
407                mount_sids,
408            }
409        } else if let Some(FsUseLabelAndType { context, use_type }) =
410            active_policy.parsed.fs_use_label_and_type(fs_type)
411        {
412            // There is an `fs_use` statement for this file-system type in the policy.
413            let fs_sid_from_policy =
414                active_policy.sid_table.security_context_to_sid(&context).unwrap();
415            let fs_sid = mount_sids.fs_context.unwrap_or(fs_sid_from_policy);
416            FileSystemLabel {
417                sid: fs_sid,
418                scheme: FileSystemLabelingScheme::FsUse {
419                    fs_use_type: use_type,
420                    default_sid: mount_sids.def_context.unwrap_or_else(|| InitialSid::File.into()),
421                },
422                mount_sids,
423            }
424        } else if let Some(context) =
425            active_policy.parsed.genfscon_label_for_fs_and_path(fs_type, ROOT_PATH.into(), None)
426        {
427            // There is a `genfscon` statement for this file-system type in the policy.
428            let genfscon_sid = active_policy.sid_table.security_context_to_sid(&context).unwrap();
429            let fs_sid = mount_sids.fs_context.unwrap_or(genfscon_sid);
430
431            // For relabeling to make sense with `genfscon` labeling they must ensure to persist the
432            // `FsNode` security state. That is implicitly the case for filesystems which persist all
433            // `FsNode`s in-memory (independent of the `DirEntry` cache), e.g. those whose contents are
434            // managed as a `SimpleDirectory` structure.
435            //
436            // TODO: https://fxbug.dev/362898792 - Replace this with a more graceful mechanism for
437            // deciding whether `genfscon` supports relabeling (as indicated by the "seclabel" tag
438            // reported by `mount`).
439            // Also consider storing the "genfs_seclabel_symlinks" setting in the resolved label.
440            let fs_type = fs_type.as_bytes();
441            let mut supports_seclabel = matches!(fs_type, b"sysfs" | b"tracefs" | b"pstore");
442            supports_seclabel |= matches!(fs_type, b"cgroup" | b"cgroup2")
443                && active_policy.parsed.has_policycap(PolicyCap::CgroupSeclabel);
444            supports_seclabel |= fs_type == b"functionfs"
445                && active_policy.parsed.has_policycap(PolicyCap::FunctionfsSeclabel);
446
447            FileSystemLabel {
448                sid: fs_sid,
449                scheme: FileSystemLabelingScheme::GenFsCon { supports_seclabel },
450                mount_sids,
451            }
452        } else {
453            // The name of the filesystem type was not recognized.
454            FileSystemLabel {
455                sid: mount_sids.fs_context.unwrap_or_else(|| InitialSid::Unlabeled.into()),
456                scheme: FileSystemLabelingScheme::FsUse {
457                    fs_use_type: FsUseType::Xattr,
458                    default_sid: mount_sids.def_context.unwrap_or_else(|| InitialSid::File.into()),
459                },
460                mount_sids,
461            }
462        };
463        Ok(label)
464    }
465
466    /// Returns the [`SecurityId`] with which to label an [`FsNode`] in a filesystem of `fs_type`,
467    /// at the specified filesystem-relative `node_path`.  Callers are responsible for ensuring that
468    /// this API is never called prior to a policy first being loaded, or for a filesystem that is
469    /// not configured to be `genfscon`-labeled.
470    pub fn genfscon_label_for_fs_and_path(
471        &self,
472        fs_type: NullessByteStr<'_>,
473        node_path: NullessByteStr<'_>,
474        class_id: Option<KernelClass>,
475    ) -> Result<SecurityId, anyhow::Error> {
476        self.backend.compute_sid(|active_policy| {
477            active_policy
478                .parsed
479                .genfscon_label_for_fs_and_path(fs_type, node_path.into(), class_id)
480                .ok_or_else(|| {
481                    anyhow::anyhow!("Genfscon label requested for non-genfscon labeled filesystem")
482                })
483        })
484    }
485
486    /// Returns true if the `bounded_sid` is bounded by the `parent_sid`.
487    /// Bounds relationships are mostly enforced by policy tooling, so this only requires validating
488    /// that the policy entry for the `TypeId` of `bounded_sid` has the `TypeId` of `parent_sid`
489    /// specified in its `bounds`.
490    pub fn is_bounded_by(&self, bounded_sid: SecurityId, parent_sid: SecurityId) -> bool {
491        let locked_state = self.backend.state.read();
492        let active_policy = locked_state.expect_active_policy();
493        let bounded_type = active_policy.sid_table.sid_to_security_context(bounded_sid).type_();
494        let parent_type = active_policy.sid_table.sid_to_security_context(parent_sid).type_();
495        active_policy.parsed.is_bounded_by(bounded_type, parent_type)
496    }
497
498    /// Assign a [`SeLinuxStatusPublisher`] to be used for pushing updates to the security server's
499    /// policy status. This should be invoked exactly once when `selinuxfs` is initialized.
500    ///
501    /// # Panics
502    ///
503    /// This will panic on debug builds if it is invoked multiple times.
504    pub fn set_status_publisher(&self, status_holder: Box<dyn SeLinuxStatusPublisher>) {
505        self.with_mut_state_and_update_status(|state| {
506            assert!(state.status_publisher.is_none());
507            state.status_publisher = Some(status_holder);
508        });
509    }
510
511    /// Locks the security server state for modification and calls the supplied function to update
512    /// it.  Once the update is complete, the configured `SeLinuxStatusPublisher` (if any) is called
513    /// to update the userspace-facing "status" file to reflect the new state.
514    fn with_mut_state_and_update_status(&self, f: impl FnOnce(&mut SecurityServerState)) {
515        let mut locked_state = self.backend.state.write();
516        f(locked_state.deref_mut());
517        let new_value = SeLinuxStatus {
518            is_enforcing: self.is_enforcing(),
519            change_count: self.backend.policy_change_count.load(Ordering::Relaxed),
520            deny_unknown: locked_state.deny_unknown(),
521        };
522        if let Some(status_publisher) = &mut locked_state.status_publisher {
523            status_publisher.set_status(new_value);
524        }
525
526        // TODO: https://fxbug.dev/367585803 - reset the cache after running `f` and before updating
527        // the userspace-facing "status", once that is possible.
528        std::mem::drop(locked_state);
529        self.access_vector_cache.reset();
530    }
531
532    /// Returns the security identifier (SID) with which to label a new object of `target_class`,
533    /// based on the specified source & target security SIDs.
534    /// For file-like classes the `compute_new_fs_node_sid*()` APIs should be used instead.
535    // TODO: Move this API to sit alongside the other `compute_*()` APIs.
536    // TODO: https://fxbug.dev/335397745 - APIs should not mix SecurityId and (raw) ClassId.
537    pub fn compute_create_sid_raw(
538        &self,
539        source_sid: SecurityId,
540        target_sid: SecurityId,
541        target_class: ClassId,
542    ) -> Result<SecurityId, anyhow::Error> {
543        self.backend.compute_create_sid_raw(source_sid, target_sid, target_class.into())
544    }
545
546    /// Returns the raw `AccessDecision` for a specified source, target and class.
547    // TODO: APIs should not mix SecurityId and (raw) ClassId.
548    pub fn compute_access_decision_raw(
549        &self,
550        source_sid: SecurityId,
551        target_sid: SecurityId,
552        target_class: ClassId,
553    ) -> AccessDecision {
554        self.backend.compute_access_decision_raw(source_sid, target_sid, target_class.into())
555    }
556}
557
558impl SecurityServerBackend {
559    fn compute_create_sid_raw(
560        &self,
561        source_sid: SecurityId,
562        target_sid: SecurityId,
563        target_class: ObjectClass,
564    ) -> Result<SecurityId, anyhow::Error> {
565        self.compute_sid(|active_policy| {
566            let source_context = active_policy.sid_table.sid_to_security_context(source_sid);
567            let target_context = active_policy.sid_table.sid_to_security_context(target_sid);
568
569            Ok(active_policy.parsed.compute_create_context(
570                source_context,
571                target_context,
572                target_class,
573            ))
574        })
575        .context("computing new security context from policy")
576    }
577
578    /// Helper for call-sites that need to compute a `SecurityContext` and assign a SID to it.
579    fn compute_sid(
580        &self,
581        compute_context: impl Fn(&ActivePolicy) -> Result<SecurityContext, anyhow::Error>,
582    ) -> Result<SecurityId, anyhow::Error> {
583        // Initially assume that the computed context will most likely already have a SID assigned,
584        // so that the operation can be completed without any modification of the SID table.
585        let readable_state = self.state.read();
586        let policy_change_count = self.policy_change_count.load(Ordering::Relaxed);
587        let policy_state = readable_state
588            .active_policy
589            .as_ref()
590            .ok_or_else(|| anyhow::anyhow!("no policy loaded"))?;
591        let context = compute_context(policy_state)?;
592        if let Some(sid) = policy_state.sid_table.security_context_to_existing_sid(&context) {
593            return Ok(sid);
594        }
595        std::mem::drop(readable_state);
596
597        // Since the computed context was not found in the table, re-try the operation with the
598        // policy state write-locked to allow for the SID table to be updated. In the rare case of
599        // a new policy having been loaded in-between the read- and write-locked stages, the
600        // `context` is re-computed using the new policy state.
601        let mut writable_state = self.state.write();
602        let needs_recompute =
603            policy_change_count != self.policy_change_count.load(Ordering::Relaxed);
604        let policy_state = writable_state.active_policy.as_mut().unwrap();
605        let context = if needs_recompute { compute_context(policy_state)? } else { context };
606        policy_state.sid_table.security_context_to_sid(&context).map_err(anyhow::Error::from)
607    }
608
609    fn compute_access_decision_raw(
610        &self,
611        source_sid: SecurityId,
612        target_sid: SecurityId,
613        target_class: ObjectClass,
614    ) -> AccessDecision {
615        let locked_state = self.state.read();
616
617        locked_state.compute_access_decision_raw(source_sid, target_sid, target_class)
618    }
619}
620
621impl Query for SecurityServerBackend {
622    fn compute_access_decision(
623        &self,
624        source_sid: SecurityId,
625        target_sid: SecurityId,
626        target_class: KernelClass,
627    ) -> KernelAccessDecision {
628        let locked_state = self.state.read();
629        let decision =
630            locked_state.compute_access_decision_raw(source_sid, target_sid, target_class.into());
631        locked_state.access_decision_to_kernel_access_decision(target_class, decision)
632    }
633
634    fn compute_create_sid(
635        &self,
636        source_sid: SecurityId,
637        target_sid: SecurityId,
638        target_class: KernelClass,
639    ) -> Result<SecurityId, anyhow::Error> {
640        self.compute_create_sid_raw(source_sid, target_sid, target_class.into())
641    }
642
643    fn compute_new_fs_node_sid_with_name(
644        &self,
645        source_sid: SecurityId,
646        target_sid: SecurityId,
647        fs_node_class: FsNodeClass,
648        fs_node_name: NullessByteStr<'_>,
649    ) -> Option<SecurityId> {
650        let mut locked_state = self.state.write();
651
652        // This interface will not be reached without a policy having been loaded.
653        let active_policy = locked_state.active_policy.as_mut().expect("Policy loaded");
654
655        let source_context = active_policy.sid_table.sid_to_security_context(source_sid);
656        let target_context = active_policy.sid_table.sid_to_security_context(target_sid);
657
658        let new_file_context = active_policy.parsed.compute_create_context_with_name(
659            source_context,
660            target_context,
661            fs_node_class,
662            fs_node_name,
663        )?;
664
665        active_policy.sid_table.security_context_to_sid(&new_file_context).ok()
666    }
667
668    fn compute_xperms_access_decision(
669        &self,
670        xperms_kind: XpermsKind,
671        source_sid: SecurityId,
672        target_sid: SecurityId,
673        permission: KernelPermission,
674        xperms_prefix: u8,
675    ) -> KernelXpermsAccessDecision {
676        let locked_state = self.state.read();
677
678        let active_policy = match &locked_state.active_policy {
679            Some(active_policy) => active_policy,
680            // All permissions are allowed when no policy is loaded, regardless of enforcing state.
681            None => {
682                return KernelXpermsAccessDecision {
683                    allow: XpermsBitmap::ALL,
684                    audit: XpermsBitmap::NONE,
685                    permissive: false,
686                    has_todo: false,
687                };
688            }
689        };
690
691        // Look up the decision for the base permission.
692        // TODO(b/493591579): avoid multiple lookups in the SID table
693        let base_decision_raw = locked_state.compute_access_decision_raw(
694            source_sid,
695            target_sid,
696            permission.class().into(),
697        );
698        let base_decision = locked_state
699            .access_decision_to_kernel_access_decision(permission.class(), base_decision_raw);
700        let permission_access_vector = permission.as_access_vector();
701        let base_permit =
702            base_decision.allow & permission_access_vector == permission_access_vector;
703        let base_audit = base_decision.audit & permission_access_vector == permission_access_vector;
704
705        // Look up the extended permission decision.
706        let source_context = active_policy.sid_table.sid_to_security_context(source_sid);
707        let target_context = active_policy.sid_table.sid_to_security_context(target_sid);
708        let xperms_decision = active_policy.parsed.compute_xperms_access_decision(
709            xperms_kind,
710            &source_context,
711            &target_context,
712            permission.class(),
713            xperms_prefix,
714        );
715
716        // Combine the base and extended decisions.
717        let allow = if !base_permit { XpermsBitmap::NONE } else { xperms_decision.allow };
718        let audit = if base_audit {
719            XpermsBitmap::ALL
720        } else {
721            (xperms_decision.allow & xperms_decision.auditallow)
722                | (!xperms_decision.allow & xperms_decision.auditdeny)
723        };
724        let permissive = (base_decision.flags & SELINUX_AVD_FLAGS_PERMISSIVE) != 0;
725        let has_todo = base_decision.todo_bug.is_some();
726        KernelXpermsAccessDecision { allow, audit, permissive, has_todo }
727    }
728}
729
730impl AccessVectorComputer for SecurityServerBackend {
731    fn access_decision_to_kernel_access_decision(
732        &self,
733        class: KernelClass,
734        av: AccessDecision,
735    ) -> KernelAccessDecision {
736        self.state.read().access_decision_to_kernel_access_decision(class, av)
737    }
738}
739
740impl AccessVectorComputer for SecurityServerState {
741    fn access_decision_to_kernel_access_decision(
742        &self,
743        class: KernelClass,
744        av: AccessDecision,
745    ) -> KernelAccessDecision {
746        match &self.active_policy {
747            Some(policy) => policy.parsed.access_decision_to_kernel_access_decision(class, av),
748            None => KernelAccessDecision {
749                allow: AccessVector::ALL,
750                audit: AccessVector::NONE,
751                flags: 0,
752                todo_bug: None,
753            },
754        }
755    }
756}
757
758/// Computes a [`SecurityId`] given a non-[`None`] value for one of the four
759/// "context" mount options (https://man7.org/linux/man-pages/man8/mount.8.html).
760fn sid_from_mount_option(
761    active_policy: &mut ActivePolicy,
762    mount_option: &Option<Vec<u8>>,
763) -> Result<Option<SecurityId>, anyhow::Error> {
764    let Some(label) = mount_option else {
765        return Ok(None);
766    };
767    let context = active_policy.parsed.parse_security_context(label.into())?;
768    let sid = active_policy.sid_table.security_context_to_sid(&context)?;
769    Ok(Some(sid))
770}
771
772#[cfg(test)]
773mod tests {
774    use super::*;
775    use crate::permission_check::PermissionCheckResult;
776    use crate::{
777        CommonFsNodePermission, DirPermission, FileClass, FilePermission, ForClass, KernelClass,
778        ProcessPermission,
779    };
780    use std::num::NonZeroU32;
781
782    const TESTSUITE_BINARY_POLICY: &[u8] = include_bytes!("../testdata/policies/selinux_testsuite");
783    const TESTS_BINARY_POLICY: &[u8] =
784        include_bytes!("../testdata/micro_policies/security_server_tests_policy");
785    const MINIMAL_BINARY_POLICY: &[u8] =
786        include_bytes!("../testdata/composite_policies/compiled/minimal_policy");
787
788    fn security_server_with_tests_policy() -> Arc<SecurityServer> {
789        let policy_bytes = TESTS_BINARY_POLICY.to_vec();
790        let security_server = SecurityServer::new_default();
791        assert_eq!(
792            Ok(()),
793            security_server.load_policy(policy_bytes).map_err(|e| format!("{:?}", e))
794        );
795        security_server
796    }
797
798    #[test]
799    fn compute_access_vector_allows_all() {
800        let security_server = SecurityServer::new_default();
801        let sid1 = InitialSid::Kernel.into();
802        let sid2 = InitialSid::Unlabeled.into();
803        assert_eq!(
804            security_server
805                .backend
806                .compute_access_decision(sid1, sid2, KernelClass::Process.into())
807                .allow,
808            AccessVector::ALL
809        );
810    }
811
812    #[test]
813    fn loaded_policy_can_be_retrieved() {
814        let security_server = security_server_with_tests_policy();
815        assert_eq!(TESTS_BINARY_POLICY, security_server.get_binary_policy().unwrap().as_slice());
816    }
817
818    #[test]
819    fn loaded_policy_is_validated() {
820        let not_really_a_policy = "not a real policy".as_bytes().to_vec();
821        let security_server = SecurityServer::new_default();
822        assert!(security_server.load_policy(not_really_a_policy.clone()).is_err());
823    }
824
825    #[test]
826    fn enforcing_mode_is_reported() {
827        let security_server = SecurityServer::new_default();
828        assert!(!security_server.is_enforcing());
829
830        security_server.set_enforcing(true);
831        assert!(security_server.is_enforcing());
832    }
833
834    #[test]
835    fn without_policy_conditional_booleans_are_empty() {
836        let security_server = SecurityServer::new_default();
837        assert!(security_server.conditional_booleans().is_empty());
838    }
839
840    #[test]
841    fn conditional_booleans_can_be_queried() {
842        let policy_bytes = TESTSUITE_BINARY_POLICY.to_vec();
843        let security_server = SecurityServer::new_default();
844        assert_eq!(
845            Ok(()),
846            security_server.load_policy(policy_bytes).map_err(|e| format!("{:?}", e))
847        );
848
849        let booleans = security_server.conditional_booleans();
850        assert!(!booleans.is_empty());
851        let boolean = booleans[0].as_str();
852
853        assert!(security_server.get_boolean("this_is_not_a_valid_boolean_name").is_err());
854        assert!(security_server.get_boolean(boolean).is_ok());
855    }
856
857    #[test]
858    fn conditional_booleans_can_be_changed() {
859        let policy_bytes = TESTSUITE_BINARY_POLICY.to_vec();
860        let security_server = SecurityServer::new_default();
861        assert_eq!(
862            Ok(()),
863            security_server.load_policy(policy_bytes).map_err(|e| format!("{:?}", e))
864        );
865
866        let booleans = security_server.conditional_booleans();
867        assert!(!booleans.is_empty());
868        let boolean = booleans[0].as_str();
869
870        let (active, pending) = security_server.get_boolean(boolean).unwrap();
871        assert_eq!(active, pending, "Initially active and pending values should match");
872
873        security_server.set_pending_boolean(boolean, !active).unwrap();
874        let (active, pending) = security_server.get_boolean(boolean).unwrap();
875        assert!(active != pending, "Before commit pending should differ from active");
876
877        security_server.commit_pending_booleans();
878        let (final_active, final_pending) = security_server.get_boolean(boolean).unwrap();
879        assert_eq!(final_active, pending, "Pending value should be active after commit");
880        assert_eq!(final_active, final_pending, "Active and pending are the same after commit");
881    }
882
883    #[test]
884    fn parse_security_context_no_policy() {
885        let security_server = SecurityServer::new_default();
886        let error = security_server
887            .security_context_to_sid(b"unconfined_u:unconfined_r:unconfined_t:s0".into())
888            .expect_err("expected error");
889        let error_string = format!("{:?}", error);
890        assert!(error_string.contains("no policy"));
891    }
892
893    #[test]
894    fn compute_new_fs_node_sid_no_defaults() {
895        let security_server = SecurityServer::new_default();
896        let policy_bytes =
897            include_bytes!("../testdata/micro_policies/file_no_defaults_policy").to_vec();
898        security_server.load_policy(policy_bytes).expect("binary policy loads");
899
900        let source_sid = security_server
901            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s1".into())
902            .expect("creating SID from security context should succeed");
903        let target_sid = security_server
904            .security_context_to_sid(b"file_u:object_r:file_t:s0".into())
905            .expect("creating SID from security context should succeed");
906
907        let computed_sid = security_server
908            .as_permission_check(&Default::default())
909            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
910            .expect("new sid computed");
911        let computed_context = security_server
912            .sid_to_security_context(computed_sid)
913            .expect("computed sid associated with context");
914
915        // User and low security level should be copied from the source,
916        // and the role and type from the target.
917        assert_eq!(computed_context, b"user_u:object_r:file_t:s0");
918    }
919
920    #[test]
921    fn compute_new_fs_node_sid_source_defaults() {
922        let security_server = SecurityServer::new_default();
923        let policy_bytes =
924            include_bytes!("../testdata/micro_policies/file_source_defaults_policy").to_vec();
925        security_server.load_policy(policy_bytes).expect("binary policy loads");
926
927        let source_sid = security_server
928            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s2:c0".into())
929            .expect("creating SID from security context should succeed");
930        let target_sid = security_server
931            .security_context_to_sid(b"file_u:object_r:file_t:s1-s3:c0".into())
932            .expect("creating SID from security context should succeed");
933
934        let computed_sid = security_server
935            .as_permission_check(&Default::default())
936            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
937            .expect("new sid computed");
938        let computed_context = security_server
939            .sid_to_security_context(computed_sid)
940            .expect("computed sid associated with context");
941
942        // All fields should be copied from the source, but only the "low" part of the security
943        // range.
944        assert_eq!(computed_context, b"user_u:unconfined_r:unconfined_t:s0");
945    }
946
947    #[test]
948    fn compute_new_fs_node_sid_target_defaults() {
949        let security_server = SecurityServer::new_default();
950        let policy_bytes =
951            include_bytes!("../testdata/micro_policies/file_target_defaults_policy").to_vec();
952        security_server.load_policy(policy_bytes).expect("binary policy loads");
953
954        let source_sid = security_server
955            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s2:c0".into())
956            .expect("creating SID from security context should succeed");
957        let target_sid = security_server
958            .security_context_to_sid(b"file_u:object_r:file_t:s1-s3:c0".into())
959            .expect("creating SID from security context should succeed");
960
961        let computed_sid = security_server
962            .as_permission_check(&Default::default())
963            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
964            .expect("new sid computed");
965        let computed_context = security_server
966            .sid_to_security_context(computed_sid)
967            .expect("computed sid associated with context");
968
969        // User, role and type copied from target, with source's low security level.
970        assert_eq!(computed_context, b"file_u:object_r:file_t:s0");
971    }
972
973    #[test]
974    fn compute_new_fs_node_sid_range_source_low_default() {
975        let security_server = SecurityServer::new_default();
976        let policy_bytes =
977            include_bytes!("../testdata/micro_policies/file_range_source_low_policy").to_vec();
978        security_server.load_policy(policy_bytes).expect("binary policy loads");
979
980        let source_sid = security_server
981            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s1:c0".into())
982            .expect("creating SID from security context should succeed");
983        let target_sid = security_server
984            .security_context_to_sid(b"file_u:object_r:file_t:s1".into())
985            .expect("creating SID from security context should succeed");
986
987        let computed_sid = security_server
988            .as_permission_check(&Default::default())
989            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
990            .expect("new sid computed");
991        let computed_context = security_server
992            .sid_to_security_context(computed_sid)
993            .expect("computed sid associated with context");
994
995        // User and low security level copied from source, role and type as default.
996        assert_eq!(computed_context, b"user_u:object_r:file_t:s0");
997    }
998
999    #[test]
1000    fn compute_new_fs_node_sid_range_source_low_high_default() {
1001        let security_server = SecurityServer::new_default();
1002        let policy_bytes =
1003            include_bytes!("../testdata/micro_policies/file_range_source_low_high_policy").to_vec();
1004        security_server.load_policy(policy_bytes).expect("binary policy loads");
1005
1006        let source_sid = security_server
1007            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s1:c0".into())
1008            .expect("creating SID from security context should succeed");
1009        let target_sid = security_server
1010            .security_context_to_sid(b"file_u:object_r:file_t:s1".into())
1011            .expect("creating SID from security context should succeed");
1012
1013        let computed_sid = security_server
1014            .as_permission_check(&Default::default())
1015            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
1016            .expect("new sid computed");
1017        let computed_context = security_server
1018            .sid_to_security_context(computed_sid)
1019            .expect("computed sid associated with context");
1020
1021        // User and full security range copied from source, role and type as default.
1022        assert_eq!(computed_context, b"user_u:object_r:file_t:s0-s1:c0");
1023    }
1024
1025    #[test]
1026    fn compute_new_fs_node_sid_range_source_high_default() {
1027        let security_server = SecurityServer::new_default();
1028        let policy_bytes =
1029            include_bytes!("../testdata/micro_policies/file_range_source_high_policy").to_vec();
1030        security_server.load_policy(policy_bytes).expect("binary policy loads");
1031
1032        let source_sid = security_server
1033            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s1:c0".into())
1034            .expect("creating SID from security context should succeed");
1035        let target_sid = security_server
1036            .security_context_to_sid(b"file_u:object_r:file_t:s0".into())
1037            .expect("creating SID from security context should succeed");
1038
1039        let computed_sid = security_server
1040            .as_permission_check(&Default::default())
1041            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
1042            .expect("new sid computed");
1043        let computed_context = security_server
1044            .sid_to_security_context(computed_sid)
1045            .expect("computed sid associated with context");
1046
1047        // User and high security level copied from source, role and type as default.
1048        assert_eq!(computed_context, b"user_u:object_r:file_t:s1:c0");
1049    }
1050
1051    #[test]
1052    fn compute_new_fs_node_sid_range_target_low_default() {
1053        let security_server = SecurityServer::new_default();
1054        let policy_bytes =
1055            include_bytes!("../testdata/micro_policies/file_range_target_low_policy").to_vec();
1056        security_server.load_policy(policy_bytes).expect("binary policy loads");
1057
1058        let source_sid = security_server
1059            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s1".into())
1060            .expect("creating SID from security context should succeed");
1061        let target_sid = security_server
1062            .security_context_to_sid(b"file_u:object_r:file_t:s0-s1:c0".into())
1063            .expect("creating SID from security context should succeed");
1064
1065        let computed_sid = security_server
1066            .as_permission_check(&Default::default())
1067            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
1068            .expect("new sid computed");
1069        let computed_context = security_server
1070            .sid_to_security_context(computed_sid)
1071            .expect("computed sid associated with context");
1072
1073        // User copied from source, low security level from target, role and type as default.
1074        assert_eq!(computed_context, b"user_u:object_r:file_t:s0");
1075    }
1076
1077    #[test]
1078    fn compute_new_fs_node_sid_range_target_low_high_default() {
1079        let security_server = SecurityServer::new_default();
1080        let policy_bytes =
1081            include_bytes!("../testdata/micro_policies/file_range_target_low_high_policy").to_vec();
1082        security_server.load_policy(policy_bytes).expect("binary policy loads");
1083
1084        let source_sid = security_server
1085            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s1".into())
1086            .expect("creating SID from security context should succeed");
1087        let target_sid = security_server
1088            .security_context_to_sid(b"file_u:object_r:file_t:s0-s1:c0".into())
1089            .expect("creating SID from security context should succeed");
1090
1091        let computed_sid = security_server
1092            .as_permission_check(&Default::default())
1093            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
1094            .expect("new sid computed");
1095        let computed_context = security_server
1096            .sid_to_security_context(computed_sid)
1097            .expect("computed sid associated with context");
1098
1099        // User copied from source, full security range from target, role and type as default.
1100        assert_eq!(computed_context, b"user_u:object_r:file_t:s0-s1:c0");
1101    }
1102
1103    #[test]
1104    fn compute_new_fs_node_sid_range_target_high_default() {
1105        let security_server = SecurityServer::new_default();
1106        let policy_bytes =
1107            include_bytes!("../testdata/micro_policies/file_range_target_high_policy").to_vec();
1108        security_server.load_policy(policy_bytes).expect("binary policy loads");
1109
1110        let source_sid = security_server
1111            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0".into())
1112            .expect("creating SID from security context should succeed");
1113        let target_sid = security_server
1114            .security_context_to_sid(b"file_u:object_r:file_t:s0-s1:c0".into())
1115            .expect("creating SID from security context should succeed");
1116
1117        let computed_sid = security_server
1118            .as_permission_check(&Default::default())
1119            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
1120            .expect("new sid computed");
1121        let computed_context = security_server
1122            .sid_to_security_context(computed_sid)
1123            .expect("computed sid associated with context");
1124
1125        // User copied from source, high security level from target, role and type as default.
1126        assert_eq!(computed_context, b"user_u:object_r:file_t:s1:c0");
1127    }
1128
1129    #[test]
1130    fn compute_new_fs_node_sid_with_name() {
1131        let security_server = SecurityServer::new_default();
1132        let policy_bytes =
1133            include_bytes!("../testdata/composite_policies/compiled/type_transition_policy")
1134                .to_vec();
1135        security_server.load_policy(policy_bytes).expect("binary policy loads");
1136
1137        let source_sid = security_server
1138            .security_context_to_sid(b"source_u:source_r:source_t:s0".into())
1139            .expect("creating SID from security context should succeed");
1140        let target_sid = security_server
1141            .security_context_to_sid(b"target_u:object_r:target_t:s0".into())
1142            .expect("creating SID from security context should succeed");
1143
1144        const SPECIAL_FILE_NAME: &[u8] = b"special_file";
1145        let computed_sid = security_server
1146            .as_permission_check(&Default::default())
1147            .compute_new_fs_node_sid(
1148                source_sid,
1149                target_sid,
1150                FileClass::File.into(),
1151                SPECIAL_FILE_NAME.into(),
1152            )
1153            .expect("new sid computed");
1154        let computed_context = security_server
1155            .sid_to_security_context(computed_sid)
1156            .expect("computed sid associated with context");
1157
1158        // New domain should be derived from the filename-specific rule.
1159        assert_eq!(computed_context, b"source_u:object_r:special_transition_t:s0");
1160
1161        let computed_sid = security_server
1162            .as_permission_check(&Default::default())
1163            .compute_new_fs_node_sid(
1164                source_sid,
1165                target_sid,
1166                FileClass::ChrFile.into(),
1167                SPECIAL_FILE_NAME.into(),
1168            )
1169            .expect("new sid computed");
1170        let computed_context = security_server
1171            .sid_to_security_context(computed_sid)
1172            .expect("computed sid associated with context");
1173
1174        // New domain should be copied from the target, because the class does not match either the
1175        // filename-specific nor generic type transition rules.
1176        assert_eq!(computed_context, b"source_u:object_r:target_t:s0");
1177
1178        const OTHER_FILE_NAME: &[u8] = b"other_file";
1179        let computed_sid = security_server
1180            .as_permission_check(&Default::default())
1181            .compute_new_fs_node_sid(
1182                source_sid,
1183                target_sid,
1184                FileClass::File.into(),
1185                OTHER_FILE_NAME.into(),
1186            )
1187            .expect("new sid computed");
1188        let computed_context = security_server
1189            .sid_to_security_context(computed_sid)
1190            .expect("computed sid associated with context");
1191
1192        // New domain should be derived from the non-filename-specific rule, because the filename
1193        // does not match.
1194        assert_eq!(computed_context, b"source_u:object_r:transition_t:s0");
1195    }
1196
1197    #[test]
1198    fn permissions_are_fresh_after_different_policy_load() {
1199        let minimal_bytes = MINIMAL_BINARY_POLICY.to_vec();
1200        let allow_fork_bytes =
1201            include_bytes!("../testdata/composite_policies/compiled/allow_fork_policy").to_vec();
1202        let context = b"source_u:object_r:source_t:s0:c0";
1203
1204        let security_server = SecurityServer::new_default();
1205        security_server.set_enforcing(true);
1206
1207        let local_cache = Default::default();
1208        let permission_check = security_server.as_permission_check(&local_cache);
1209
1210        // Load the minimal policy and get a SID for the context.
1211        assert_eq!(
1212            Ok(()),
1213            security_server.load_policy(minimal_bytes).map_err(|e| format!("{:?}", e))
1214        );
1215        let sid = security_server.security_context_to_sid(context.into()).unwrap();
1216
1217        // The minimal policy does not grant fork allowance.
1218        assert!(!permission_check.has_permission(sid, sid, ProcessPermission::Fork).granted);
1219
1220        // Load a policy that does grant fork allowance.
1221        assert_eq!(
1222            Ok(()),
1223            security_server.load_policy(allow_fork_bytes).map_err(|e| format!("{:?}", e))
1224        );
1225
1226        // Reuse the cache to check invalidation.
1227        let permission_check = security_server.as_permission_check(&local_cache);
1228
1229        // The now-loaded "allow_fork" policy allows the context represented by `sid` to fork.
1230        assert!(permission_check.has_permission(sid, sid, ProcessPermission::Fork).granted);
1231    }
1232
1233    #[test]
1234    fn unknown_sids_are_effectively_unlabeled() {
1235        let with_unlabeled_access_domain_policy_bytes = include_bytes!(
1236            "../testdata/composite_policies/compiled/with_unlabeled_access_domain_policy"
1237        )
1238        .to_vec();
1239        let with_additional_domain_policy_bytes =
1240            include_bytes!("../testdata/composite_policies/compiled/with_additional_domain_policy")
1241                .to_vec();
1242        let allowed_type_context = b"source_u:object_r:allowed_t:s0:c0";
1243        let additional_type_context = b"source_u:object_r:additional_t:s0:c0";
1244
1245        let security_server = SecurityServer::new_default();
1246        security_server.set_enforcing(true);
1247
1248        // Load a policy, get a SID for a context that is valid for that policy, and verify
1249        // that a context that is not valid for that policy is not issued a SID.
1250        assert_eq!(
1251            Ok(()),
1252            security_server
1253                .load_policy(with_unlabeled_access_domain_policy_bytes.clone())
1254                .map_err(|e| format!("{:?}", e))
1255        );
1256        let allowed_type_sid =
1257            security_server.security_context_to_sid(allowed_type_context.into()).unwrap();
1258        assert!(security_server.security_context_to_sid(additional_type_context.into()).is_err());
1259
1260        // Load the policy that makes the second context valid, and verify that it is valid, and
1261        // verify that the first context remains valid (and unchanged).
1262        assert_eq!(
1263            Ok(()),
1264            security_server
1265                .load_policy(with_additional_domain_policy_bytes.clone())
1266                .map_err(|e| format!("{:?}", e))
1267        );
1268        let additional_type_sid =
1269            security_server.security_context_to_sid(additional_type_context.into()).unwrap();
1270        assert_eq!(
1271            allowed_type_sid,
1272            security_server.security_context_to_sid(allowed_type_context.into()).unwrap()
1273        );
1274
1275        let local_cache = Default::default();
1276        let permission_check = security_server.as_permission_check(&local_cache);
1277
1278        // "allowed_t" is allowed the process getsched capability to "unlabeled_t" - but since
1279        // the currently-loaded policy defines "additional_t", the SID for "additional_t" does
1280        // not get treated as effectively unlabeled, and these permission checks are denied.
1281        assert!(
1282            !permission_check
1283                .has_permission(additional_type_sid, allowed_type_sid, ProcessPermission::GetSched)
1284                .granted
1285        );
1286        assert!(
1287            !permission_check
1288                .has_permission(additional_type_sid, allowed_type_sid, ProcessPermission::SetSched)
1289                .granted
1290        );
1291        assert!(
1292            !permission_check
1293                .has_permission(allowed_type_sid, additional_type_sid, ProcessPermission::GetSched)
1294                .granted
1295        );
1296        assert!(
1297            !permission_check
1298                .has_permission(allowed_type_sid, additional_type_sid, ProcessPermission::SetSched)
1299                .granted
1300        );
1301
1302        // We now flip back to the policy that does not recognize "additional_t"...
1303        assert_eq!(
1304            Ok(()),
1305            security_server
1306                .load_policy(with_unlabeled_access_domain_policy_bytes)
1307                .map_err(|e| format!("{:?}", e))
1308        );
1309
1310        // Reuse the cache to check invalidation.
1311        let permission_check = security_server.as_permission_check(&local_cache);
1312
1313        // The now-loaded policy allows "allowed_t" the process getsched capability
1314        // to "unlabeled_t" and since the now-loaded policy does not recognize "additional_t",
1315        // "allowed_t" is now allowed the process getsched capability to "additional_t".
1316        assert!(
1317            permission_check
1318                .has_permission(allowed_type_sid, additional_type_sid, ProcessPermission::GetSched)
1319                .granted
1320        );
1321        assert!(
1322            !permission_check
1323                .has_permission(allowed_type_sid, additional_type_sid, ProcessPermission::SetSched)
1324                .granted
1325        );
1326
1327        // ... and the now-loaded policy also allows "unlabeled_t" the process
1328        // setsched capability to "allowed_t" and since the now-loaded policy does not recognize
1329        // "additional_t", "unlabeled_t" is now allowed the process setsched capability to
1330        // "allowed_t".
1331        assert!(
1332            !permission_check
1333                .has_permission(additional_type_sid, allowed_type_sid, ProcessPermission::GetSched)
1334                .granted
1335        );
1336        assert!(
1337            permission_check
1338                .has_permission(additional_type_sid, allowed_type_sid, ProcessPermission::SetSched)
1339                .granted
1340        );
1341
1342        // We also verify that we do not get a serialization for unrecognized "additional_t"...
1343        assert!(security_server.sid_to_security_context(additional_type_sid).is_none());
1344
1345        // ... but if we flip forward to the policy that recognizes "additional_t", then we see
1346        // the serialization succeed and return the original context string.
1347        assert_eq!(
1348            Ok(()),
1349            security_server
1350                .load_policy(with_additional_domain_policy_bytes)
1351                .map_err(|e| format!("{:?}", e))
1352        );
1353        assert_eq!(
1354            additional_type_context.to_vec(),
1355            security_server.sid_to_security_context(additional_type_sid).unwrap()
1356        );
1357    }
1358
1359    #[test]
1360    fn permission_check_permissive() {
1361        let security_server = security_server_with_tests_policy();
1362        security_server.set_enforcing(false);
1363        assert!(!security_server.is_enforcing());
1364
1365        let sid =
1366            security_server.security_context_to_sid("user0:object_r:type0:s0".into()).unwrap();
1367        let local_cache = Default::default();
1368        let permission_check = security_server.as_permission_check(&local_cache);
1369
1370        // Test policy grants "type0" the process-fork permission to itself.
1371        // Since the permission is granted by policy, the check will not be audit logged.
1372        assert_eq!(
1373            permission_check.has_permission(sid, sid, ProcessPermission::Fork),
1374            PermissionCheckResult {
1375                granted: true,
1376                audit: false,
1377                permissive: false,
1378                todo_bug: None
1379            }
1380        );
1381
1382        // Test policy does not grant "type0" the process-getrlimit permission to itself, but
1383        // the security server is configured to be permissive. Because the permission was not
1384        // granted by the policy, the check will be audit logged.
1385        let result = permission_check.has_permission(sid, sid, ProcessPermission::GetRlimit);
1386        assert_eq!(
1387            result,
1388            PermissionCheckResult { granted: false, audit: true, permissive: true, todo_bug: None }
1389        );
1390        assert!(result.permit());
1391
1392        // Test policy is built with "deny unknown" behaviour, and has no "blk_file" class defined.
1393        // This permission should be treated like a defined permission that is not allowed to the
1394        // source, and both allowed and audited here.
1395        let result = permission_check.has_permission(
1396            sid,
1397            sid,
1398            CommonFsNodePermission::GetAttr.for_class(FileClass::BlkFile),
1399        );
1400        assert_eq!(
1401            result,
1402            PermissionCheckResult { granted: false, audit: true, permissive: true, todo_bug: None }
1403        );
1404        assert!(result.permit());
1405    }
1406
1407    #[test]
1408    fn permission_check_enforcing() {
1409        let security_server = security_server_with_tests_policy();
1410        security_server.set_enforcing(true);
1411        assert!(security_server.is_enforcing());
1412
1413        let sid =
1414            security_server.security_context_to_sid("user0:object_r:type0:s0".into()).unwrap();
1415        let local_cache = Default::default();
1416        let permission_check = security_server.as_permission_check(&local_cache);
1417
1418        // Test policy grants "type0" the process-fork permission to itself.
1419        let result = permission_check.has_permission(sid, sid, ProcessPermission::Fork);
1420        assert_eq!(
1421            result,
1422            PermissionCheckResult {
1423                granted: true,
1424                audit: false,
1425                permissive: false,
1426                todo_bug: None
1427            }
1428        );
1429        assert!(result.permit());
1430
1431        // Test policy does not grant "type0" the process-getrlimit permission to itself.
1432        // Permission denials are audit logged in enforcing mode.
1433        let result = permission_check.has_permission(sid, sid, ProcessPermission::GetRlimit);
1434        assert_eq!(
1435            result,
1436            PermissionCheckResult {
1437                granted: false,
1438                audit: true,
1439                permissive: false,
1440                todo_bug: None
1441            }
1442        );
1443        assert!(!result.permit());
1444
1445        // Test policy is built with "deny unknown" behaviour, and has no "blk_file" class defined.
1446        // This permission should therefore be denied, and the denial audited.
1447        let result = permission_check.has_permission(
1448            sid,
1449            sid,
1450            CommonFsNodePermission::GetAttr.for_class(FileClass::BlkFile),
1451        );
1452        assert_eq!(
1453            result,
1454            PermissionCheckResult {
1455                granted: false,
1456                audit: true,
1457                permissive: false,
1458                todo_bug: None
1459            }
1460        );
1461        assert!(!result.permit());
1462    }
1463
1464    #[test]
1465    fn permissive_domain() {
1466        let security_server = security_server_with_tests_policy();
1467        security_server.set_enforcing(true);
1468        assert!(security_server.is_enforcing());
1469
1470        let permissive_sid = security_server
1471            .security_context_to_sid("user0:object_r:permissive_t:s0".into())
1472            .unwrap();
1473        let non_permissive_sid = security_server
1474            .security_context_to_sid("user0:object_r:non_permissive_t:s0".into())
1475            .unwrap();
1476
1477        let local_cache = Default::default();
1478        let permission_check = security_server.as_permission_check(&local_cache);
1479
1480        // Test policy grants process-getsched permission to both of the test domains.
1481        let result = permission_check.has_permission(
1482            permissive_sid,
1483            permissive_sid,
1484            ProcessPermission::GetSched,
1485        );
1486        assert_eq!(
1487            result,
1488            PermissionCheckResult { granted: true, audit: false, permissive: true, todo_bug: None }
1489        );
1490        assert!(result.permit());
1491        let result = permission_check.has_permission(
1492            non_permissive_sid,
1493            non_permissive_sid,
1494            ProcessPermission::GetSched,
1495        );
1496        assert_eq!(
1497            result,
1498            PermissionCheckResult {
1499                granted: true,
1500                audit: false,
1501                permissive: false,
1502                todo_bug: None
1503            }
1504        );
1505        assert!(result.permit());
1506
1507        // Test policy does not grant process-getsched permission to the test domains on one another.
1508        // The permissive domain will be granted the permission, since it is marked permissive.
1509        let result = permission_check.has_permission(
1510            permissive_sid,
1511            non_permissive_sid,
1512            ProcessPermission::GetSched,
1513        );
1514        assert_eq!(
1515            result,
1516            PermissionCheckResult { granted: false, audit: true, permissive: true, todo_bug: None }
1517        );
1518        assert!(result.permit());
1519        let result = permission_check.has_permission(
1520            non_permissive_sid,
1521            permissive_sid,
1522            ProcessPermission::GetSched,
1523        );
1524        assert_eq!(
1525            result,
1526            PermissionCheckResult {
1527                granted: false,
1528                audit: true,
1529                permissive: false,
1530                todo_bug: None
1531            }
1532        );
1533        assert!(!result.permit());
1534
1535        // Test policy has "deny unknown" behaviour and does not define the "blk_file" class, so
1536        // access to a permission on it will depend on whether the source is permissive.
1537        // The target domain is irrelevant, since the class/permission do not exist, so the non-
1538        // permissive SID is used for both checks.
1539        let result = permission_check.has_permission(
1540            permissive_sid,
1541            non_permissive_sid,
1542            CommonFsNodePermission::GetAttr.for_class(FileClass::BlkFile),
1543        );
1544        assert_eq!(
1545            result,
1546            PermissionCheckResult { granted: false, audit: true, permissive: true, todo_bug: None }
1547        );
1548        assert!(result.permit());
1549        let result = permission_check.has_permission(
1550            non_permissive_sid,
1551            non_permissive_sid,
1552            CommonFsNodePermission::GetAttr.for_class(FileClass::BlkFile),
1553        );
1554        assert_eq!(
1555            result,
1556            PermissionCheckResult {
1557                granted: false,
1558                audit: true,
1559                permissive: false,
1560                todo_bug: None
1561            }
1562        );
1563        assert!(!result.permit());
1564    }
1565
1566    #[test]
1567    fn auditallow_and_dontaudit() {
1568        let security_server = security_server_with_tests_policy();
1569        security_server.set_enforcing(true);
1570        assert!(security_server.is_enforcing());
1571
1572        let audit_sid = security_server
1573            .security_context_to_sid("user0:object_r:test_audit_t:s0".into())
1574            .unwrap();
1575
1576        let local_cache = Default::default();
1577        let permission_check = security_server.as_permission_check(&local_cache);
1578
1579        // Test policy grants the domain self-fork permission, and marks it audit-allow.
1580        let result = permission_check.has_permission(audit_sid, audit_sid, ProcessPermission::Fork);
1581        assert_eq!(
1582            result,
1583            PermissionCheckResult { granted: true, audit: true, permissive: false, todo_bug: None }
1584        );
1585        assert!(result.permit());
1586
1587        // Self-setsched permission is granted, and marked dont-audit, which takes no effect.
1588        let result =
1589            permission_check.has_permission(audit_sid, audit_sid, ProcessPermission::SetSched);
1590        assert_eq!(
1591            result,
1592            PermissionCheckResult {
1593                granted: true,
1594                audit: false,
1595                permissive: false,
1596                todo_bug: None
1597            }
1598        );
1599        assert!(result.permit());
1600
1601        // Self-getsched permission is denied, but marked dont-audit.
1602        let result =
1603            permission_check.has_permission(audit_sid, audit_sid, ProcessPermission::GetSched);
1604        assert_eq!(
1605            result,
1606            PermissionCheckResult {
1607                granted: false,
1608                audit: false,
1609                permissive: false,
1610                todo_bug: None
1611            }
1612        );
1613        assert!(!result.permit());
1614
1615        // Self-getpgid permission is denied, with neither audit-allow nor dont-audit.
1616        let result =
1617            permission_check.has_permission(audit_sid, audit_sid, ProcessPermission::GetPgid);
1618        assert_eq!(
1619            result,
1620            PermissionCheckResult {
1621                granted: false,
1622                audit: true,
1623                permissive: false,
1624                todo_bug: None
1625            }
1626        );
1627        assert!(!result.permit());
1628    }
1629
1630    #[test]
1631    fn access_checks_with_exceptions_config() {
1632        const EXCEPTIONS_CONFIG: &[&str] = &[
1633            // These statement should all be resolved.
1634            "todo_deny b/001 test_exception_source_t test_exception_target_t file",
1635            "todo_deny b/002 test_exception_other_t test_exception_target_t chr_file",
1636            "todo_deny b/003 test_exception_source_t test_exception_other_t anon_inode",
1637            "todo_deny b/004 test_exception_permissive_t test_exception_target_t file",
1638            "todo_permissive b/005 test_exception_todo_permissive_t",
1639            // These statements should not be resolved.
1640            "todo_deny b/101 test_undefined_source_t test_exception_target_t file",
1641            "todo_deny b/102 test_exception_source_t test_undefined_target_t file",
1642            "todo_permissive b/103 test_undefined_source_t",
1643        ];
1644        let exceptions_config = EXCEPTIONS_CONFIG.iter().map(|x| String::from(*x)).collect();
1645        let security_server = SecurityServer::new(String::new(), exceptions_config);
1646        security_server.set_enforcing(true);
1647
1648        const EXCEPTIONS_POLICY: &[u8] =
1649            include_bytes!("../testdata/composite_policies/compiled/exceptions_config_policy");
1650        assert!(security_server.load_policy(EXCEPTIONS_POLICY.into()).is_ok());
1651
1652        let source_sid = security_server
1653            .security_context_to_sid("test_exception_u:object_r:test_exception_source_t:s0".into())
1654            .unwrap();
1655        let target_sid = security_server
1656            .security_context_to_sid("test_exception_u:object_r:test_exception_target_t:s0".into())
1657            .unwrap();
1658        let other_sid = security_server
1659            .security_context_to_sid("test_exception_u:object_r:test_exception_other_t:s0".into())
1660            .unwrap();
1661        let permissive_sid = security_server
1662            .security_context_to_sid(
1663                "test_exception_u:object_r:test_exception_permissive_t:s0".into(),
1664            )
1665            .unwrap();
1666        let unmatched_sid = security_server
1667            .security_context_to_sid(
1668                "test_exception_u:object_r:test_exception_unmatched_t:s0".into(),
1669            )
1670            .unwrap();
1671        let todo_permissive_sid = security_server
1672            .security_context_to_sid(
1673                "test_exception_u:object_r:test_exception_todo_permissive_t:s0".into(),
1674            )
1675            .unwrap();
1676
1677        let local_cache = Default::default();
1678        let permission_check = security_server.as_permission_check(&local_cache);
1679
1680        // Source SID has no "process" permissions to target SID, and no exceptions.
1681        let result =
1682            permission_check.has_permission(source_sid, target_sid, ProcessPermission::GetPgid);
1683        assert_eq!(
1684            result,
1685            PermissionCheckResult {
1686                granted: false,
1687                audit: true,
1688                permissive: false,
1689                todo_bug: None
1690            }
1691        );
1692        assert!(!result.permit());
1693
1694        // Source SID has no "file:entrypoint" permission to target SID, but there is an exception defined.
1695        let result =
1696            permission_check.has_permission(source_sid, target_sid, FilePermission::Entrypoint);
1697        assert_eq!(
1698            result,
1699            PermissionCheckResult {
1700                granted: true,
1701                audit: true,
1702                permissive: false,
1703                todo_bug: Some(NonZeroU32::new(1).unwrap())
1704            }
1705        );
1706        assert!(result.permit());
1707
1708        // Source SID has "file:execute_no_trans" permission to target SID.
1709        let result =
1710            permission_check.has_permission(source_sid, target_sid, FilePermission::ExecuteNoTrans);
1711        assert_eq!(
1712            result,
1713            PermissionCheckResult {
1714                granted: true,
1715                audit: false,
1716                permissive: false,
1717                todo_bug: None,
1718            }
1719        );
1720        assert!(result.permit());
1721
1722        // Other SID has no "file:entrypoint" permissions to target SID, and the exception does not match "file" class.
1723        let result =
1724            permission_check.has_permission(other_sid, target_sid, FilePermission::Entrypoint);
1725        assert_eq!(
1726            result,
1727            PermissionCheckResult {
1728                granted: false,
1729                audit: true,
1730                permissive: false,
1731                todo_bug: None
1732            }
1733        );
1734        assert!(!result.permit());
1735
1736        // Other SID has no "chr_file" permissions to target SID, but there is an exception defined.
1737        let result = permission_check.has_permission(
1738            other_sid,
1739            target_sid,
1740            CommonFsNodePermission::Read.for_class(FileClass::ChrFile),
1741        );
1742        assert_eq!(
1743            result,
1744            PermissionCheckResult {
1745                granted: true,
1746                audit: true,
1747                permissive: false,
1748                todo_bug: Some(NonZeroU32::new(2).unwrap())
1749            }
1750        );
1751        assert!(result.permit());
1752
1753        // Source SID has no "file:entrypoint" permissions to unmatched SID, and no exception is defined.
1754        let result =
1755            permission_check.has_permission(source_sid, unmatched_sid, FilePermission::Entrypoint);
1756        assert_eq!(
1757            result,
1758            PermissionCheckResult {
1759                granted: false,
1760                audit: true,
1761                permissive: false,
1762                todo_bug: None
1763            }
1764        );
1765        assert!(!result.permit());
1766
1767        // Unmatched SID has no "file:entrypoint" permissions to target SID, and no exception is defined.
1768        let result =
1769            permission_check.has_permission(unmatched_sid, target_sid, FilePermission::Entrypoint);
1770        assert_eq!(
1771            result,
1772            PermissionCheckResult {
1773                granted: false,
1774                audit: true,
1775                permissive: false,
1776                todo_bug: None
1777            }
1778        );
1779        assert!(!result.permit());
1780
1781        // Todo-deny exceptions are processed before the permissive bit is handled.
1782        let result =
1783            permission_check.has_permission(permissive_sid, target_sid, FilePermission::Entrypoint);
1784        assert_eq!(
1785            result,
1786            PermissionCheckResult {
1787                granted: true,
1788                audit: true,
1789                permissive: true,
1790                todo_bug: Some(NonZeroU32::new(4).unwrap())
1791            }
1792        );
1793        assert!(result.permit());
1794
1795        // Todo-permissive SID is not granted any permissions, so all permissions should be granted,
1796        // to all target domains and classes, and all grants should be associated with the bug.
1797        let result = permission_check.has_permission(
1798            todo_permissive_sid,
1799            target_sid,
1800            FilePermission::Entrypoint,
1801        );
1802        assert_eq!(
1803            result,
1804            PermissionCheckResult {
1805                granted: true,
1806                audit: true,
1807                permissive: false,
1808                todo_bug: Some(NonZeroU32::new(5).unwrap())
1809            }
1810        );
1811        assert!(result.permit());
1812        let result = permission_check.has_permission(
1813            todo_permissive_sid,
1814            todo_permissive_sid,
1815            FilePermission::Entrypoint,
1816        );
1817        assert_eq!(
1818            result,
1819            PermissionCheckResult {
1820                granted: true,
1821                audit: true,
1822                permissive: false,
1823                todo_bug: Some(NonZeroU32::new(5).unwrap())
1824            }
1825        );
1826        assert!(result.permit());
1827        let result = permission_check.has_permission(
1828            todo_permissive_sid,
1829            target_sid,
1830            FilePermission::Entrypoint,
1831        );
1832        assert_eq!(
1833            result,
1834            PermissionCheckResult {
1835                granted: true,
1836                audit: true,
1837                permissive: false,
1838                todo_bug: Some(NonZeroU32::new(5).unwrap())
1839            }
1840        );
1841        assert!(result.permit());
1842    }
1843
1844    #[test]
1845    fn handle_unknown() {
1846        let security_server = security_server_with_tests_policy();
1847
1848        let sid = security_server
1849            .security_context_to_sid("user0:object_r:type0:s0".into())
1850            .expect("Resolve Context to SID");
1851
1852        // Load a policy that is missing some elements, and marked handle_unknown=reject.
1853        // The policy should be rejected, since not all classes/permissions are defined.
1854        // Rejecting policy is not controlled by permissive vs enforcing.
1855        const REJECT_POLICY: &[u8] =
1856            include_bytes!("../testdata/composite_policies/compiled/handle_unknown_policy-reject");
1857        assert!(security_server.load_policy(REJECT_POLICY.to_vec()).is_err());
1858
1859        security_server.set_enforcing(true);
1860
1861        // Load a policy that is missing some elements, and marked handle_unknown=deny.
1862        const DENY_POLICY: &[u8] =
1863            include_bytes!("../testdata/composite_policies/compiled/handle_unknown_policy-deny");
1864        assert!(security_server.load_policy(DENY_POLICY.to_vec()).is_ok());
1865        let local_cache = Default::default();
1866        let permission_check = security_server.as_permission_check(&local_cache);
1867
1868        // Check against undefined classes or permissions should deny access and audit.
1869        let result = permission_check.has_permission(sid, sid, ProcessPermission::GetSched);
1870        assert_eq!(
1871            result,
1872            PermissionCheckResult {
1873                granted: false,
1874                audit: true,
1875                permissive: false,
1876                todo_bug: None
1877            }
1878        );
1879        assert!(!result.permit());
1880        let result = permission_check.has_permission(sid, sid, DirPermission::AddName);
1881        assert_eq!(
1882            result,
1883            PermissionCheckResult {
1884                granted: false,
1885                audit: true,
1886                permissive: false,
1887                todo_bug: None
1888            }
1889        );
1890        assert!(!result.permit());
1891
1892        // Check that permissions that are defined are unaffected by handle-unknown.
1893        let result = permission_check.has_permission(sid, sid, DirPermission::Search);
1894        assert_eq!(
1895            result,
1896            PermissionCheckResult {
1897                granted: true,
1898                audit: false,
1899                permissive: false,
1900                todo_bug: None
1901            }
1902        );
1903        assert!(result.permit());
1904        let result = permission_check.has_permission(sid, sid, DirPermission::Reparent);
1905        assert_eq!(
1906            result,
1907            PermissionCheckResult {
1908                granted: false,
1909                audit: true,
1910                permissive: false,
1911                todo_bug: None
1912            }
1913        );
1914        assert!(!result.permit());
1915
1916        // Load a policy that is missing some elements, and marked handle_unknown=allow.
1917        const ALLOW_POLICY: &[u8] =
1918            include_bytes!("../testdata/composite_policies/compiled/handle_unknown_policy-allow");
1919        assert!(security_server.load_policy(ALLOW_POLICY.to_vec()).is_ok());
1920        let local_cache2 = Default::default();
1921        let permission_check = security_server.as_permission_check(&local_cache2);
1922
1923        // Check against undefined classes or permissions should grant access without audit.
1924        let result = permission_check.has_permission(sid, sid, ProcessPermission::GetSched);
1925        assert_eq!(
1926            result,
1927            PermissionCheckResult {
1928                granted: true,
1929                audit: false,
1930                permissive: false,
1931                todo_bug: None
1932            }
1933        );
1934        assert!(result.permit());
1935        let result = permission_check.has_permission(sid, sid, DirPermission::AddName);
1936        assert_eq!(
1937            result,
1938            PermissionCheckResult {
1939                granted: true,
1940                audit: false,
1941                permissive: false,
1942                todo_bug: None
1943            }
1944        );
1945        assert!(result.permit());
1946
1947        // Check that permissions that are defined are unaffected by handle-unknown.
1948        let result = permission_check.has_permission(sid, sid, DirPermission::Search);
1949        assert_eq!(
1950            result,
1951            PermissionCheckResult {
1952                granted: true,
1953                audit: false,
1954                permissive: false,
1955                todo_bug: None
1956            }
1957        );
1958        assert!(result.permit());
1959
1960        let result = permission_check.has_permission(sid, sid, DirPermission::Reparent);
1961        assert_eq!(
1962            result,
1963            PermissionCheckResult {
1964                granted: false,
1965                audit: true,
1966                permissive: false,
1967                todo_bug: None
1968            }
1969        );
1970        assert!(!result.permit());
1971    }
1972}