1#![allow(non_upper_case_globals)]
7
8pub(super) mod audit;
9pub(super) mod binder;
10pub(super) mod bpf;
11pub(super) mod file;
12pub(super) mod fs_node;
13pub(super) mod netlink_socket;
14pub(super) mod perf_event;
15pub(super) mod selinuxfs;
16pub(super) mod socket;
17pub(super) mod superblock;
18pub(super) mod task;
19pub(super) mod testing;
20
21use super::{PermissionFlags, TaskState};
22use crate::task::{CurrentTask, FullCredentials};
23use crate::vfs::{
24 Anon, DirEntry, FileHandle, FileObject, FileSystem, FileSystemOps, FsNode, OutputBuffer,
25};
26use audit::{Auditable, audit_decision, audit_todo_decision};
27use indexmap::IndexSet;
28use selinux::permission_check::PermissionCheck;
29use selinux::policy::{FsUseType, XpermsKind};
30use selinux::{
31 ClassPermission, CommonFilePermission, CommonFsNodePermission, DirPermission, FdPermission,
32 FileClass, FileSystemLabel, FileSystemLabelingScheme, FileSystemMountOptions, ForClass,
33 FsNodeClass, InitialSid, KernelPermission, PolicyCap, ProcessPermission, SecurityId,
34 SecurityServer,
35};
36use smallvec;
37use starnix_logging::{BugRef, CATEGORY_STARNIX_SECURITY, bug_ref, trace_duration, track_stub};
38use starnix_sync::{Mutex, MutexGuard};
39use starnix_uapi::arc_key::WeakKey;
40use starnix_uapi::error;
41use starnix_uapi::errors::Errno;
42use starnix_uapi::file_mode::FileMode;
43use std::cell::Ref;
44use std::ops::Deref;
45use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
46use std::sync::{Arc, OnceLock};
47
48const NO_PERMISSIONS: &[KernelPermission] = &[];
51
52type PermissionFlagsVec = smallvec::SmallVec<[KernelPermission; 3]>;
54
55fn permissions_from_flags(flags: PermissionFlags, class: FsNodeClass) -> PermissionFlagsVec {
57 let mut result = PermissionFlagsVec::new();
58
59 if flags.contains(PermissionFlags::READ) {
60 result.push(CommonFsNodePermission::Read.for_class(class));
61 }
62 if flags.contains(PermissionFlags::WRITE) {
63 if flags.contains(PermissionFlags::APPEND) {
66 result.push(CommonFsNodePermission::Append.for_class(class));
67 } else {
68 result.push(CommonFsNodePermission::Write.for_class(class));
69 }
70 }
71
72 if let FsNodeClass::File(class) = class {
73 if flags.contains(PermissionFlags::EXEC) {
74 if class == FileClass::Dir {
75 result.push(DirPermission::Search.into());
76 } else {
77 result.push(CommonFilePermission::Execute.for_class(class));
78 }
79 }
80 }
81 result
82}
83
84fn is_internal_operation(current_task: &CurrentTask) -> bool {
85 current_task_state(current_task).lock().internal_operation
86}
87
88fn has_file_permissions(
91 permission_check: &PermissionCheck<'_>,
92 current_task: &CurrentTask,
93 subject_sid: SecurityId,
94 file: &FileObject,
95 permissions: &[impl ForClass<FsNodeClass>],
96 audit_context: Auditable<'_>,
97) -> Result<(), Errno> {
98 if is_internal_operation(current_task) {
99 return Ok(());
100 };
101 let file_sid = file.security_state.state.sid;
104 if subject_sid != file_sid {
105 let node = file.node().as_ref().as_ref();
106 let audit_context = [audit_context, file.into(), node.into()];
107 check_permission(
108 permission_check,
109 current_task,
110 subject_sid,
111 file_sid,
112 FdPermission::Use,
113 (&audit_context).into(),
114 )?;
115 }
116
117 if !permissions.is_empty() {
119 let audit_context = [audit_context, file.into()];
120 has_fs_node_permissions(
121 permission_check,
122 current_task,
123 subject_sid,
124 file.node(),
125 permissions,
126 (&audit_context).into(),
127 )?;
128 }
129
130 Ok(())
131}
132
133fn has_file_ioctl_permission(
134 permission_check: &PermissionCheck<'_>,
135 current_task: &CurrentTask,
136 subject_sid: SecurityId,
137 file: &FileObject,
138 ioctl: u16,
139 audit_context: Auditable<'_>,
140) -> Result<(), Errno> {
141 has_file_permissions(
143 permission_check,
144 current_task,
145 subject_sid,
146 file,
147 NO_PERMISSIONS,
148 audit_context,
149 )?;
150
151 let fs_node = file.node().as_ref().as_ref();
154 if Anon::is_private(fs_node) {
155 return Ok(());
156 }
157 let FsNodeSidAndClass { sid: target_sid, class: target_class } =
158 fs_node_effective_sid_and_class(fs_node);
159
160 let audit_context =
161 &[audit_context, file.into(), fs_node.into(), Auditable::IoctlCommand(ioctl)];
162
163 check_permission_and_xperms(
165 permission_check,
166 current_task,
167 subject_sid,
168 target_sid,
169 CommonFsNodePermission::Ioctl.for_class(target_class),
170 XpermsKind::Ioctl,
171 ioctl,
172 audit_context.into(),
173 )
174}
175
176fn check_permission_and_xperms(
177 permission_check: &PermissionCheck<'_>,
178 current_task: &CurrentTask,
179 subject_sid: SecurityId,
180 target_sid: SecurityId,
181 permission: KernelPermission,
182 xperms_kind: XpermsKind,
183 xperm: u16,
184 audit_context: Auditable<'_>,
185) -> Result<(), Errno> {
186 if is_internal_operation(current_task) {
187 return Ok(());
188 }
189 let result = permission_check.has_extended_permission(
190 xperms_kind,
191 subject_sid,
192 target_sid,
193 permission.clone(),
194 xperm,
195 );
196
197 if result.audit {
198 if !result.permit {
199 current_task
200 .kernel()
201 .security_state
202 .state
203 .as_ref()
204 .unwrap()
205 .access_denial_count
206 .fetch_add(1, Ordering::Release);
207 }
208
209 audit_decision(
210 current_task,
211 permission_check,
212 result.clone(),
213 subject_sid,
214 target_sid,
215 permission.into(),
216 audit_context.into(),
217 );
218 }
219
220 result.permit.then_some(Ok(())).unwrap_or_else(|| error!(EACCES))
221}
222
223fn has_fs_node_permissions_dontaudit(
225 permission_check: &PermissionCheck<'_>,
226 _current_task: &CurrentTask,
227 subject_sid: SecurityId,
228 fs_node: &FsNode,
229 permissions: &[impl ForClass<FsNodeClass>],
230) -> Result<(), Errno> {
231 trace_duration!(
232 CATEGORY_STARNIX_SECURITY,
233 "security.selinux.has_fs_node_permissions_dontaudit"
234 );
235
236 if Anon::is_private(fs_node) {
237 return Ok(());
238 }
239
240 let target = fs_node_effective_sid_and_class(fs_node);
241 for permission in permissions {
242 if !permission_check
243 .has_permission(subject_sid, target.sid, permission.for_class(target.class))
244 .permit
245 {
246 return error!(EACCES);
247 }
248 }
249
250 Ok(())
251}
252
253fn has_fs_node_permissions(
255 permission_check: &PermissionCheck<'_>,
256 current_task: &CurrentTask,
257 subject_sid: SecurityId,
258 fs_node: &FsNode,
259 permissions: &[impl ForClass<FsNodeClass>],
260 audit_context: Auditable<'_>,
261) -> Result<(), Errno> {
262 trace_duration!(CATEGORY_STARNIX_SECURITY, "security.selinux.has_fs_node_permissions");
263
264 if Anon::is_private(fs_node) {
265 return Ok(());
266 }
267
268 let target = fs_node_effective_sid_and_class(fs_node);
269
270 let fs = fs_node.fs();
271 let audit_context = [audit_context, fs_node.into(), fs.as_ref().into()];
272 for permission in permissions {
273 check_permission(
274 permission_check,
275 current_task,
276 subject_sid,
277 target.sid,
278 permission.for_class(target.class),
279 (&audit_context).into(),
280 )?;
281 }
282
283 Ok(())
284}
285
286#[allow(dead_code)]
288fn todo_has_fs_node_permissions(
289 bug: BugRef,
290 permission_check: &PermissionCheck<'_>,
291 current_task: &CurrentTask,
292 subject_sid: SecurityId,
293 fs_node: &FsNode,
294 permissions: &[impl ForClass<FsNodeClass>],
295 audit_context: Auditable<'_>,
296) -> Result<(), Errno> {
297 trace_duration!(CATEGORY_STARNIX_SECURITY, "security.selinux.todo_has_fs_node_permissions");
298
299 if Anon::is_private(fs_node) {
300 return Ok(());
301 }
302
303 let target = fs_node_effective_sid_and_class(fs_node);
304
305 let fs = fs_node.fs();
306 let audit_context = [audit_context, fs_node.into(), fs.as_ref().into()];
307 for permission in permissions {
308 todo_check_permission(
309 bug.clone(),
310 permission_check,
311 current_task,
312 subject_sid,
313 target.sid,
314 permission.for_class(target.class),
315 (&audit_context).into(),
316 )?;
317 }
318
319 Ok(())
320}
321
322fn file_class_from_file_mode(mode: FileMode) -> Result<FileClass, Errno> {
323 let file_type = mode.bits() & starnix_uapi::S_IFMT;
324 match file_type {
325 starnix_uapi::S_IFLNK => Ok(FileClass::Link),
326 starnix_uapi::S_IFREG => Ok(FileClass::File),
327 starnix_uapi::S_IFDIR => Ok(FileClass::Dir),
328 starnix_uapi::S_IFCHR => Ok(FileClass::Character),
329 starnix_uapi::S_IFBLK => Ok(FileClass::Block),
330 starnix_uapi::S_IFIFO => Ok(FileClass::Fifo),
331 starnix_uapi::S_IFSOCK => Ok(FileClass::SockFile),
332 0 => {
333 track_stub!(TODO("https://fxbug.dev/378864191"), "File with zero IFMT?");
334 Ok(FileClass::File)
335 }
336 _ => error!(EINVAL, format!("mode: {:?}", mode)),
337 }
338}
339
340#[macro_export]
341macro_rules! TODO_DENY {
342 ($bug_url:literal, $message:literal) => {{
343 use starnix_logging::bug_ref;
344 bug_ref!($bug_url)
345 }};
346}
347
348fn fs_node_effective_sid_and_class(fs_node: &FsNode) -> FsNodeSidAndClass {
350 let state = fs_node.security_state.lock().clone();
351 let sid = match state.label {
352 FsNodeLabel::SecurityId { sid } => sid,
353 FsNodeLabel::FromTask { task_state } => task_state.lock().current_sid,
354 FsNodeLabel::Uninitialized => {
355 if cfg!(any(test, debug_assertions)) {
357 panic!(
358 "Unlabeled FsNode@{} of class {:?} in {} (label {:?})",
359 fs_node.ino,
360 file_class_from_file_mode(fs_node.info().mode),
361 fs_node.fs().name(),
362 fs_node.fs().security_state.state.label(),
363 );
364 } else {
365 track_stub!(
366 TODO("https://fxbug.dev/381210513"),
367 "SID requested for unlabeled FsNode"
368 );
369 InitialSid::Unlabeled.into()
370 }
371 }
372 };
373 FsNodeSidAndClass { sid, class: state.class }
374}
375
376fn todo_check_permission<P: ClassPermission + Into<KernelPermission> + Clone + 'static>(
379 bug: BugRef,
380 permission_check: &PermissionCheck<'_>,
381 current_task: &CurrentTask,
382 source_sid: SecurityId,
383 target_sid: SecurityId,
384 permission: P,
385 audit_context: Auditable<'_>,
386) -> Result<(), Errno> {
387 if is_internal_operation(current_task) {
388 return Ok(());
389 }
390 let kernel = current_task.kernel();
391 if kernel.features.selinux_test_suite {
392 check_permission(
393 permission_check,
394 current_task,
395 source_sid,
396 target_sid,
397 permission,
398 audit_context,
399 )
400 } else {
401 trace_duration!(CATEGORY_STARNIX_SECURITY, "security.selinux.todo_check_permission");
402
403 let result = permission_check.has_permission(source_sid, target_sid, permission.clone());
404
405 if result.audit {
406 audit_todo_decision(
407 current_task,
408 bug,
409 permission_check,
410 result,
411 source_sid,
412 target_sid,
413 permission.into(),
414 audit_context,
415 );
416 }
417
418 Ok(())
419 }
420}
421
422fn check_permission<P: ClassPermission + Into<KernelPermission> + Clone + 'static>(
424 permission_check: &PermissionCheck<'_>,
425 current_task: &CurrentTask,
426 source_sid: SecurityId,
427 target_sid: SecurityId,
428 permission: P,
429 audit_context: Auditable<'_>,
430) -> Result<(), Errno> {
431 trace_duration!(CATEGORY_STARNIX_SECURITY, "security.selinux.check_permission");
432
433 if is_internal_operation(current_task) {
434 return Ok(());
435 }
436 let result = permission_check.has_permission(source_sid, target_sid, permission.clone());
437
438 if result.audit {
439 if !result.permit {
440 current_task
441 .kernel()
442 .security_state
443 .state
444 .as_ref()
445 .unwrap()
446 .access_denial_count
447 .fetch_add(1, Ordering::Release);
448 }
449
450 audit_decision(
451 current_task,
452 permission_check,
453 result.clone(),
454 source_sid,
455 target_sid,
456 permission.into(),
457 audit_context,
458 );
459 };
460
461 result.permit.then_some(Ok(())).unwrap_or_else(|| error!(EACCES))
462}
463
464fn check_self_permission<P: ClassPermission + Into<KernelPermission> + Clone + 'static>(
466 permission_check: &PermissionCheck<'_>,
467 current_task: &CurrentTask,
468 subject_sid: SecurityId,
469 permission: P,
470 audit_context: Auditable<'_>,
471) -> Result<(), Errno> {
472 check_permission(
473 permission_check,
474 current_task,
475 subject_sid,
476 subject_sid,
477 permission,
478 audit_context,
479 )
480}
481
482pub(super) fn kernel_init_security(options: String, exceptions: Vec<String>) -> KernelState {
484 KernelState {
485 server: SecurityServer::new(options, exceptions),
486 pending_file_systems: Mutex::default(),
487 selinuxfs_null: OnceLock::default(),
488 access_denial_count: AtomicU64::new(0u64),
489 has_policy: false.into(),
490 }
491}
492
493pub(super) struct KernelState {
495 pub(super) server: Arc<SecurityServer>,
497
498 pub(super) pending_file_systems: Mutex<IndexSet<WeakKey<FileSystem>>>,
503
504 pub(super) has_policy: AtomicBool,
506
507 pub(super) selinuxfs_null: OnceLock<FileHandle>,
510
511 pub(super) access_denial_count: AtomicU64,
513}
514
515impl KernelState {
516 pub(super) fn access_denial_count(&self) -> u64 {
517 self.access_denial_count.load(Ordering::Acquire)
518 }
519
520 pub(super) fn has_policy(&self) -> bool {
521 self.has_policy.load(Ordering::Acquire)
522 }
523}
524
525#[derive(Clone, Debug, PartialEq)]
527pub(super) struct PerfEventState {
528 sid: SecurityId,
529}
530
531#[derive(Clone, Debug, PartialEq)]
533pub(super) struct TaskAttrs {
534 pub current_sid: SecurityId,
536
537 pub exec_sid: Option<SecurityId>,
539
540 pub fscreate_sid: Option<SecurityId>,
542
543 pub keycreate_sid: Option<SecurityId>,
545
546 pub previous_sid: SecurityId,
548
549 pub sockcreate_sid: Option<SecurityId>,
551
552 pub internal_operation: bool,
555}
556
557impl TaskAttrs {
558 pub(super) fn for_kernel() -> Self {
560 Self::for_sid(InitialSid::Kernel.into())
561 }
562
563 pub(super) fn for_selinux_disabled() -> Self {
565 Self::for_sid(InitialSid::Unlabeled.into())
566 }
567
568 pub(super) fn for_sid(sid: SecurityId) -> Self {
570 Self {
571 current_sid: sid,
572 previous_sid: sid,
573 exec_sid: None,
574 fscreate_sid: None,
575 keycreate_sid: None,
576 sockcreate_sid: None,
577 internal_operation: false,
578 }
579 }
580}
581
582pub(super) enum CurrentTaskStateHolder<'a> {
583 TaskState(&'a TaskState),
584 OverriddenTaskState(Ref<'a, Option<FullCredentials>>),
585}
586
587impl Deref for CurrentTaskStateHolder<'_> {
588 type Target = TaskState;
589 fn deref(&self) -> &Self::Target {
590 match self {
591 CurrentTaskStateHolder::TaskState(task_attrs) => &task_attrs,
592 CurrentTaskStateHolder::OverriddenTaskState(overridden_creds) => {
593 &overridden_creds.as_ref().unwrap().security_state
594 }
595 }
596 }
597}
598
599pub(in crate::security) fn current_task_state(
600 current_task: &CurrentTask,
601) -> CurrentTaskStateHolder<'_> {
602 if current_task.has_overridden_creds() {
603 CurrentTaskStateHolder::OverriddenTaskState(current_task.overridden_creds.borrow())
604 } else {
605 CurrentTaskStateHolder::TaskState(¤t_task.security_state)
606 }
607}
608
609pub(in crate::security) fn task_consistent_attrs(
611 current_task: &CurrentTask,
612) -> MutexGuard<'_, TaskAttrs> {
613 assert!(!current_task.has_overridden_creds());
614 current_task.security_state.lock()
615}
616
617#[derive(Debug)]
620pub(super) struct FileObjectState {
621 sid: SecurityId,
622}
623
624#[derive(Debug)]
627pub(super) struct FileSystemState {
628 mount_options: FileSystemMountOptions,
630 pending_entries: Mutex<IndexSet<WeakKey<DirEntry>>>,
631
632 label: OnceLock<FileSystemLabel>,
634}
635
636impl FileSystemState {
637 fn new(mount_options: FileSystemMountOptions, _ops: &dyn FileSystemOps) -> Self {
638 let pending_entries = Mutex::new(IndexSet::new());
639 let label = OnceLock::new();
640
641 Self { mount_options, pending_entries, label }
642 }
643
644 pub fn label(&self) -> Option<&FileSystemLabel> {
646 self.label.get()
647 }
648
649 pub fn supports_relabel(&self) -> bool {
651 let Some(label) = self.label() else {
652 return false;
653 };
654 match label.scheme {
655 FileSystemLabelingScheme::Mountpoint { .. } => false,
656 FileSystemLabelingScheme::FsUse { .. } => true,
657 FileSystemLabelingScheme::GenFsCon { supports_seclabel } => supports_seclabel,
658 }
659 }
660
661 pub fn supports_xattr(&self) -> bool {
663 let Some(label) = self.label() else {
664 return false;
665 };
666 match label.scheme {
667 FileSystemLabelingScheme::Mountpoint { .. }
668 | FileSystemLabelingScheme::GenFsCon { .. } => false,
669 FileSystemLabelingScheme::FsUse { fs_use_type, .. } => fs_use_type == FsUseType::Xattr,
670 }
671 }
672
673 fn write_mount_options(
683 &self,
684 security_server: &SecurityServer,
685 buf: &mut impl OutputBuffer,
686 ) -> Result<(), Errno> {
687 let Some(label) = self.label() else {
688 return Self::write_mount_options_to_buf(buf, &self.mount_options);
689 };
690
691 let to_context = |sid| security_server.sid_to_security_context(sid);
692 let mount_options = FileSystemMountOptions {
693 context: label.mount_sids.context.and_then(to_context),
694 fs_context: label.mount_sids.fs_context.and_then(to_context),
695 def_context: label.mount_sids.def_context.and_then(to_context),
696 root_context: label.mount_sids.root_context.and_then(to_context),
697 };
698
699 if self.supports_relabel() {
700 buf.write_all(b",seclabel").map(|_| ())?;
701 }
702
703 Self::write_mount_options_to_buf(buf, &mount_options)
704 }
705
706 fn write_mount_options_to_buf(
708 buf: &mut impl OutputBuffer,
709 mount_options: &FileSystemMountOptions,
710 ) -> Result<(), Errno> {
711 let mut write_option = |prefix: &[u8], option: &Option<Vec<u8>>| -> Result<(), Errno> {
712 let Some(value) = option else {
713 return Ok(());
714 };
715 buf.write_all(prefix).map(|_| ())?;
716 buf.write_all(value).map(|_| ())
717 };
718 write_option(b",context=", &mount_options.context)?;
719 write_option(b",fscontext=", &mount_options.fs_context)?;
720 write_option(b",defcontext=", &mount_options.def_context)?;
721 write_option(b",rootcontext=", &mount_options.root_context)
722 }
723}
724
725#[derive(Debug, Clone)]
727pub struct FsNodeState {
728 label: FsNodeLabel,
729 class: FsNodeClass,
730}
731
732impl Default for FsNodeState {
733 fn default() -> Self {
734 Self { label: FsNodeLabel::Uninitialized, class: FileClass::File.into() }
735 }
736}
737
738#[derive(Debug, Clone)]
740pub(super) enum FsNodeLabel {
741 Uninitialized,
742 SecurityId { sid: SecurityId },
743 FromTask { task_state: Arc<Mutex<TaskAttrs>> },
745}
746
747impl FsNodeLabel {
748 fn is_initialized(&self) -> bool {
749 !matches!(self, FsNodeLabel::Uninitialized)
750 }
751}
752
753#[derive(Debug, PartialEq)]
755struct FsNodeSidAndClass {
756 sid: SecurityId,
757 class: FsNodeClass,
758}
759
760#[derive(Clone, Debug, PartialEq)]
763pub(super) struct BinderConnectionState {
764 sid: SecurityId,
765}
766
767#[derive(Debug, Default)]
770pub(super) struct SocketState {
771 peer_sid: Mutex<Option<SecurityId>>,
772}
773
774#[derive(Clone, Debug, PartialEq)]
777pub(super) struct BpfMapState {
778 sid: SecurityId,
779}
780
781#[derive(Clone, Debug, PartialEq)]
784pub(super) struct BpfProgState {
785 sid: SecurityId,
786}
787
788pub(super) fn set_cached_sid(fs_node: &FsNode, sid: SecurityId) {
792 fs_node.security_state.lock().label = FsNodeLabel::SecurityId { sid };
793}
794
795fn fs_node_set_label_with_task(fs_node: &FsNode, task_state: Arc<Mutex<TaskAttrs>>) {
799 fs_node.security_state.lock().label = FsNodeLabel::FromTask { task_state };
800}
801
802fn fs_node_ensure_class(fs_node: &FsNode) -> Result<FsNodeClass, Errno> {
806 let class = fs_node.security_state.lock().class;
808 if class != FileClass::File.into() {
809 return Ok(class);
810 }
811
812 let file_mode = fs_node.info().mode;
813 let class = file_class_from_file_mode(file_mode)?.into();
814 fs_node.security_state.lock().class = class;
815 Ok(class)
816}
817
818#[cfg(test)]
819pub(super) fn get_cached_sid(fs_node: &FsNode) -> Option<SecurityId> {
821 let state = fs_node.security_state.lock().clone();
822 if matches!(state.label, FsNodeLabel::Uninitialized) {
823 None
824 } else {
825 Some(fs_node_effective_sid_and_class(fs_node).sid)
826 }
827}
828
829#[derive(Debug)]
832pub enum PolicyCapSupport {
833 AlwaysOn(BugRef),
834 AlwaysOff(BugRef),
835 Configurable,
836 NotImplemented,
837}
838
839fn policycap_support(policy_cap: PolicyCap) -> PolicyCapSupport {
842 match policy_cap {
843 PolicyCap::AlwaysCheckNetwork => {
844 PolicyCapSupport::AlwaysOff(bug_ref!("https://fxbug.dev/452453565"))
845 }
846 PolicyCap::CgroupSeclabel => PolicyCapSupport::Configurable,
847 PolicyCap::ExtendedSocketClass => {
848 PolicyCapSupport::AlwaysOff(bug_ref!("https://fxbug.dev/452453565"))
849 }
850 PolicyCap::FunctionfsSeclabel => PolicyCapSupport::Configurable,
851 PolicyCap::GenfsSeclabelSymlinks => PolicyCapSupport::Configurable,
852 PolicyCap::GenfsSeclabelWildcard => {
853 PolicyCapSupport::AlwaysOff(bug_ref!("https://fxbug.dev/452453565"))
854 }
855 PolicyCap::IoctlSkipCloexec => {
856 PolicyCapSupport::AlwaysOn(bug_ref!("https://fxbug.dev/452453565"))
857 }
858 PolicyCap::MemfdClass => PolicyCapSupport::Configurable,
859 PolicyCap::NetifWildcard => {
860 PolicyCapSupport::AlwaysOff(bug_ref!("https://fxbug.dev/452453565"))
861 }
862 PolicyCap::NetlinkXperm => PolicyCapSupport::Configurable,
863 PolicyCap::NetworkPeerControls => PolicyCapSupport::NotImplemented,
864 PolicyCap::NnpNosuidTransition => PolicyCapSupport::Configurable,
865 PolicyCap::OpenPerms => PolicyCapSupport::AlwaysOn(bug_ref!("https://fxbug.dev/452453565")),
866 PolicyCap::UserspaceInitialContext => {
867 PolicyCapSupport::AlwaysOn(bug_ref!("https://fxbug.dev/452453565"))
868 }
869 }
870}