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