Skip to main content

selinux/
security_server.rs

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