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