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    ) -> FileSystemLabel {
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        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    }
464
465    /// Returns the [`SecurityId`] with which to label an [`FsNode`] in a filesystem of `fs_type`,
466    /// at the specified filesystem-relative `node_path`.  Callers are responsible for ensuring that
467    /// this API is never called prior to a policy first being loaded, or for a filesystem that is
468    /// not configured to be `genfscon`-labeled.
469    pub fn genfscon_label_for_fs_and_path(
470        &self,
471        fs_type: NullessByteStr<'_>,
472        node_path: NullessByteStr<'_>,
473        class_id: Option<KernelClass>,
474    ) -> Result<SecurityId, anyhow::Error> {
475        self.backend.compute_sid(|active_policy| {
476            active_policy
477                .parsed
478                .genfscon_label_for_fs_and_path(fs_type, node_path.into(), class_id)
479                .ok_or_else(|| {
480                    anyhow::anyhow!("Genfscon label requested for non-genfscon labeled filesystem")
481                })
482        })
483    }
484
485    /// Returns true if the `bounded_sid` is bounded by the `parent_sid`.
486    /// Bounds relationships are mostly enforced by policy tooling, so this only requires validating
487    /// that the policy entry for the `TypeId` of `bounded_sid` has the `TypeId` of `parent_sid`
488    /// specified in its `bounds`.
489    pub fn is_bounded_by(&self, bounded_sid: SecurityId, parent_sid: SecurityId) -> bool {
490        let locked_state = self.backend.state.read();
491        let active_policy = locked_state.expect_active_policy();
492        let bounded_type = active_policy.sid_table.sid_to_security_context(bounded_sid).type_();
493        let parent_type = active_policy.sid_table.sid_to_security_context(parent_sid).type_();
494        active_policy.parsed.is_bounded_by(bounded_type, parent_type)
495    }
496
497    /// Assign a [`SeLinuxStatusPublisher`] to be used for pushing updates to the security server's
498    /// policy status. This should be invoked exactly once when `selinuxfs` is initialized.
499    ///
500    /// # Panics
501    ///
502    /// This will panic on debug builds if it is invoked multiple times.
503    pub fn set_status_publisher(&self, status_holder: Box<dyn SeLinuxStatusPublisher>) {
504        self.with_mut_state_and_update_status(|state| {
505            assert!(state.status_publisher.is_none());
506            state.status_publisher = Some(status_holder);
507        });
508    }
509
510    /// Locks the security server state for modification and calls the supplied function to update
511    /// it.  Once the update is complete, the configured `SeLinuxStatusPublisher` (if any) is called
512    /// to update the userspace-facing "status" file to reflect the new state.
513    fn with_mut_state_and_update_status(&self, f: impl FnOnce(&mut SecurityServerState)) {
514        let mut locked_state = self.backend.state.write();
515        f(locked_state.deref_mut());
516        let new_value = SeLinuxStatus {
517            is_enforcing: self.is_enforcing(),
518            change_count: self.backend.policy_change_count.load(Ordering::Relaxed),
519            deny_unknown: locked_state.deny_unknown(),
520        };
521        if let Some(status_publisher) = &mut locked_state.status_publisher {
522            status_publisher.set_status(new_value);
523        }
524
525        // TODO: https://fxbug.dev/367585803 - reset the cache after running `f` and before updating
526        // the userspace-facing "status", once that is possible.
527        std::mem::drop(locked_state);
528        self.access_vector_cache.reset();
529    }
530
531    /// Returns the security identifier (SID) with which to label a new object of `target_class`,
532    /// based on the specified source & target security SIDs.
533    /// For file-like classes the `compute_new_fs_node_sid*()` APIs should be used instead.
534    // TODO: Move this API to sit alongside the other `compute_*()` APIs.
535    // TODO: https://fxbug.dev/335397745 - APIs should not mix SecurityId and (raw) ClassId.
536    pub fn compute_create_sid_raw(
537        &self,
538        source_sid: SecurityId,
539        target_sid: SecurityId,
540        target_class: ClassId,
541    ) -> Result<SecurityId, anyhow::Error> {
542        self.backend.compute_create_sid_raw(source_sid, target_sid, target_class.into())
543    }
544
545    /// Returns the raw `AccessDecision` for a specified source, target and class.
546    // TODO: APIs should not mix SecurityId and (raw) ClassId.
547    pub fn compute_access_decision_raw(
548        &self,
549        source_sid: SecurityId,
550        target_sid: SecurityId,
551        target_class: ClassId,
552    ) -> AccessDecision {
553        self.backend.compute_access_decision_raw(source_sid, target_sid, target_class.into())
554    }
555}
556
557impl SecurityServerBackend {
558    fn compute_create_sid_raw(
559        &self,
560        source_sid: SecurityId,
561        target_sid: SecurityId,
562        target_class: ObjectClass,
563    ) -> Result<SecurityId, anyhow::Error> {
564        self.compute_sid(|active_policy| {
565            let source_context = active_policy.sid_table.sid_to_security_context(source_sid);
566            let target_context = active_policy.sid_table.sid_to_security_context(target_sid);
567
568            Ok(active_policy.parsed.compute_create_context(
569                source_context,
570                target_context,
571                target_class,
572            ))
573        })
574        .context("computing new security context from policy")
575    }
576
577    /// Helper for call-sites that need to compute a `SecurityContext` and assign a SID to it.
578    fn compute_sid(
579        &self,
580        compute_context: impl Fn(&ActivePolicy) -> Result<SecurityContext, anyhow::Error>,
581    ) -> Result<SecurityId, anyhow::Error> {
582        // Initially assume that the computed context will most likely already have a SID assigned,
583        // so that the operation can be completed without any modification of the SID table.
584        let readable_state = self.state.read();
585        let policy_change_count = self.policy_change_count.load(Ordering::Relaxed);
586        let policy_state = readable_state
587            .active_policy
588            .as_ref()
589            .ok_or_else(|| anyhow::anyhow!("no policy loaded"))?;
590        let context = compute_context(policy_state)?;
591        if let Some(sid) = policy_state.sid_table.security_context_to_existing_sid(&context) {
592            return Ok(sid);
593        }
594        std::mem::drop(readable_state);
595
596        // Since the computed context was not found in the table, re-try the operation with the
597        // policy state write-locked to allow for the SID table to be updated. In the rare case of
598        // a new policy having been loaded in-between the read- and write-locked stages, the
599        // `context` is re-computed using the new policy state.
600        let mut writable_state = self.state.write();
601        let needs_recompute =
602            policy_change_count != self.policy_change_count.load(Ordering::Relaxed);
603        let policy_state = writable_state.active_policy.as_mut().unwrap();
604        let context = if needs_recompute { compute_context(policy_state)? } else { context };
605        policy_state.sid_table.security_context_to_sid(&context).map_err(anyhow::Error::from)
606    }
607
608    fn compute_access_decision_raw(
609        &self,
610        source_sid: SecurityId,
611        target_sid: SecurityId,
612        target_class: ObjectClass,
613    ) -> AccessDecision {
614        let locked_state = self.state.read();
615
616        locked_state.compute_access_decision_raw(source_sid, target_sid, target_class)
617    }
618}
619
620impl Query for SecurityServerBackend {
621    fn compute_access_decision(
622        &self,
623        source_sid: SecurityId,
624        target_sid: SecurityId,
625        target_class: KernelClass,
626    ) -> KernelAccessDecision {
627        let locked_state = self.state.read();
628        let decision =
629            locked_state.compute_access_decision_raw(source_sid, target_sid, target_class.into());
630        locked_state.access_decision_to_kernel_access_decision(target_class, decision)
631    }
632
633    fn compute_create_sid(
634        &self,
635        source_sid: SecurityId,
636        target_sid: SecurityId,
637        target_class: KernelClass,
638    ) -> Result<SecurityId, anyhow::Error> {
639        self.compute_create_sid_raw(source_sid, target_sid, target_class.into())
640    }
641
642    fn compute_new_fs_node_sid_with_name(
643        &self,
644        source_sid: SecurityId,
645        target_sid: SecurityId,
646        fs_node_class: FsNodeClass,
647        fs_node_name: NullessByteStr<'_>,
648    ) -> Option<SecurityId> {
649        let mut locked_state = self.state.write();
650
651        // This interface will not be reached without a policy having been loaded.
652        let active_policy = locked_state.active_policy.as_mut().expect("Policy loaded");
653
654        let source_context = active_policy.sid_table.sid_to_security_context(source_sid);
655        let target_context = active_policy.sid_table.sid_to_security_context(target_sid);
656
657        let new_file_context = active_policy.parsed.compute_create_context_with_name(
658            source_context,
659            target_context,
660            fs_node_class,
661            fs_node_name,
662        )?;
663
664        active_policy.sid_table.security_context_to_sid(&new_file_context).ok()
665    }
666
667    fn compute_xperms_access_decision(
668        &self,
669        xperms_kind: XpermsKind,
670        source_sid: SecurityId,
671        target_sid: SecurityId,
672        permission: KernelPermission,
673        xperms_prefix: u8,
674    ) -> KernelXpermsAccessDecision {
675        let locked_state = self.state.read();
676
677        let active_policy = match &locked_state.active_policy {
678            Some(active_policy) => active_policy,
679            // All permissions are allowed when no policy is loaded, regardless of enforcing state.
680            None => {
681                return KernelXpermsAccessDecision {
682                    allow: XpermsBitmap::ALL,
683                    audit: XpermsBitmap::NONE,
684                    permissive: false,
685                    has_todo: false,
686                };
687            }
688        };
689
690        // Look up the decision for the base permission.
691        // TODO(b/493591579): avoid multiple lookups in the SID table
692        let base_decision_raw = locked_state.compute_access_decision_raw(
693            source_sid,
694            target_sid,
695            permission.class().into(),
696        );
697        let base_decision = locked_state
698            .access_decision_to_kernel_access_decision(permission.class(), base_decision_raw);
699        let permission_access_vector = permission.as_access_vector();
700        let base_permit =
701            base_decision.allow & permission_access_vector == permission_access_vector;
702        let base_audit = base_decision.audit & permission_access_vector == permission_access_vector;
703
704        // Look up the extended permission decision.
705        let source_context = active_policy.sid_table.sid_to_security_context(source_sid);
706        let target_context = active_policy.sid_table.sid_to_security_context(target_sid);
707        let xperms_decision = active_policy.parsed.compute_xperms_access_decision(
708            xperms_kind,
709            &source_context,
710            &target_context,
711            permission.class(),
712            xperms_prefix,
713        );
714
715        // Combine the base and extended decisions.
716        let allow = if !base_permit { XpermsBitmap::NONE } else { xperms_decision.allow };
717        let audit = if base_audit {
718            XpermsBitmap::ALL
719        } else {
720            (xperms_decision.allow & xperms_decision.auditallow)
721                | (!xperms_decision.allow & xperms_decision.auditdeny)
722        };
723        let permissive = (base_decision.flags & SELINUX_AVD_FLAGS_PERMISSIVE) != 0;
724        let has_todo = base_decision.todo_bug.is_some();
725        KernelXpermsAccessDecision { allow, audit, permissive, has_todo }
726    }
727}
728
729impl AccessVectorComputer for SecurityServerBackend {
730    fn access_decision_to_kernel_access_decision(
731        &self,
732        class: KernelClass,
733        av: AccessDecision,
734    ) -> KernelAccessDecision {
735        self.state.read().access_decision_to_kernel_access_decision(class, av)
736    }
737}
738
739impl AccessVectorComputer for SecurityServerState {
740    fn access_decision_to_kernel_access_decision(
741        &self,
742        class: KernelClass,
743        av: AccessDecision,
744    ) -> KernelAccessDecision {
745        match &self.active_policy {
746            Some(policy) => policy.parsed.access_decision_to_kernel_access_decision(class, av),
747            None => KernelAccessDecision {
748                allow: AccessVector::ALL,
749                audit: AccessVector::NONE,
750                flags: 0,
751                todo_bug: None,
752            },
753        }
754    }
755}
756
757/// Computes a [`SecurityId`] given a non-[`None`] value for one of the four
758/// "context" mount options (https://man7.org/linux/man-pages/man8/mount.8.html).
759fn sid_from_mount_option(
760    active_policy: &mut ActivePolicy,
761    mount_option: &Option<Vec<u8>>,
762) -> Option<SecurityId> {
763    if let Some(label) = mount_option.as_ref() {
764        Some(
765            if let Some(context) = active_policy.parsed.parse_security_context(label.into()).ok() {
766                active_policy.sid_table.security_context_to_sid(&context).unwrap()
767            } else {
768                // The mount option is present-but-not-valid: we use `Unlabeled`.
769                InitialSid::Unlabeled.into()
770            },
771        )
772    } else {
773        None
774    }
775}
776
777#[cfg(test)]
778mod tests {
779    use super::*;
780    use crate::permission_check::PermissionCheckResult;
781    use crate::{
782        CommonFsNodePermission, DirPermission, FileClass, FilePermission, ForClass, KernelClass,
783        ProcessPermission,
784    };
785    use std::num::NonZeroU32;
786
787    const TESTSUITE_BINARY_POLICY: &[u8] = include_bytes!("../testdata/policies/selinux_testsuite");
788    const TESTS_BINARY_POLICY: &[u8] =
789        include_bytes!("../testdata/micro_policies/security_server_tests_policy");
790    const MINIMAL_BINARY_POLICY: &[u8] =
791        include_bytes!("../testdata/composite_policies/compiled/minimal_policy");
792
793    fn security_server_with_tests_policy() -> Arc<SecurityServer> {
794        let policy_bytes = TESTS_BINARY_POLICY.to_vec();
795        let security_server = SecurityServer::new_default();
796        assert_eq!(
797            Ok(()),
798            security_server.load_policy(policy_bytes).map_err(|e| format!("{:?}", e))
799        );
800        security_server
801    }
802
803    #[test]
804    fn compute_access_vector_allows_all() {
805        let security_server = SecurityServer::new_default();
806        let sid1 = InitialSid::Kernel.into();
807        let sid2 = InitialSid::Unlabeled.into();
808        assert_eq!(
809            security_server
810                .backend
811                .compute_access_decision(sid1, sid2, KernelClass::Process.into())
812                .allow,
813            AccessVector::ALL
814        );
815    }
816
817    #[test]
818    fn loaded_policy_can_be_retrieved() {
819        let security_server = security_server_with_tests_policy();
820        assert_eq!(TESTS_BINARY_POLICY, security_server.get_binary_policy().unwrap().as_slice());
821    }
822
823    #[test]
824    fn loaded_policy_is_validated() {
825        let not_really_a_policy = "not a real policy".as_bytes().to_vec();
826        let security_server = SecurityServer::new_default();
827        assert!(security_server.load_policy(not_really_a_policy.clone()).is_err());
828    }
829
830    #[test]
831    fn enforcing_mode_is_reported() {
832        let security_server = SecurityServer::new_default();
833        assert!(!security_server.is_enforcing());
834
835        security_server.set_enforcing(true);
836        assert!(security_server.is_enforcing());
837    }
838
839    #[test]
840    fn without_policy_conditional_booleans_are_empty() {
841        let security_server = SecurityServer::new_default();
842        assert!(security_server.conditional_booleans().is_empty());
843    }
844
845    #[test]
846    fn conditional_booleans_can_be_queried() {
847        let policy_bytes = TESTSUITE_BINARY_POLICY.to_vec();
848        let security_server = SecurityServer::new_default();
849        assert_eq!(
850            Ok(()),
851            security_server.load_policy(policy_bytes).map_err(|e| format!("{:?}", e))
852        );
853
854        let booleans = security_server.conditional_booleans();
855        assert!(!booleans.is_empty());
856        let boolean = booleans[0].as_str();
857
858        assert!(security_server.get_boolean("this_is_not_a_valid_boolean_name").is_err());
859        assert!(security_server.get_boolean(boolean).is_ok());
860    }
861
862    #[test]
863    fn conditional_booleans_can_be_changed() {
864        let policy_bytes = TESTSUITE_BINARY_POLICY.to_vec();
865        let security_server = SecurityServer::new_default();
866        assert_eq!(
867            Ok(()),
868            security_server.load_policy(policy_bytes).map_err(|e| format!("{:?}", e))
869        );
870
871        let booleans = security_server.conditional_booleans();
872        assert!(!booleans.is_empty());
873        let boolean = booleans[0].as_str();
874
875        let (active, pending) = security_server.get_boolean(boolean).unwrap();
876        assert_eq!(active, pending, "Initially active and pending values should match");
877
878        security_server.set_pending_boolean(boolean, !active).unwrap();
879        let (active, pending) = security_server.get_boolean(boolean).unwrap();
880        assert!(active != pending, "Before commit pending should differ from active");
881
882        security_server.commit_pending_booleans();
883        let (final_active, final_pending) = security_server.get_boolean(boolean).unwrap();
884        assert_eq!(final_active, pending, "Pending value should be active after commit");
885        assert_eq!(final_active, final_pending, "Active and pending are the same after commit");
886    }
887
888    #[test]
889    fn parse_security_context_no_policy() {
890        let security_server = SecurityServer::new_default();
891        let error = security_server
892            .security_context_to_sid(b"unconfined_u:unconfined_r:unconfined_t:s0".into())
893            .expect_err("expected error");
894        let error_string = format!("{:?}", error);
895        assert!(error_string.contains("no policy"));
896    }
897
898    #[test]
899    fn compute_new_fs_node_sid_no_defaults() {
900        let security_server = SecurityServer::new_default();
901        let policy_bytes =
902            include_bytes!("../testdata/micro_policies/file_no_defaults_policy").to_vec();
903        security_server.load_policy(policy_bytes).expect("binary policy loads");
904
905        let source_sid = security_server
906            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s1".into())
907            .expect("creating SID from security context should succeed");
908        let target_sid = security_server
909            .security_context_to_sid(b"file_u:object_r:file_t:s0".into())
910            .expect("creating SID from security context should succeed");
911
912        let computed_sid = security_server
913            .as_permission_check(&Default::default())
914            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
915            .expect("new sid computed");
916        let computed_context = security_server
917            .sid_to_security_context(computed_sid)
918            .expect("computed sid associated with context");
919
920        // User and low security level should be copied from the source,
921        // and the role and type from the target.
922        assert_eq!(computed_context, b"user_u:object_r:file_t:s0");
923    }
924
925    #[test]
926    fn compute_new_fs_node_sid_source_defaults() {
927        let security_server = SecurityServer::new_default();
928        let policy_bytes =
929            include_bytes!("../testdata/micro_policies/file_source_defaults_policy").to_vec();
930        security_server.load_policy(policy_bytes).expect("binary policy loads");
931
932        let source_sid = security_server
933            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s2:c0".into())
934            .expect("creating SID from security context should succeed");
935        let target_sid = security_server
936            .security_context_to_sid(b"file_u:object_r:file_t:s1-s3:c0".into())
937            .expect("creating SID from security context should succeed");
938
939        let computed_sid = security_server
940            .as_permission_check(&Default::default())
941            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
942            .expect("new sid computed");
943        let computed_context = security_server
944            .sid_to_security_context(computed_sid)
945            .expect("computed sid associated with context");
946
947        // All fields should be copied from the source, but only the "low" part of the security
948        // range.
949        assert_eq!(computed_context, b"user_u:unconfined_r:unconfined_t:s0");
950    }
951
952    #[test]
953    fn compute_new_fs_node_sid_target_defaults() {
954        let security_server = SecurityServer::new_default();
955        let policy_bytes =
956            include_bytes!("../testdata/micro_policies/file_target_defaults_policy").to_vec();
957        security_server.load_policy(policy_bytes).expect("binary policy loads");
958
959        let source_sid = security_server
960            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s2:c0".into())
961            .expect("creating SID from security context should succeed");
962        let target_sid = security_server
963            .security_context_to_sid(b"file_u:object_r:file_t:s1-s3:c0".into())
964            .expect("creating SID from security context should succeed");
965
966        let computed_sid = security_server
967            .as_permission_check(&Default::default())
968            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
969            .expect("new sid computed");
970        let computed_context = security_server
971            .sid_to_security_context(computed_sid)
972            .expect("computed sid associated with context");
973
974        // User, role and type copied from target, with source's low security level.
975        assert_eq!(computed_context, b"file_u:object_r:file_t:s0");
976    }
977
978    #[test]
979    fn compute_new_fs_node_sid_range_source_low_default() {
980        let security_server = SecurityServer::new_default();
981        let policy_bytes =
982            include_bytes!("../testdata/micro_policies/file_range_source_low_policy").to_vec();
983        security_server.load_policy(policy_bytes).expect("binary policy loads");
984
985        let source_sid = security_server
986            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s1:c0".into())
987            .expect("creating SID from security context should succeed");
988        let target_sid = security_server
989            .security_context_to_sid(b"file_u:object_r:file_t:s1".into())
990            .expect("creating SID from security context should succeed");
991
992        let computed_sid = security_server
993            .as_permission_check(&Default::default())
994            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
995            .expect("new sid computed");
996        let computed_context = security_server
997            .sid_to_security_context(computed_sid)
998            .expect("computed sid associated with context");
999
1000        // User and low security level copied from source, role and type as default.
1001        assert_eq!(computed_context, b"user_u:object_r:file_t:s0");
1002    }
1003
1004    #[test]
1005    fn compute_new_fs_node_sid_range_source_low_high_default() {
1006        let security_server = SecurityServer::new_default();
1007        let policy_bytes =
1008            include_bytes!("../testdata/micro_policies/file_range_source_low_high_policy").to_vec();
1009        security_server.load_policy(policy_bytes).expect("binary policy loads");
1010
1011        let source_sid = security_server
1012            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s1:c0".into())
1013            .expect("creating SID from security context should succeed");
1014        let target_sid = security_server
1015            .security_context_to_sid(b"file_u:object_r:file_t:s1".into())
1016            .expect("creating SID from security context should succeed");
1017
1018        let computed_sid = security_server
1019            .as_permission_check(&Default::default())
1020            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
1021            .expect("new sid computed");
1022        let computed_context = security_server
1023            .sid_to_security_context(computed_sid)
1024            .expect("computed sid associated with context");
1025
1026        // User and full security range copied from source, role and type as default.
1027        assert_eq!(computed_context, b"user_u:object_r:file_t:s0-s1:c0");
1028    }
1029
1030    #[test]
1031    fn compute_new_fs_node_sid_range_source_high_default() {
1032        let security_server = SecurityServer::new_default();
1033        let policy_bytes =
1034            include_bytes!("../testdata/micro_policies/file_range_source_high_policy").to_vec();
1035        security_server.load_policy(policy_bytes).expect("binary policy loads");
1036
1037        let source_sid = security_server
1038            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s1:c0".into())
1039            .expect("creating SID from security context should succeed");
1040        let target_sid = security_server
1041            .security_context_to_sid(b"file_u:object_r:file_t:s0".into())
1042            .expect("creating SID from security context should succeed");
1043
1044        let computed_sid = security_server
1045            .as_permission_check(&Default::default())
1046            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
1047            .expect("new sid computed");
1048        let computed_context = security_server
1049            .sid_to_security_context(computed_sid)
1050            .expect("computed sid associated with context");
1051
1052        // User and high security level copied from source, role and type as default.
1053        assert_eq!(computed_context, b"user_u:object_r:file_t:s1:c0");
1054    }
1055
1056    #[test]
1057    fn compute_new_fs_node_sid_range_target_low_default() {
1058        let security_server = SecurityServer::new_default();
1059        let policy_bytes =
1060            include_bytes!("../testdata/micro_policies/file_range_target_low_policy").to_vec();
1061        security_server.load_policy(policy_bytes).expect("binary policy loads");
1062
1063        let source_sid = security_server
1064            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s1".into())
1065            .expect("creating SID from security context should succeed");
1066        let target_sid = security_server
1067            .security_context_to_sid(b"file_u:object_r:file_t:s0-s1:c0".into())
1068            .expect("creating SID from security context should succeed");
1069
1070        let computed_sid = security_server
1071            .as_permission_check(&Default::default())
1072            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
1073            .expect("new sid computed");
1074        let computed_context = security_server
1075            .sid_to_security_context(computed_sid)
1076            .expect("computed sid associated with context");
1077
1078        // User copied from source, low security level from target, role and type as default.
1079        assert_eq!(computed_context, b"user_u:object_r:file_t:s0");
1080    }
1081
1082    #[test]
1083    fn compute_new_fs_node_sid_range_target_low_high_default() {
1084        let security_server = SecurityServer::new_default();
1085        let policy_bytes =
1086            include_bytes!("../testdata/micro_policies/file_range_target_low_high_policy").to_vec();
1087        security_server.load_policy(policy_bytes).expect("binary policy loads");
1088
1089        let source_sid = security_server
1090            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s1".into())
1091            .expect("creating SID from security context should succeed");
1092        let target_sid = security_server
1093            .security_context_to_sid(b"file_u:object_r:file_t:s0-s1:c0".into())
1094            .expect("creating SID from security context should succeed");
1095
1096        let computed_sid = security_server
1097            .as_permission_check(&Default::default())
1098            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
1099            .expect("new sid computed");
1100        let computed_context = security_server
1101            .sid_to_security_context(computed_sid)
1102            .expect("computed sid associated with context");
1103
1104        // User copied from source, full security range from target, role and type as default.
1105        assert_eq!(computed_context, b"user_u:object_r:file_t:s0-s1:c0");
1106    }
1107
1108    #[test]
1109    fn compute_new_fs_node_sid_range_target_high_default() {
1110        let security_server = SecurityServer::new_default();
1111        let policy_bytes =
1112            include_bytes!("../testdata/micro_policies/file_range_target_high_policy").to_vec();
1113        security_server.load_policy(policy_bytes).expect("binary policy loads");
1114
1115        let source_sid = security_server
1116            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0".into())
1117            .expect("creating SID from security context should succeed");
1118        let target_sid = security_server
1119            .security_context_to_sid(b"file_u:object_r:file_t:s0-s1:c0".into())
1120            .expect("creating SID from security context should succeed");
1121
1122        let computed_sid = security_server
1123            .as_permission_check(&Default::default())
1124            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
1125            .expect("new sid computed");
1126        let computed_context = security_server
1127            .sid_to_security_context(computed_sid)
1128            .expect("computed sid associated with context");
1129
1130        // User copied from source, high security level from target, role and type as default.
1131        assert_eq!(computed_context, b"user_u:object_r:file_t:s1:c0");
1132    }
1133
1134    #[test]
1135    fn compute_new_fs_node_sid_with_name() {
1136        let security_server = SecurityServer::new_default();
1137        let policy_bytes =
1138            include_bytes!("../testdata/composite_policies/compiled/type_transition_policy")
1139                .to_vec();
1140        security_server.load_policy(policy_bytes).expect("binary policy loads");
1141
1142        let source_sid = security_server
1143            .security_context_to_sid(b"source_u:source_r:source_t:s0".into())
1144            .expect("creating SID from security context should succeed");
1145        let target_sid = security_server
1146            .security_context_to_sid(b"target_u:object_r:target_t:s0".into())
1147            .expect("creating SID from security context should succeed");
1148
1149        const SPECIAL_FILE_NAME: &[u8] = b"special_file";
1150        let computed_sid = security_server
1151            .as_permission_check(&Default::default())
1152            .compute_new_fs_node_sid(
1153                source_sid,
1154                target_sid,
1155                FileClass::File.into(),
1156                SPECIAL_FILE_NAME.into(),
1157            )
1158            .expect("new sid computed");
1159        let computed_context = security_server
1160            .sid_to_security_context(computed_sid)
1161            .expect("computed sid associated with context");
1162
1163        // New domain should be derived from the filename-specific rule.
1164        assert_eq!(computed_context, b"source_u:object_r:special_transition_t:s0");
1165
1166        let computed_sid = security_server
1167            .as_permission_check(&Default::default())
1168            .compute_new_fs_node_sid(
1169                source_sid,
1170                target_sid,
1171                FileClass::ChrFile.into(),
1172                SPECIAL_FILE_NAME.into(),
1173            )
1174            .expect("new sid computed");
1175        let computed_context = security_server
1176            .sid_to_security_context(computed_sid)
1177            .expect("computed sid associated with context");
1178
1179        // New domain should be copied from the target, because the class does not match either the
1180        // filename-specific nor generic type transition rules.
1181        assert_eq!(computed_context, b"source_u:object_r:target_t:s0");
1182
1183        const OTHER_FILE_NAME: &[u8] = b"other_file";
1184        let computed_sid = security_server
1185            .as_permission_check(&Default::default())
1186            .compute_new_fs_node_sid(
1187                source_sid,
1188                target_sid,
1189                FileClass::File.into(),
1190                OTHER_FILE_NAME.into(),
1191            )
1192            .expect("new sid computed");
1193        let computed_context = security_server
1194            .sid_to_security_context(computed_sid)
1195            .expect("computed sid associated with context");
1196
1197        // New domain should be derived from the non-filename-specific rule, because the filename
1198        // does not match.
1199        assert_eq!(computed_context, b"source_u:object_r:transition_t:s0");
1200    }
1201
1202    #[test]
1203    fn permissions_are_fresh_after_different_policy_load() {
1204        let minimal_bytes = MINIMAL_BINARY_POLICY.to_vec();
1205        let allow_fork_bytes =
1206            include_bytes!("../testdata/composite_policies/compiled/allow_fork_policy").to_vec();
1207        let context = b"source_u:object_r:source_t:s0:c0";
1208
1209        let security_server = SecurityServer::new_default();
1210        security_server.set_enforcing(true);
1211
1212        let local_cache = Default::default();
1213        let permission_check = security_server.as_permission_check(&local_cache);
1214
1215        // Load the minimal policy and get a SID for the context.
1216        assert_eq!(
1217            Ok(()),
1218            security_server.load_policy(minimal_bytes).map_err(|e| format!("{:?}", e))
1219        );
1220        let sid = security_server.security_context_to_sid(context.into()).unwrap();
1221
1222        // The minimal policy does not grant fork allowance.
1223        assert!(!permission_check.has_permission(sid, sid, ProcessPermission::Fork).granted);
1224
1225        // Load a policy that does grant fork allowance.
1226        assert_eq!(
1227            Ok(()),
1228            security_server.load_policy(allow_fork_bytes).map_err(|e| format!("{:?}", e))
1229        );
1230
1231        // Reuse the cache to check invalidation.
1232        let permission_check = security_server.as_permission_check(&local_cache);
1233
1234        // The now-loaded "allow_fork" policy allows the context represented by `sid` to fork.
1235        assert!(permission_check.has_permission(sid, sid, ProcessPermission::Fork).granted);
1236    }
1237
1238    #[test]
1239    fn unknown_sids_are_effectively_unlabeled() {
1240        let with_unlabeled_access_domain_policy_bytes = include_bytes!(
1241            "../testdata/composite_policies/compiled/with_unlabeled_access_domain_policy"
1242        )
1243        .to_vec();
1244        let with_additional_domain_policy_bytes =
1245            include_bytes!("../testdata/composite_policies/compiled/with_additional_domain_policy")
1246                .to_vec();
1247        let allowed_type_context = b"source_u:object_r:allowed_t:s0:c0";
1248        let additional_type_context = b"source_u:object_r:additional_t:s0:c0";
1249
1250        let security_server = SecurityServer::new_default();
1251        security_server.set_enforcing(true);
1252
1253        // Load a policy, get a SID for a context that is valid for that policy, and verify
1254        // that a context that is not valid for that policy is not issued a SID.
1255        assert_eq!(
1256            Ok(()),
1257            security_server
1258                .load_policy(with_unlabeled_access_domain_policy_bytes.clone())
1259                .map_err(|e| format!("{:?}", e))
1260        );
1261        let allowed_type_sid =
1262            security_server.security_context_to_sid(allowed_type_context.into()).unwrap();
1263        assert!(security_server.security_context_to_sid(additional_type_context.into()).is_err());
1264
1265        // Load the policy that makes the second context valid, and verify that it is valid, and
1266        // verify that the first context remains valid (and unchanged).
1267        assert_eq!(
1268            Ok(()),
1269            security_server
1270                .load_policy(with_additional_domain_policy_bytes.clone())
1271                .map_err(|e| format!("{:?}", e))
1272        );
1273        let additional_type_sid =
1274            security_server.security_context_to_sid(additional_type_context.into()).unwrap();
1275        assert_eq!(
1276            allowed_type_sid,
1277            security_server.security_context_to_sid(allowed_type_context.into()).unwrap()
1278        );
1279
1280        let local_cache = Default::default();
1281        let permission_check = security_server.as_permission_check(&local_cache);
1282
1283        // "allowed_t" is allowed the process getsched capability to "unlabeled_t" - but since
1284        // the currently-loaded policy defines "additional_t", the SID for "additional_t" does
1285        // not get treated as effectively unlabeled, and these permission checks are denied.
1286        assert!(
1287            !permission_check
1288                .has_permission(additional_type_sid, allowed_type_sid, ProcessPermission::GetSched)
1289                .granted
1290        );
1291        assert!(
1292            !permission_check
1293                .has_permission(additional_type_sid, allowed_type_sid, ProcessPermission::SetSched)
1294                .granted
1295        );
1296        assert!(
1297            !permission_check
1298                .has_permission(allowed_type_sid, additional_type_sid, ProcessPermission::GetSched)
1299                .granted
1300        );
1301        assert!(
1302            !permission_check
1303                .has_permission(allowed_type_sid, additional_type_sid, ProcessPermission::SetSched)
1304                .granted
1305        );
1306
1307        // We now flip back to the policy that does not recognize "additional_t"...
1308        assert_eq!(
1309            Ok(()),
1310            security_server
1311                .load_policy(with_unlabeled_access_domain_policy_bytes)
1312                .map_err(|e| format!("{:?}", e))
1313        );
1314
1315        // Reuse the cache to check invalidation.
1316        let permission_check = security_server.as_permission_check(&local_cache);
1317
1318        // The now-loaded policy allows "allowed_t" the process getsched capability
1319        // to "unlabeled_t" and since the now-loaded policy does not recognize "additional_t",
1320        // "allowed_t" is now allowed the process getsched capability to "additional_t".
1321        assert!(
1322            permission_check
1323                .has_permission(allowed_type_sid, additional_type_sid, ProcessPermission::GetSched)
1324                .granted
1325        );
1326        assert!(
1327            !permission_check
1328                .has_permission(allowed_type_sid, additional_type_sid, ProcessPermission::SetSched)
1329                .granted
1330        );
1331
1332        // ... and the now-loaded policy also allows "unlabeled_t" the process
1333        // setsched capability to "allowed_t" and since the now-loaded policy does not recognize
1334        // "additional_t", "unlabeled_t" is now allowed the process setsched capability to
1335        // "allowed_t".
1336        assert!(
1337            !permission_check
1338                .has_permission(additional_type_sid, allowed_type_sid, ProcessPermission::GetSched)
1339                .granted
1340        );
1341        assert!(
1342            permission_check
1343                .has_permission(additional_type_sid, allowed_type_sid, ProcessPermission::SetSched)
1344                .granted
1345        );
1346
1347        // We also verify that we do not get a serialization for unrecognized "additional_t"...
1348        assert!(security_server.sid_to_security_context(additional_type_sid).is_none());
1349
1350        // ... but if we flip forward to the policy that recognizes "additional_t", then we see
1351        // the serialization succeed and return the original context string.
1352        assert_eq!(
1353            Ok(()),
1354            security_server
1355                .load_policy(with_additional_domain_policy_bytes)
1356                .map_err(|e| format!("{:?}", e))
1357        );
1358        assert_eq!(
1359            additional_type_context.to_vec(),
1360            security_server.sid_to_security_context(additional_type_sid).unwrap()
1361        );
1362    }
1363
1364    #[test]
1365    fn permission_check_permissive() {
1366        let security_server = security_server_with_tests_policy();
1367        security_server.set_enforcing(false);
1368        assert!(!security_server.is_enforcing());
1369
1370        let sid =
1371            security_server.security_context_to_sid("user0:object_r:type0:s0".into()).unwrap();
1372        let local_cache = Default::default();
1373        let permission_check = security_server.as_permission_check(&local_cache);
1374
1375        // Test policy grants "type0" the process-fork permission to itself.
1376        // Since the permission is granted by policy, the check will not be audit logged.
1377        assert_eq!(
1378            permission_check.has_permission(sid, sid, ProcessPermission::Fork),
1379            PermissionCheckResult {
1380                granted: true,
1381                audit: false,
1382                permissive: false,
1383                todo_bug: None
1384            }
1385        );
1386
1387        // Test policy does not grant "type0" the process-getrlimit permission to itself, but
1388        // the security server is configured to be permissive. Because the permission was not
1389        // granted by the policy, the check will be audit logged.
1390        let result = permission_check.has_permission(sid, sid, ProcessPermission::GetRlimit);
1391        assert_eq!(
1392            result,
1393            PermissionCheckResult { granted: false, audit: true, permissive: true, todo_bug: None }
1394        );
1395        assert!(result.permit());
1396
1397        // Test policy is built with "deny unknown" behaviour, and has no "blk_file" class defined.
1398        // This permission should be treated like a defined permission that is not allowed to the
1399        // source, and both allowed and audited here.
1400        let result = permission_check.has_permission(
1401            sid,
1402            sid,
1403            CommonFsNodePermission::GetAttr.for_class(FileClass::BlkFile),
1404        );
1405        assert_eq!(
1406            result,
1407            PermissionCheckResult { granted: false, audit: true, permissive: true, todo_bug: None }
1408        );
1409        assert!(result.permit());
1410    }
1411
1412    #[test]
1413    fn permission_check_enforcing() {
1414        let security_server = security_server_with_tests_policy();
1415        security_server.set_enforcing(true);
1416        assert!(security_server.is_enforcing());
1417
1418        let sid =
1419            security_server.security_context_to_sid("user0:object_r:type0:s0".into()).unwrap();
1420        let local_cache = Default::default();
1421        let permission_check = security_server.as_permission_check(&local_cache);
1422
1423        // Test policy grants "type0" the process-fork permission to itself.
1424        let result = permission_check.has_permission(sid, sid, ProcessPermission::Fork);
1425        assert_eq!(
1426            result,
1427            PermissionCheckResult {
1428                granted: true,
1429                audit: false,
1430                permissive: false,
1431                todo_bug: None
1432            }
1433        );
1434        assert!(result.permit());
1435
1436        // Test policy does not grant "type0" the process-getrlimit permission to itself.
1437        // Permission denials are audit logged in enforcing mode.
1438        let result = permission_check.has_permission(sid, sid, ProcessPermission::GetRlimit);
1439        assert_eq!(
1440            result,
1441            PermissionCheckResult {
1442                granted: false,
1443                audit: true,
1444                permissive: false,
1445                todo_bug: None
1446            }
1447        );
1448        assert!(!result.permit());
1449
1450        // Test policy is built with "deny unknown" behaviour, and has no "blk_file" class defined.
1451        // This permission should therefore be denied, and the denial audited.
1452        let result = permission_check.has_permission(
1453            sid,
1454            sid,
1455            CommonFsNodePermission::GetAttr.for_class(FileClass::BlkFile),
1456        );
1457        assert_eq!(
1458            result,
1459            PermissionCheckResult {
1460                granted: false,
1461                audit: true,
1462                permissive: false,
1463                todo_bug: None
1464            }
1465        );
1466        assert!(!result.permit());
1467    }
1468
1469    #[test]
1470    fn permissive_domain() {
1471        let security_server = security_server_with_tests_policy();
1472        security_server.set_enforcing(true);
1473        assert!(security_server.is_enforcing());
1474
1475        let permissive_sid = security_server
1476            .security_context_to_sid("user0:object_r:permissive_t:s0".into())
1477            .unwrap();
1478        let non_permissive_sid = security_server
1479            .security_context_to_sid("user0:object_r:non_permissive_t:s0".into())
1480            .unwrap();
1481
1482        let local_cache = Default::default();
1483        let permission_check = security_server.as_permission_check(&local_cache);
1484
1485        // Test policy grants process-getsched permission to both of the test domains.
1486        let result = permission_check.has_permission(
1487            permissive_sid,
1488            permissive_sid,
1489            ProcessPermission::GetSched,
1490        );
1491        assert_eq!(
1492            result,
1493            PermissionCheckResult { granted: true, audit: false, permissive: true, todo_bug: None }
1494        );
1495        assert!(result.permit());
1496        let result = permission_check.has_permission(
1497            non_permissive_sid,
1498            non_permissive_sid,
1499            ProcessPermission::GetSched,
1500        );
1501        assert_eq!(
1502            result,
1503            PermissionCheckResult {
1504                granted: true,
1505                audit: false,
1506                permissive: false,
1507                todo_bug: None
1508            }
1509        );
1510        assert!(result.permit());
1511
1512        // Test policy does not grant process-getsched permission to the test domains on one another.
1513        // The permissive domain will be granted the permission, since it is marked permissive.
1514        let result = permission_check.has_permission(
1515            permissive_sid,
1516            non_permissive_sid,
1517            ProcessPermission::GetSched,
1518        );
1519        assert_eq!(
1520            result,
1521            PermissionCheckResult { granted: false, audit: true, permissive: true, todo_bug: None }
1522        );
1523        assert!(result.permit());
1524        let result = permission_check.has_permission(
1525            non_permissive_sid,
1526            permissive_sid,
1527            ProcessPermission::GetSched,
1528        );
1529        assert_eq!(
1530            result,
1531            PermissionCheckResult {
1532                granted: false,
1533                audit: true,
1534                permissive: false,
1535                todo_bug: None
1536            }
1537        );
1538        assert!(!result.permit());
1539
1540        // Test policy has "deny unknown" behaviour and does not define the "blk_file" class, so
1541        // access to a permission on it will depend on whether the source is permissive.
1542        // The target domain is irrelevant, since the class/permission do not exist, so the non-
1543        // permissive SID is used for both checks.
1544        let result = permission_check.has_permission(
1545            permissive_sid,
1546            non_permissive_sid,
1547            CommonFsNodePermission::GetAttr.for_class(FileClass::BlkFile),
1548        );
1549        assert_eq!(
1550            result,
1551            PermissionCheckResult { granted: false, audit: true, permissive: true, todo_bug: None }
1552        );
1553        assert!(result.permit());
1554        let result = permission_check.has_permission(
1555            non_permissive_sid,
1556            non_permissive_sid,
1557            CommonFsNodePermission::GetAttr.for_class(FileClass::BlkFile),
1558        );
1559        assert_eq!(
1560            result,
1561            PermissionCheckResult {
1562                granted: false,
1563                audit: true,
1564                permissive: false,
1565                todo_bug: None
1566            }
1567        );
1568        assert!(!result.permit());
1569    }
1570
1571    #[test]
1572    fn auditallow_and_dontaudit() {
1573        let security_server = security_server_with_tests_policy();
1574        security_server.set_enforcing(true);
1575        assert!(security_server.is_enforcing());
1576
1577        let audit_sid = security_server
1578            .security_context_to_sid("user0:object_r:test_audit_t:s0".into())
1579            .unwrap();
1580
1581        let local_cache = Default::default();
1582        let permission_check = security_server.as_permission_check(&local_cache);
1583
1584        // Test policy grants the domain self-fork permission, and marks it audit-allow.
1585        let result = permission_check.has_permission(audit_sid, audit_sid, ProcessPermission::Fork);
1586        assert_eq!(
1587            result,
1588            PermissionCheckResult { granted: true, audit: true, permissive: false, todo_bug: None }
1589        );
1590        assert!(result.permit());
1591
1592        // Self-setsched permission is granted, and marked dont-audit, which takes no effect.
1593        let result =
1594            permission_check.has_permission(audit_sid, audit_sid, ProcessPermission::SetSched);
1595        assert_eq!(
1596            result,
1597            PermissionCheckResult {
1598                granted: true,
1599                audit: false,
1600                permissive: false,
1601                todo_bug: None
1602            }
1603        );
1604        assert!(result.permit());
1605
1606        // Self-getsched permission is denied, but marked dont-audit.
1607        let result =
1608            permission_check.has_permission(audit_sid, audit_sid, ProcessPermission::GetSched);
1609        assert_eq!(
1610            result,
1611            PermissionCheckResult {
1612                granted: false,
1613                audit: false,
1614                permissive: false,
1615                todo_bug: None
1616            }
1617        );
1618        assert!(!result.permit());
1619
1620        // Self-getpgid permission is denied, with neither audit-allow nor dont-audit.
1621        let result =
1622            permission_check.has_permission(audit_sid, audit_sid, ProcessPermission::GetPgid);
1623        assert_eq!(
1624            result,
1625            PermissionCheckResult {
1626                granted: false,
1627                audit: true,
1628                permissive: false,
1629                todo_bug: None
1630            }
1631        );
1632        assert!(!result.permit());
1633    }
1634
1635    #[test]
1636    fn access_checks_with_exceptions_config() {
1637        const EXCEPTIONS_CONFIG: &[&str] = &[
1638            // These statement should all be resolved.
1639            "todo_deny b/001 test_exception_source_t test_exception_target_t file",
1640            "todo_deny b/002 test_exception_other_t test_exception_target_t chr_file",
1641            "todo_deny b/003 test_exception_source_t test_exception_other_t anon_inode",
1642            "todo_deny b/004 test_exception_permissive_t test_exception_target_t file",
1643            "todo_permissive b/005 test_exception_todo_permissive_t",
1644            // These statements should not be resolved.
1645            "todo_deny b/101 test_undefined_source_t test_exception_target_t file",
1646            "todo_deny b/102 test_exception_source_t test_undefined_target_t file",
1647            "todo_permissive b/103 test_undefined_source_t",
1648        ];
1649        let exceptions_config = EXCEPTIONS_CONFIG.iter().map(|x| String::from(*x)).collect();
1650        let security_server = SecurityServer::new(String::new(), exceptions_config);
1651        security_server.set_enforcing(true);
1652
1653        const EXCEPTIONS_POLICY: &[u8] =
1654            include_bytes!("../testdata/composite_policies/compiled/exceptions_config_policy");
1655        assert!(security_server.load_policy(EXCEPTIONS_POLICY.into()).is_ok());
1656
1657        let source_sid = security_server
1658            .security_context_to_sid("test_exception_u:object_r:test_exception_source_t:s0".into())
1659            .unwrap();
1660        let target_sid = security_server
1661            .security_context_to_sid("test_exception_u:object_r:test_exception_target_t:s0".into())
1662            .unwrap();
1663        let other_sid = security_server
1664            .security_context_to_sid("test_exception_u:object_r:test_exception_other_t:s0".into())
1665            .unwrap();
1666        let permissive_sid = security_server
1667            .security_context_to_sid(
1668                "test_exception_u:object_r:test_exception_permissive_t:s0".into(),
1669            )
1670            .unwrap();
1671        let unmatched_sid = security_server
1672            .security_context_to_sid(
1673                "test_exception_u:object_r:test_exception_unmatched_t:s0".into(),
1674            )
1675            .unwrap();
1676        let todo_permissive_sid = security_server
1677            .security_context_to_sid(
1678                "test_exception_u:object_r:test_exception_todo_permissive_t:s0".into(),
1679            )
1680            .unwrap();
1681
1682        let local_cache = Default::default();
1683        let permission_check = security_server.as_permission_check(&local_cache);
1684
1685        // Source SID has no "process" permissions to target SID, and no exceptions.
1686        let result =
1687            permission_check.has_permission(source_sid, target_sid, ProcessPermission::GetPgid);
1688        assert_eq!(
1689            result,
1690            PermissionCheckResult {
1691                granted: false,
1692                audit: true,
1693                permissive: false,
1694                todo_bug: None
1695            }
1696        );
1697        assert!(!result.permit());
1698
1699        // Source SID has no "file:entrypoint" permission to target SID, but there is an exception defined.
1700        let result =
1701            permission_check.has_permission(source_sid, target_sid, FilePermission::Entrypoint);
1702        assert_eq!(
1703            result,
1704            PermissionCheckResult {
1705                granted: true,
1706                audit: true,
1707                permissive: false,
1708                todo_bug: Some(NonZeroU32::new(1).unwrap())
1709            }
1710        );
1711        assert!(result.permit());
1712
1713        // Source SID has "file:execute_no_trans" permission to target SID.
1714        let result =
1715            permission_check.has_permission(source_sid, target_sid, FilePermission::ExecuteNoTrans);
1716        assert_eq!(
1717            result,
1718            PermissionCheckResult {
1719                granted: true,
1720                audit: false,
1721                permissive: false,
1722                todo_bug: None,
1723            }
1724        );
1725        assert!(result.permit());
1726
1727        // Other SID has no "file:entrypoint" permissions to target SID, and the exception does not match "file" class.
1728        let result =
1729            permission_check.has_permission(other_sid, target_sid, FilePermission::Entrypoint);
1730        assert_eq!(
1731            result,
1732            PermissionCheckResult {
1733                granted: false,
1734                audit: true,
1735                permissive: false,
1736                todo_bug: None
1737            }
1738        );
1739        assert!(!result.permit());
1740
1741        // Other SID has no "chr_file" permissions to target SID, but there is an exception defined.
1742        let result = permission_check.has_permission(
1743            other_sid,
1744            target_sid,
1745            CommonFsNodePermission::Read.for_class(FileClass::ChrFile),
1746        );
1747        assert_eq!(
1748            result,
1749            PermissionCheckResult {
1750                granted: true,
1751                audit: true,
1752                permissive: false,
1753                todo_bug: Some(NonZeroU32::new(2).unwrap())
1754            }
1755        );
1756        assert!(result.permit());
1757
1758        // Source SID has no "file:entrypoint" permissions to unmatched SID, and no exception is defined.
1759        let result =
1760            permission_check.has_permission(source_sid, unmatched_sid, FilePermission::Entrypoint);
1761        assert_eq!(
1762            result,
1763            PermissionCheckResult {
1764                granted: false,
1765                audit: true,
1766                permissive: false,
1767                todo_bug: None
1768            }
1769        );
1770        assert!(!result.permit());
1771
1772        // Unmatched SID has no "file:entrypoint" permissions to target SID, and no exception is defined.
1773        let result =
1774            permission_check.has_permission(unmatched_sid, target_sid, FilePermission::Entrypoint);
1775        assert_eq!(
1776            result,
1777            PermissionCheckResult {
1778                granted: false,
1779                audit: true,
1780                permissive: false,
1781                todo_bug: None
1782            }
1783        );
1784        assert!(!result.permit());
1785
1786        // Todo-deny exceptions are processed before the permissive bit is handled.
1787        let result =
1788            permission_check.has_permission(permissive_sid, target_sid, FilePermission::Entrypoint);
1789        assert_eq!(
1790            result,
1791            PermissionCheckResult {
1792                granted: true,
1793                audit: true,
1794                permissive: true,
1795                todo_bug: Some(NonZeroU32::new(4).unwrap())
1796            }
1797        );
1798        assert!(result.permit());
1799
1800        // Todo-permissive SID is not granted any permissions, so all permissions should be granted,
1801        // to all target domains and classes, and all grants should be associated with the bug.
1802        let result = permission_check.has_permission(
1803            todo_permissive_sid,
1804            target_sid,
1805            FilePermission::Entrypoint,
1806        );
1807        assert_eq!(
1808            result,
1809            PermissionCheckResult {
1810                granted: true,
1811                audit: true,
1812                permissive: false,
1813                todo_bug: Some(NonZeroU32::new(5).unwrap())
1814            }
1815        );
1816        assert!(result.permit());
1817        let result = permission_check.has_permission(
1818            todo_permissive_sid,
1819            todo_permissive_sid,
1820            FilePermission::Entrypoint,
1821        );
1822        assert_eq!(
1823            result,
1824            PermissionCheckResult {
1825                granted: true,
1826                audit: true,
1827                permissive: false,
1828                todo_bug: Some(NonZeroU32::new(5).unwrap())
1829            }
1830        );
1831        assert!(result.permit());
1832        let result = permission_check.has_permission(
1833            todo_permissive_sid,
1834            target_sid,
1835            FilePermission::Entrypoint,
1836        );
1837        assert_eq!(
1838            result,
1839            PermissionCheckResult {
1840                granted: true,
1841                audit: true,
1842                permissive: false,
1843                todo_bug: Some(NonZeroU32::new(5).unwrap())
1844            }
1845        );
1846        assert!(result.permit());
1847    }
1848
1849    #[test]
1850    fn handle_unknown() {
1851        let security_server = security_server_with_tests_policy();
1852
1853        let sid = security_server
1854            .security_context_to_sid("user0:object_r:type0:s0".into())
1855            .expect("Resolve Context to SID");
1856
1857        // Load a policy that is missing some elements, and marked handle_unknown=reject.
1858        // The policy should be rejected, since not all classes/permissions are defined.
1859        // Rejecting policy is not controlled by permissive vs enforcing.
1860        const REJECT_POLICY: &[u8] =
1861            include_bytes!("../testdata/composite_policies/compiled/handle_unknown_policy-reject");
1862        assert!(security_server.load_policy(REJECT_POLICY.to_vec()).is_err());
1863
1864        security_server.set_enforcing(true);
1865
1866        // Load a policy that is missing some elements, and marked handle_unknown=deny.
1867        const DENY_POLICY: &[u8] =
1868            include_bytes!("../testdata/composite_policies/compiled/handle_unknown_policy-deny");
1869        assert!(security_server.load_policy(DENY_POLICY.to_vec()).is_ok());
1870        let local_cache = Default::default();
1871        let permission_check = security_server.as_permission_check(&local_cache);
1872
1873        // Check against undefined classes or permissions should deny access and audit.
1874        let result = permission_check.has_permission(sid, sid, ProcessPermission::GetSched);
1875        assert_eq!(
1876            result,
1877            PermissionCheckResult {
1878                granted: false,
1879                audit: true,
1880                permissive: false,
1881                todo_bug: None
1882            }
1883        );
1884        assert!(!result.permit());
1885        let result = permission_check.has_permission(sid, sid, DirPermission::AddName);
1886        assert_eq!(
1887            result,
1888            PermissionCheckResult {
1889                granted: false,
1890                audit: true,
1891                permissive: false,
1892                todo_bug: None
1893            }
1894        );
1895        assert!(!result.permit());
1896
1897        // Check that permissions that are defined are unaffected by handle-unknown.
1898        let result = permission_check.has_permission(sid, sid, DirPermission::Search);
1899        assert_eq!(
1900            result,
1901            PermissionCheckResult {
1902                granted: true,
1903                audit: false,
1904                permissive: false,
1905                todo_bug: None
1906            }
1907        );
1908        assert!(result.permit());
1909        let result = permission_check.has_permission(sid, sid, DirPermission::Reparent);
1910        assert_eq!(
1911            result,
1912            PermissionCheckResult {
1913                granted: false,
1914                audit: true,
1915                permissive: false,
1916                todo_bug: None
1917            }
1918        );
1919        assert!(!result.permit());
1920
1921        // Load a policy that is missing some elements, and marked handle_unknown=allow.
1922        const ALLOW_POLICY: &[u8] =
1923            include_bytes!("../testdata/composite_policies/compiled/handle_unknown_policy-allow");
1924        assert!(security_server.load_policy(ALLOW_POLICY.to_vec()).is_ok());
1925        let local_cache2 = Default::default();
1926        let permission_check = security_server.as_permission_check(&local_cache2);
1927
1928        // Check against undefined classes or permissions should grant access without audit.
1929        let result = permission_check.has_permission(sid, sid, ProcessPermission::GetSched);
1930        assert_eq!(
1931            result,
1932            PermissionCheckResult {
1933                granted: true,
1934                audit: false,
1935                permissive: false,
1936                todo_bug: None
1937            }
1938        );
1939        assert!(result.permit());
1940        let result = permission_check.has_permission(sid, sid, DirPermission::AddName);
1941        assert_eq!(
1942            result,
1943            PermissionCheckResult {
1944                granted: true,
1945                audit: false,
1946                permissive: false,
1947                todo_bug: None
1948            }
1949        );
1950        assert!(result.permit());
1951
1952        // Check that permissions that are defined are unaffected by handle-unknown.
1953        let result = permission_check.has_permission(sid, sid, DirPermission::Search);
1954        assert_eq!(
1955            result,
1956            PermissionCheckResult {
1957                granted: true,
1958                audit: false,
1959                permissive: false,
1960                todo_bug: None
1961            }
1962        );
1963        assert!(result.permit());
1964
1965        let result = permission_check.has_permission(sid, sid, DirPermission::Reparent);
1966        assert_eq!(
1967            result,
1968            PermissionCheckResult {
1969                granted: false,
1970                audit: true,
1971                permissive: false,
1972                todo_bug: None
1973            }
1974        );
1975        assert!(!result.permit());
1976    }
1977}