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