Skip to main content

selinux/
security_server.rs

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