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.pp");
790    const MINIMAL_BINARY_POLICY: &[u8] =
791        include_bytes!("../testdata/composite_policies/compiled/minimal_policy.pp");
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.pp").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.pp").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.pp").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.pp").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.pp")
1009                .to_vec();
1010        security_server.load_policy(policy_bytes).expect("binary policy loads");
1011
1012        let source_sid = security_server
1013            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s1:c0".into())
1014            .expect("creating SID from security context should succeed");
1015        let target_sid = security_server
1016            .security_context_to_sid(b"file_u:object_r:file_t:s1".into())
1017            .expect("creating SID from security context should succeed");
1018
1019        let computed_sid = security_server
1020            .as_permission_check(&Default::default())
1021            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
1022            .expect("new sid computed");
1023        let computed_context = security_server
1024            .sid_to_security_context(computed_sid)
1025            .expect("computed sid associated with context");
1026
1027        // User and full security range copied from source, role and type as default.
1028        assert_eq!(computed_context, b"user_u:object_r:file_t:s0-s1:c0");
1029    }
1030
1031    #[test]
1032    fn compute_new_fs_node_sid_range_source_high_default() {
1033        let security_server = SecurityServer::new_default();
1034        let policy_bytes =
1035            include_bytes!("../testdata/micro_policies/file_range_source_high_policy.pp").to_vec();
1036        security_server.load_policy(policy_bytes).expect("binary policy loads");
1037
1038        let source_sid = security_server
1039            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s0-s1:c0".into())
1040            .expect("creating SID from security context should succeed");
1041        let target_sid = security_server
1042            .security_context_to_sid(b"file_u:object_r:file_t:s0".into())
1043            .expect("creating SID from security context should succeed");
1044
1045        let computed_sid = security_server
1046            .as_permission_check(&Default::default())
1047            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
1048            .expect("new sid computed");
1049        let computed_context = security_server
1050            .sid_to_security_context(computed_sid)
1051            .expect("computed sid associated with context");
1052
1053        // User and high security level copied from source, role and type as default.
1054        assert_eq!(computed_context, b"user_u:object_r:file_t:s1:c0");
1055    }
1056
1057    #[test]
1058    fn compute_new_fs_node_sid_range_target_low_default() {
1059        let security_server = SecurityServer::new_default();
1060        let policy_bytes =
1061            include_bytes!("../testdata/micro_policies/file_range_target_low_policy.pp").to_vec();
1062        security_server.load_policy(policy_bytes).expect("binary policy loads");
1063
1064        let source_sid = security_server
1065            .security_context_to_sid(b"user_u:unconfined_r:unconfined_t:s1".into())
1066            .expect("creating SID from security context should succeed");
1067        let target_sid = security_server
1068            .security_context_to_sid(b"file_u:object_r:file_t:s0-s1:c0".into())
1069            .expect("creating SID from security context should succeed");
1070
1071        let computed_sid = security_server
1072            .as_permission_check(&Default::default())
1073            .compute_new_fs_node_sid(source_sid, target_sid, FileClass::File.into(), "".into())
1074            .expect("new sid computed");
1075        let computed_context = security_server
1076            .sid_to_security_context(computed_sid)
1077            .expect("computed sid associated with context");
1078
1079        // User copied from source, low security level from target, role and type as default.
1080        assert_eq!(computed_context, b"user_u:object_r:file_t:s0");
1081    }
1082
1083    #[test]
1084    fn compute_new_fs_node_sid_range_target_low_high_default() {
1085        let security_server = SecurityServer::new_default();
1086        let policy_bytes =
1087            include_bytes!("../testdata/micro_policies/file_range_target_low_high_policy.pp")
1088                .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.pp").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.pp")
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.pp").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.pp"
1244        )
1245        .to_vec();
1246        let with_additional_domain_policy_bytes = include_bytes!(
1247            "../testdata/composite_policies/compiled/with_additional_domain_policy.pp"
1248        )
1249        .to_vec();
1250        let allowed_type_context = b"source_u:object_r:allowed_t:s0:c0";
1251        let additional_type_context = b"source_u:object_r:additional_t:s0:c0";
1252
1253        let security_server = SecurityServer::new_default();
1254        security_server.set_enforcing(true);
1255
1256        // Load a policy, get a SID for a context that is valid for that policy, and verify
1257        // that a context that is not valid for that policy is not issued a SID.
1258        assert_eq!(
1259            Ok(()),
1260            security_server
1261                .load_policy(with_unlabeled_access_domain_policy_bytes.clone())
1262                .map_err(|e| format!("{:?}", e))
1263        );
1264        let allowed_type_sid =
1265            security_server.security_context_to_sid(allowed_type_context.into()).unwrap();
1266        assert!(security_server.security_context_to_sid(additional_type_context.into()).is_err());
1267
1268        // Load the policy that makes the second context valid, and verify that it is valid, and
1269        // verify that the first context remains valid (and unchanged).
1270        assert_eq!(
1271            Ok(()),
1272            security_server
1273                .load_policy(with_additional_domain_policy_bytes.clone())
1274                .map_err(|e| format!("{:?}", e))
1275        );
1276        let additional_type_sid =
1277            security_server.security_context_to_sid(additional_type_context.into()).unwrap();
1278        assert_eq!(
1279            allowed_type_sid,
1280            security_server.security_context_to_sid(allowed_type_context.into()).unwrap()
1281        );
1282
1283        let local_cache = Default::default();
1284        let permission_check = security_server.as_permission_check(&local_cache);
1285
1286        // "allowed_t" is allowed the process getsched capability to "unlabeled_t" - but since
1287        // the currently-loaded policy defines "additional_t", the SID for "additional_t" does
1288        // not get treated as effectively unlabeled, and these permission checks are denied.
1289        assert!(
1290            !permission_check
1291                .has_permission(additional_type_sid, allowed_type_sid, ProcessPermission::GetSched)
1292                .granted
1293        );
1294        assert!(
1295            !permission_check
1296                .has_permission(additional_type_sid, allowed_type_sid, ProcessPermission::SetSched)
1297                .granted
1298        );
1299        assert!(
1300            !permission_check
1301                .has_permission(allowed_type_sid, additional_type_sid, ProcessPermission::GetSched)
1302                .granted
1303        );
1304        assert!(
1305            !permission_check
1306                .has_permission(allowed_type_sid, additional_type_sid, ProcessPermission::SetSched)
1307                .granted
1308        );
1309
1310        // We now flip back to the policy that does not recognize "additional_t"...
1311        assert_eq!(
1312            Ok(()),
1313            security_server
1314                .load_policy(with_unlabeled_access_domain_policy_bytes)
1315                .map_err(|e| format!("{:?}", e))
1316        );
1317
1318        // Reuse the cache to check invalidation.
1319        let permission_check = security_server.as_permission_check(&local_cache);
1320
1321        // The now-loaded policy allows "allowed_t" the process getsched capability
1322        // to "unlabeled_t" and since the now-loaded policy does not recognize "additional_t",
1323        // "allowed_t" is now allowed the process getsched capability to "additional_t".
1324        assert!(
1325            permission_check
1326                .has_permission(allowed_type_sid, additional_type_sid, ProcessPermission::GetSched)
1327                .granted
1328        );
1329        assert!(
1330            !permission_check
1331                .has_permission(allowed_type_sid, additional_type_sid, ProcessPermission::SetSched)
1332                .granted
1333        );
1334
1335        // ... and the now-loaded policy also allows "unlabeled_t" the process
1336        // setsched capability to "allowed_t" and since the now-loaded policy does not recognize
1337        // "additional_t", "unlabeled_t" is now allowed the process setsched capability to
1338        // "allowed_t".
1339        assert!(
1340            !permission_check
1341                .has_permission(additional_type_sid, allowed_type_sid, ProcessPermission::GetSched)
1342                .granted
1343        );
1344        assert!(
1345            permission_check
1346                .has_permission(additional_type_sid, allowed_type_sid, ProcessPermission::SetSched)
1347                .granted
1348        );
1349
1350        // We also verify that we do not get a serialization for unrecognized "additional_t"...
1351        assert!(security_server.sid_to_security_context(additional_type_sid).is_none());
1352
1353        // ... but if we flip forward to the policy that recognizes "additional_t", then we see
1354        // the serialization succeed and return the original context string.
1355        assert_eq!(
1356            Ok(()),
1357            security_server
1358                .load_policy(with_additional_domain_policy_bytes)
1359                .map_err(|e| format!("{:?}", e))
1360        );
1361        assert_eq!(
1362            additional_type_context.to_vec(),
1363            security_server.sid_to_security_context(additional_type_sid).unwrap()
1364        );
1365    }
1366
1367    #[test]
1368    fn permission_check_permissive() {
1369        let security_server = security_server_with_tests_policy();
1370        security_server.set_enforcing(false);
1371        assert!(!security_server.is_enforcing());
1372
1373        let sid =
1374            security_server.security_context_to_sid("user0:object_r:type0:s0".into()).unwrap();
1375        let local_cache = Default::default();
1376        let permission_check = security_server.as_permission_check(&local_cache);
1377
1378        // Test policy grants "type0" the process-fork permission to itself.
1379        // Since the permission is granted by policy, the check will not be audit logged.
1380        assert_eq!(
1381            permission_check.has_permission(sid, sid, ProcessPermission::Fork),
1382            PermissionCheckResult {
1383                granted: true,
1384                audit: false,
1385                permissive: false,
1386                todo_bug: None
1387            }
1388        );
1389
1390        // Test policy does not grant "type0" the process-getrlimit permission to itself, but
1391        // the security server is configured to be permissive. Because the permission was not
1392        // granted by the policy, the check will be audit logged.
1393        let result = permission_check.has_permission(sid, sid, ProcessPermission::GetRlimit);
1394        assert_eq!(
1395            result,
1396            PermissionCheckResult { granted: false, audit: true, permissive: true, todo_bug: None }
1397        );
1398        assert!(result.permit());
1399
1400        // Test policy is built with "deny unknown" behaviour, and has no "blk_file" class defined.
1401        // This permission should be treated like a defined permission that is not allowed to the
1402        // source, and both allowed and audited here.
1403        let result = permission_check.has_permission(
1404            sid,
1405            sid,
1406            CommonFsNodePermission::GetAttr.for_class(FileClass::BlkFile),
1407        );
1408        assert_eq!(
1409            result,
1410            PermissionCheckResult { granted: false, audit: true, permissive: true, todo_bug: None }
1411        );
1412        assert!(result.permit());
1413    }
1414
1415    #[test]
1416    fn permission_check_enforcing() {
1417        let security_server = security_server_with_tests_policy();
1418        security_server.set_enforcing(true);
1419        assert!(security_server.is_enforcing());
1420
1421        let sid =
1422            security_server.security_context_to_sid("user0:object_r:type0:s0".into()).unwrap();
1423        let local_cache = Default::default();
1424        let permission_check = security_server.as_permission_check(&local_cache);
1425
1426        // Test policy grants "type0" the process-fork permission to itself.
1427        let result = permission_check.has_permission(sid, sid, ProcessPermission::Fork);
1428        assert_eq!(
1429            result,
1430            PermissionCheckResult {
1431                granted: true,
1432                audit: false,
1433                permissive: false,
1434                todo_bug: None
1435            }
1436        );
1437        assert!(result.permit());
1438
1439        // Test policy does not grant "type0" the process-getrlimit permission to itself.
1440        // Permission denials are audit logged in enforcing mode.
1441        let result = permission_check.has_permission(sid, sid, ProcessPermission::GetRlimit);
1442        assert_eq!(
1443            result,
1444            PermissionCheckResult {
1445                granted: false,
1446                audit: true,
1447                permissive: false,
1448                todo_bug: None
1449            }
1450        );
1451        assert!(!result.permit());
1452
1453        // Test policy is built with "deny unknown" behaviour, and has no "blk_file" class defined.
1454        // This permission should therefore be denied, and the denial audited.
1455        let result = permission_check.has_permission(
1456            sid,
1457            sid,
1458            CommonFsNodePermission::GetAttr.for_class(FileClass::BlkFile),
1459        );
1460        assert_eq!(
1461            result,
1462            PermissionCheckResult {
1463                granted: false,
1464                audit: true,
1465                permissive: false,
1466                todo_bug: None
1467            }
1468        );
1469        assert!(!result.permit());
1470    }
1471
1472    #[test]
1473    fn permissive_domain() {
1474        let security_server = security_server_with_tests_policy();
1475        security_server.set_enforcing(true);
1476        assert!(security_server.is_enforcing());
1477
1478        let permissive_sid = security_server
1479            .security_context_to_sid("user0:object_r:permissive_t:s0".into())
1480            .unwrap();
1481        let non_permissive_sid = security_server
1482            .security_context_to_sid("user0:object_r:non_permissive_t:s0".into())
1483            .unwrap();
1484
1485        let local_cache = Default::default();
1486        let permission_check = security_server.as_permission_check(&local_cache);
1487
1488        // Test policy grants process-getsched permission to both of the test domains.
1489        let result = permission_check.has_permission(
1490            permissive_sid,
1491            permissive_sid,
1492            ProcessPermission::GetSched,
1493        );
1494        assert_eq!(
1495            result,
1496            PermissionCheckResult { granted: true, audit: false, permissive: true, todo_bug: None }
1497        );
1498        assert!(result.permit());
1499        let result = permission_check.has_permission(
1500            non_permissive_sid,
1501            non_permissive_sid,
1502            ProcessPermission::GetSched,
1503        );
1504        assert_eq!(
1505            result,
1506            PermissionCheckResult {
1507                granted: true,
1508                audit: false,
1509                permissive: false,
1510                todo_bug: None
1511            }
1512        );
1513        assert!(result.permit());
1514
1515        // Test policy does not grant process-getsched permission to the test domains on one another.
1516        // The permissive domain will be granted the permission, since it is marked permissive.
1517        let result = permission_check.has_permission(
1518            permissive_sid,
1519            non_permissive_sid,
1520            ProcessPermission::GetSched,
1521        );
1522        assert_eq!(
1523            result,
1524            PermissionCheckResult { granted: false, audit: true, permissive: true, todo_bug: None }
1525        );
1526        assert!(result.permit());
1527        let result = permission_check.has_permission(
1528            non_permissive_sid,
1529            permissive_sid,
1530            ProcessPermission::GetSched,
1531        );
1532        assert_eq!(
1533            result,
1534            PermissionCheckResult {
1535                granted: false,
1536                audit: true,
1537                permissive: false,
1538                todo_bug: None
1539            }
1540        );
1541        assert!(!result.permit());
1542
1543        // Test policy has "deny unknown" behaviour and does not define the "blk_file" class, so
1544        // access to a permission on it will depend on whether the source is permissive.
1545        // The target domain is irrelevant, since the class/permission do not exist, so the non-
1546        // permissive SID is used for both checks.
1547        let result = permission_check.has_permission(
1548            permissive_sid,
1549            non_permissive_sid,
1550            CommonFsNodePermission::GetAttr.for_class(FileClass::BlkFile),
1551        );
1552        assert_eq!(
1553            result,
1554            PermissionCheckResult { granted: false, audit: true, permissive: true, todo_bug: None }
1555        );
1556        assert!(result.permit());
1557        let result = permission_check.has_permission(
1558            non_permissive_sid,
1559            non_permissive_sid,
1560            CommonFsNodePermission::GetAttr.for_class(FileClass::BlkFile),
1561        );
1562        assert_eq!(
1563            result,
1564            PermissionCheckResult {
1565                granted: false,
1566                audit: true,
1567                permissive: false,
1568                todo_bug: None
1569            }
1570        );
1571        assert!(!result.permit());
1572    }
1573
1574    #[test]
1575    fn auditallow_and_dontaudit() {
1576        let security_server = security_server_with_tests_policy();
1577        security_server.set_enforcing(true);
1578        assert!(security_server.is_enforcing());
1579
1580        let audit_sid = security_server
1581            .security_context_to_sid("user0:object_r:test_audit_t:s0".into())
1582            .unwrap();
1583
1584        let local_cache = Default::default();
1585        let permission_check = security_server.as_permission_check(&local_cache);
1586
1587        // Test policy grants the domain self-fork permission, and marks it audit-allow.
1588        let result = permission_check.has_permission(audit_sid, audit_sid, ProcessPermission::Fork);
1589        assert_eq!(
1590            result,
1591            PermissionCheckResult { granted: true, audit: true, permissive: false, todo_bug: None }
1592        );
1593        assert!(result.permit());
1594
1595        // Self-setsched permission is granted, and marked dont-audit, which takes no effect.
1596        let result =
1597            permission_check.has_permission(audit_sid, audit_sid, ProcessPermission::SetSched);
1598        assert_eq!(
1599            result,
1600            PermissionCheckResult {
1601                granted: true,
1602                audit: false,
1603                permissive: false,
1604                todo_bug: None
1605            }
1606        );
1607        assert!(result.permit());
1608
1609        // Self-getsched permission is denied, but marked dont-audit.
1610        let result =
1611            permission_check.has_permission(audit_sid, audit_sid, ProcessPermission::GetSched);
1612        assert_eq!(
1613            result,
1614            PermissionCheckResult {
1615                granted: false,
1616                audit: false,
1617                permissive: false,
1618                todo_bug: None
1619            }
1620        );
1621        assert!(!result.permit());
1622
1623        // Self-getpgid permission is denied, with neither audit-allow nor dont-audit.
1624        let result =
1625            permission_check.has_permission(audit_sid, audit_sid, ProcessPermission::GetPgid);
1626        assert_eq!(
1627            result,
1628            PermissionCheckResult {
1629                granted: false,
1630                audit: true,
1631                permissive: false,
1632                todo_bug: None
1633            }
1634        );
1635        assert!(!result.permit());
1636    }
1637
1638    #[test]
1639    fn access_checks_with_exceptions_config() {
1640        const EXCEPTIONS_CONFIG: &[&str] = &[
1641            // These statement should all be resolved.
1642            "todo_deny b/001 test_exception_source_t test_exception_target_t file",
1643            "todo_deny b/002 test_exception_other_t test_exception_target_t chr_file",
1644            "todo_deny b/003 test_exception_source_t test_exception_other_t anon_inode",
1645            "todo_deny b/004 test_exception_permissive_t test_exception_target_t file",
1646            "todo_permissive b/005 test_exception_todo_permissive_t",
1647            // These statements should not be resolved.
1648            "todo_deny b/101 test_undefined_source_t test_exception_target_t file",
1649            "todo_deny b/102 test_exception_source_t test_undefined_target_t file",
1650            "todo_permissive b/103 test_undefined_source_t",
1651        ];
1652        let exceptions_config = EXCEPTIONS_CONFIG.iter().map(|x| String::from(*x)).collect();
1653        let security_server = SecurityServer::new(String::new(), exceptions_config);
1654        security_server.set_enforcing(true);
1655
1656        const EXCEPTIONS_POLICY: &[u8] =
1657            include_bytes!("../testdata/composite_policies/compiled/exceptions_config_policy.pp");
1658        assert!(security_server.load_policy(EXCEPTIONS_POLICY.into()).is_ok());
1659
1660        let source_sid = security_server
1661            .security_context_to_sid("test_exception_u:object_r:test_exception_source_t:s0".into())
1662            .unwrap();
1663        let target_sid = security_server
1664            .security_context_to_sid("test_exception_u:object_r:test_exception_target_t:s0".into())
1665            .unwrap();
1666        let other_sid = security_server
1667            .security_context_to_sid("test_exception_u:object_r:test_exception_other_t:s0".into())
1668            .unwrap();
1669        let permissive_sid = security_server
1670            .security_context_to_sid(
1671                "test_exception_u:object_r:test_exception_permissive_t:s0".into(),
1672            )
1673            .unwrap();
1674        let unmatched_sid = security_server
1675            .security_context_to_sid(
1676                "test_exception_u:object_r:test_exception_unmatched_t:s0".into(),
1677            )
1678            .unwrap();
1679        let todo_permissive_sid = security_server
1680            .security_context_to_sid(
1681                "test_exception_u:object_r:test_exception_todo_permissive_t:s0".into(),
1682            )
1683            .unwrap();
1684
1685        let local_cache = Default::default();
1686        let permission_check = security_server.as_permission_check(&local_cache);
1687
1688        // Source SID has no "process" permissions to target SID, and no exceptions.
1689        let result =
1690            permission_check.has_permission(source_sid, target_sid, ProcessPermission::GetPgid);
1691        assert_eq!(
1692            result,
1693            PermissionCheckResult {
1694                granted: false,
1695                audit: true,
1696                permissive: false,
1697                todo_bug: None
1698            }
1699        );
1700        assert!(!result.permit());
1701
1702        // Source SID has no "file:entrypoint" permission to target SID, but there is an exception defined.
1703        let result =
1704            permission_check.has_permission(source_sid, target_sid, FilePermission::Entrypoint);
1705        assert_eq!(
1706            result,
1707            PermissionCheckResult {
1708                granted: true,
1709                audit: true,
1710                permissive: false,
1711                todo_bug: Some(NonZeroU32::new(1).unwrap())
1712            }
1713        );
1714        assert!(result.permit());
1715
1716        // Source SID has "file:execute_no_trans" permission to target SID.
1717        let result =
1718            permission_check.has_permission(source_sid, target_sid, FilePermission::ExecuteNoTrans);
1719        assert_eq!(
1720            result,
1721            PermissionCheckResult {
1722                granted: true,
1723                audit: false,
1724                permissive: false,
1725                todo_bug: None,
1726            }
1727        );
1728        assert!(result.permit());
1729
1730        // Other SID has no "file:entrypoint" permissions to target SID, and the exception does not match "file" class.
1731        let result =
1732            permission_check.has_permission(other_sid, target_sid, FilePermission::Entrypoint);
1733        assert_eq!(
1734            result,
1735            PermissionCheckResult {
1736                granted: false,
1737                audit: true,
1738                permissive: false,
1739                todo_bug: None
1740            }
1741        );
1742        assert!(!result.permit());
1743
1744        // Other SID has no "chr_file" permissions to target SID, but there is an exception defined.
1745        let result = permission_check.has_permission(
1746            other_sid,
1747            target_sid,
1748            CommonFsNodePermission::Read.for_class(FileClass::ChrFile),
1749        );
1750        assert_eq!(
1751            result,
1752            PermissionCheckResult {
1753                granted: true,
1754                audit: true,
1755                permissive: false,
1756                todo_bug: Some(NonZeroU32::new(2).unwrap())
1757            }
1758        );
1759        assert!(result.permit());
1760
1761        // Source SID has no "file:entrypoint" permissions to unmatched SID, and no exception is defined.
1762        let result =
1763            permission_check.has_permission(source_sid, unmatched_sid, FilePermission::Entrypoint);
1764        assert_eq!(
1765            result,
1766            PermissionCheckResult {
1767                granted: false,
1768                audit: true,
1769                permissive: false,
1770                todo_bug: None
1771            }
1772        );
1773        assert!(!result.permit());
1774
1775        // Unmatched SID has no "file:entrypoint" permissions to target SID, and no exception is defined.
1776        let result =
1777            permission_check.has_permission(unmatched_sid, target_sid, FilePermission::Entrypoint);
1778        assert_eq!(
1779            result,
1780            PermissionCheckResult {
1781                granted: false,
1782                audit: true,
1783                permissive: false,
1784                todo_bug: None
1785            }
1786        );
1787        assert!(!result.permit());
1788
1789        // Todo-deny exceptions are processed before the permissive bit is handled.
1790        let result =
1791            permission_check.has_permission(permissive_sid, target_sid, FilePermission::Entrypoint);
1792        assert_eq!(
1793            result,
1794            PermissionCheckResult {
1795                granted: true,
1796                audit: true,
1797                permissive: true,
1798                todo_bug: Some(NonZeroU32::new(4).unwrap())
1799            }
1800        );
1801        assert!(result.permit());
1802
1803        // Todo-permissive SID is not granted any permissions, so all permissions should be granted,
1804        // to all target domains and classes, and all grants should be associated with the bug.
1805        let result = permission_check.has_permission(
1806            todo_permissive_sid,
1807            target_sid,
1808            FilePermission::Entrypoint,
1809        );
1810        assert_eq!(
1811            result,
1812            PermissionCheckResult {
1813                granted: true,
1814                audit: true,
1815                permissive: false,
1816                todo_bug: Some(NonZeroU32::new(5).unwrap())
1817            }
1818        );
1819        assert!(result.permit());
1820        let result = permission_check.has_permission(
1821            todo_permissive_sid,
1822            todo_permissive_sid,
1823            FilePermission::Entrypoint,
1824        );
1825        assert_eq!(
1826            result,
1827            PermissionCheckResult {
1828                granted: true,
1829                audit: true,
1830                permissive: false,
1831                todo_bug: Some(NonZeroU32::new(5).unwrap())
1832            }
1833        );
1834        assert!(result.permit());
1835        let result = permission_check.has_permission(
1836            todo_permissive_sid,
1837            target_sid,
1838            FilePermission::Entrypoint,
1839        );
1840        assert_eq!(
1841            result,
1842            PermissionCheckResult {
1843                granted: true,
1844                audit: true,
1845                permissive: false,
1846                todo_bug: Some(NonZeroU32::new(5).unwrap())
1847            }
1848        );
1849        assert!(result.permit());
1850    }
1851
1852    #[test]
1853    fn handle_unknown() {
1854        let security_server = security_server_with_tests_policy();
1855
1856        let sid = security_server
1857            .security_context_to_sid("user0:object_r:type0:s0".into())
1858            .expect("Resolve Context to SID");
1859
1860        // Load a policy that is missing some elements, and marked handle_unknown=reject.
1861        // The policy should be rejected, since not all classes/permissions are defined.
1862        // Rejecting policy is not controlled by permissive vs enforcing.
1863        const REJECT_POLICY: &[u8] = include_bytes!(
1864            "../testdata/composite_policies/compiled/handle_unknown_policy-reject.pp"
1865        );
1866        assert!(security_server.load_policy(REJECT_POLICY.to_vec()).is_err());
1867
1868        security_server.set_enforcing(true);
1869
1870        // Load a policy that is missing some elements, and marked handle_unknown=deny.
1871        const DENY_POLICY: &[u8] =
1872            include_bytes!("../testdata/composite_policies/compiled/handle_unknown_policy-deny.pp");
1873        assert!(security_server.load_policy(DENY_POLICY.to_vec()).is_ok());
1874        let local_cache = Default::default();
1875        let permission_check = security_server.as_permission_check(&local_cache);
1876
1877        // Check against undefined classes or permissions should deny access and audit.
1878        let result = permission_check.has_permission(sid, sid, ProcessPermission::GetSched);
1879        assert_eq!(
1880            result,
1881            PermissionCheckResult {
1882                granted: false,
1883                audit: true,
1884                permissive: false,
1885                todo_bug: None
1886            }
1887        );
1888        assert!(!result.permit());
1889        let result = permission_check.has_permission(sid, sid, DirPermission::AddName);
1890        assert_eq!(
1891            result,
1892            PermissionCheckResult {
1893                granted: false,
1894                audit: true,
1895                permissive: false,
1896                todo_bug: None
1897            }
1898        );
1899        assert!(!result.permit());
1900
1901        // Check that permissions that are defined are unaffected by handle-unknown.
1902        let result = permission_check.has_permission(sid, sid, DirPermission::Search);
1903        assert_eq!(
1904            result,
1905            PermissionCheckResult {
1906                granted: true,
1907                audit: false,
1908                permissive: false,
1909                todo_bug: None
1910            }
1911        );
1912        assert!(result.permit());
1913        let result = permission_check.has_permission(sid, sid, DirPermission::Reparent);
1914        assert_eq!(
1915            result,
1916            PermissionCheckResult {
1917                granted: false,
1918                audit: true,
1919                permissive: false,
1920                todo_bug: None
1921            }
1922        );
1923        assert!(!result.permit());
1924
1925        // Load a policy that is missing some elements, and marked handle_unknown=allow.
1926        const ALLOW_POLICY: &[u8] = include_bytes!(
1927            "../testdata/composite_policies/compiled/handle_unknown_policy-allow.pp"
1928        );
1929        assert!(security_server.load_policy(ALLOW_POLICY.to_vec()).is_ok());
1930        let local_cache2 = Default::default();
1931        let permission_check = security_server.as_permission_check(&local_cache2);
1932
1933        // Check against undefined classes or permissions should grant access without audit.
1934        let result = permission_check.has_permission(sid, sid, ProcessPermission::GetSched);
1935        assert_eq!(
1936            result,
1937            PermissionCheckResult {
1938                granted: true,
1939                audit: false,
1940                permissive: false,
1941                todo_bug: None
1942            }
1943        );
1944        assert!(result.permit());
1945        let result = permission_check.has_permission(sid, sid, DirPermission::AddName);
1946        assert_eq!(
1947            result,
1948            PermissionCheckResult {
1949                granted: true,
1950                audit: false,
1951                permissive: false,
1952                todo_bug: None
1953            }
1954        );
1955        assert!(result.permit());
1956
1957        // Check that permissions that are defined are unaffected by handle-unknown.
1958        let result = permission_check.has_permission(sid, sid, DirPermission::Search);
1959        assert_eq!(
1960            result,
1961            PermissionCheckResult {
1962                granted: true,
1963                audit: false,
1964                permissive: false,
1965                todo_bug: None
1966            }
1967        );
1968        assert!(result.permit());
1969
1970        let result = permission_check.has_permission(sid, sid, DirPermission::Reparent);
1971        assert_eq!(
1972            result,
1973            PermissionCheckResult {
1974                granted: false,
1975                audit: true,
1976                permissive: false,
1977                todo_bug: None
1978            }
1979        );
1980        assert!(!result.permit());
1981    }
1982}