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