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
482async fn create_inspect_values(
483 security_server: Arc<SecurityServer>,
484) -> Result<fuchsia_inspect::Inspector, anyhow::Error> {
485 let inspector = fuchsia_inspect::Inspector::default();
486
487 let policy_bytes = if let Some(policy_data) = security_server.get_binary_policy() {
488 policy_data.len().try_into()?
489 } else {
490 0
491 };
492 inspector.root().record_uint("policy_bytes", policy_bytes);
493
494 Ok(inspector)
495}
496
497pub(super) fn kernel_init_security(
499 options: String,
500 exceptions: Vec<String>,
501 inspect_node: &fuchsia_inspect::Node,
502) -> KernelState {
503 let server = SecurityServer::new(options, exceptions);
504 let inspect_node = inspect_node.create_child("selinux");
505
506 let server_for_inspect = server.clone();
507 inspect_node.record_lazy_values("server", move || {
508 Box::pin(create_inspect_values(server_for_inspect.clone()))
509 });
510
511 KernelState {
512 server,
513 pending_file_systems: Mutex::default(),
514 selinuxfs_null: OnceLock::default(),
515 access_denial_count: AtomicU64::new(0u64),
516 has_policy: false.into(),
517 _inspect_node: inspect_node,
518 }
519}
520
521pub(super) struct KernelState {
523 pub(super) server: Arc<SecurityServer>,
525
526 pub(super) pending_file_systems: Mutex<IndexSet<WeakKey<FileSystem>>>,
531
532 pub(super) has_policy: AtomicBool,
534
535 pub(super) selinuxfs_null: OnceLock<FileHandle>,
538
539 pub(super) access_denial_count: AtomicU64,
541
542 pub(super) _inspect_node: fuchsia_inspect::Node,
544}
545
546impl KernelState {
547 pub(super) fn access_denial_count(&self) -> u64 {
548 self.access_denial_count.load(Ordering::Acquire)
549 }
550
551 pub(super) fn has_policy(&self) -> bool {
552 self.has_policy.load(Ordering::Acquire)
553 }
554}
555
556#[derive(Clone, Debug, PartialEq)]
558pub(super) struct PerfEventState {
559 sid: SecurityId,
560}
561
562#[derive(Clone, Debug, PartialEq)]
564pub(super) struct TaskAttrs {
565 pub current_sid: SecurityId,
567
568 pub exec_sid: Option<SecurityId>,
570
571 pub fscreate_sid: Option<SecurityId>,
573
574 pub keycreate_sid: Option<SecurityId>,
576
577 pub previous_sid: SecurityId,
579
580 pub sockcreate_sid: Option<SecurityId>,
582
583 pub internal_operation: bool,
586}
587
588impl TaskAttrs {
589 pub(super) fn for_kernel() -> Self {
591 Self::for_sid(InitialSid::Kernel.into())
592 }
593
594 pub(super) fn for_selinux_disabled() -> Self {
596 Self::for_sid(InitialSid::Unlabeled.into())
597 }
598
599 pub(super) fn for_sid(sid: SecurityId) -> Self {
601 Self {
602 current_sid: sid,
603 previous_sid: sid,
604 exec_sid: None,
605 fscreate_sid: None,
606 keycreate_sid: None,
607 sockcreate_sid: None,
608 internal_operation: false,
609 }
610 }
611}
612
613pub(super) enum CurrentTaskStateHolder<'a> {
614 TaskState(&'a TaskState),
615 OverriddenTaskState(Ref<'a, Option<FullCredentials>>),
616}
617
618impl Deref for CurrentTaskStateHolder<'_> {
619 type Target = TaskState;
620 fn deref(&self) -> &Self::Target {
621 match self {
622 CurrentTaskStateHolder::TaskState(task_attrs) => &task_attrs,
623 CurrentTaskStateHolder::OverriddenTaskState(overridden_creds) => {
624 &overridden_creds.as_ref().unwrap().security_state
625 }
626 }
627 }
628}
629
630pub(in crate::security) fn current_task_state(
631 current_task: &CurrentTask,
632) -> CurrentTaskStateHolder<'_> {
633 if current_task.has_overridden_creds() {
634 CurrentTaskStateHolder::OverriddenTaskState(current_task.overridden_creds.borrow())
635 } else {
636 CurrentTaskStateHolder::TaskState(¤t_task.security_state)
637 }
638}
639
640pub(in crate::security) fn task_consistent_attrs(
642 current_task: &CurrentTask,
643) -> MutexGuard<'_, TaskAttrs> {
644 assert!(!current_task.has_overridden_creds());
645 current_task.security_state.lock()
646}
647
648#[derive(Debug)]
651pub(super) struct FileObjectState {
652 sid: SecurityId,
653}
654
655#[derive(Debug)]
658pub(super) struct FileSystemState {
659 mount_options: FileSystemMountOptions,
661 pending_entries: Mutex<IndexSet<WeakKey<DirEntry>>>,
662
663 label: OnceLock<FileSystemLabel>,
665}
666
667impl FileSystemState {
668 fn new(mount_options: FileSystemMountOptions, _ops: &dyn FileSystemOps) -> Self {
669 let pending_entries = Mutex::new(IndexSet::new());
670 let label = OnceLock::new();
671
672 Self { mount_options, pending_entries, label }
673 }
674
675 pub fn label(&self) -> Option<&FileSystemLabel> {
677 self.label.get()
678 }
679
680 pub fn supports_relabel(&self) -> bool {
682 let Some(label) = self.label() else {
683 return false;
684 };
685 match label.scheme {
686 FileSystemLabelingScheme::Mountpoint { .. } => false,
687 FileSystemLabelingScheme::FsUse { .. } => true,
688 FileSystemLabelingScheme::GenFsCon { supports_seclabel } => supports_seclabel,
689 }
690 }
691
692 pub fn supports_xattr(&self) -> bool {
694 let Some(label) = self.label() else {
695 return false;
696 };
697 match label.scheme {
698 FileSystemLabelingScheme::Mountpoint { .. }
699 | FileSystemLabelingScheme::GenFsCon { .. } => false,
700 FileSystemLabelingScheme::FsUse { fs_use_type, .. } => fs_use_type == FsUseType::Xattr,
701 }
702 }
703
704 fn write_mount_options(
714 &self,
715 security_server: &SecurityServer,
716 buf: &mut impl OutputBuffer,
717 ) -> Result<(), Errno> {
718 let Some(label) = self.label() else {
719 return Self::write_mount_options_to_buf(buf, &self.mount_options);
720 };
721
722 let to_context = |sid| security_server.sid_to_security_context(sid);
723 let mount_options = FileSystemMountOptions {
724 context: label.mount_sids.context.and_then(to_context),
725 fs_context: label.mount_sids.fs_context.and_then(to_context),
726 def_context: label.mount_sids.def_context.and_then(to_context),
727 root_context: label.mount_sids.root_context.and_then(to_context),
728 };
729
730 if self.supports_relabel() {
731 buf.write_all(b",seclabel").map(|_| ())?;
732 }
733
734 Self::write_mount_options_to_buf(buf, &mount_options)
735 }
736
737 fn write_mount_options_to_buf(
739 buf: &mut impl OutputBuffer,
740 mount_options: &FileSystemMountOptions,
741 ) -> Result<(), Errno> {
742 let mut write_option = |prefix: &[u8], option: &Option<Vec<u8>>| -> Result<(), Errno> {
743 let Some(value) = option else {
744 return Ok(());
745 };
746 buf.write_all(prefix).map(|_| ())?;
747 buf.write_all(value).map(|_| ())
748 };
749 write_option(b",context=", &mount_options.context)?;
750 write_option(b",fscontext=", &mount_options.fs_context)?;
751 write_option(b",defcontext=", &mount_options.def_context)?;
752 write_option(b",rootcontext=", &mount_options.root_context)
753 }
754}
755
756#[derive(Debug, Clone)]
758pub struct FsNodeState {
759 label: FsNodeLabel,
760 class: FsNodeClass,
761}
762
763impl Default for FsNodeState {
764 fn default() -> Self {
765 Self { label: FsNodeLabel::Uninitialized, class: FileClass::File.into() }
766 }
767}
768
769#[derive(Debug, Clone)]
771pub(super) enum FsNodeLabel {
772 Uninitialized,
773 SecurityId { sid: SecurityId },
774 FromTask { task_state: Arc<Mutex<TaskAttrs>> },
776}
777
778impl FsNodeLabel {
779 fn is_initialized(&self) -> bool {
780 !matches!(self, FsNodeLabel::Uninitialized)
781 }
782}
783
784#[derive(Debug, PartialEq)]
786struct FsNodeSidAndClass {
787 sid: SecurityId,
788 class: FsNodeClass,
789}
790
791#[derive(Clone, Debug, PartialEq)]
794pub(super) struct BinderConnectionState {
795 sid: SecurityId,
796}
797
798#[derive(Debug, Default)]
801pub(super) struct SocketState {
802 peer_sid: Mutex<Option<SecurityId>>,
803}
804
805#[derive(Clone, Debug, PartialEq)]
808pub(super) struct BpfMapState {
809 sid: SecurityId,
810}
811
812#[derive(Clone, Debug, PartialEq)]
815pub(super) struct BpfProgState {
816 sid: SecurityId,
817}
818
819pub(super) fn set_cached_sid(fs_node: &FsNode, sid: SecurityId) {
823 fs_node.security_state.lock().label = FsNodeLabel::SecurityId { sid };
824}
825
826fn fs_node_set_label_with_task(fs_node: &FsNode, task_state: Arc<Mutex<TaskAttrs>>) {
830 fs_node.security_state.lock().label = FsNodeLabel::FromTask { task_state };
831}
832
833fn fs_node_ensure_class(fs_node: &FsNode) -> Result<FsNodeClass, Errno> {
837 let class = fs_node.security_state.lock().class;
839 if class != FileClass::File.into() {
840 return Ok(class);
841 }
842
843 let file_mode = fs_node.info().mode;
844 let class = file_class_from_file_mode(file_mode)?.into();
845 fs_node.security_state.lock().class = class;
846 Ok(class)
847}
848
849#[cfg(test)]
850pub(super) fn get_cached_sid(fs_node: &FsNode) -> Option<SecurityId> {
852 let state = fs_node.security_state.lock().clone();
853 if matches!(state.label, FsNodeLabel::Uninitialized) {
854 None
855 } else {
856 Some(fs_node_effective_sid_and_class(fs_node).sid)
857 }
858}
859
860#[derive(Debug)]
863pub enum PolicyCapSupport {
864 AlwaysOn(BugRef),
865 AlwaysOff(BugRef),
866 Configurable,
867 NotImplemented,
868}
869
870fn policycap_support(policy_cap: PolicyCap) -> PolicyCapSupport {
873 match policy_cap {
874 PolicyCap::AlwaysCheckNetwork => {
875 PolicyCapSupport::AlwaysOff(bug_ref!("https://fxbug.dev/452453565"))
876 }
877 PolicyCap::CgroupSeclabel => PolicyCapSupport::Configurable,
878 PolicyCap::ExtendedSocketClass => {
879 PolicyCapSupport::AlwaysOff(bug_ref!("https://fxbug.dev/452453565"))
880 }
881 PolicyCap::FunctionfsSeclabel => PolicyCapSupport::Configurable,
882 PolicyCap::GenfsSeclabelSymlinks => PolicyCapSupport::Configurable,
883 PolicyCap::GenfsSeclabelWildcard => {
884 PolicyCapSupport::AlwaysOff(bug_ref!("https://fxbug.dev/452453565"))
885 }
886 PolicyCap::IoctlSkipCloexec => {
887 PolicyCapSupport::AlwaysOn(bug_ref!("https://fxbug.dev/452453565"))
888 }
889 PolicyCap::MemfdClass => PolicyCapSupport::Configurable,
890 PolicyCap::NetifWildcard => {
891 PolicyCapSupport::AlwaysOff(bug_ref!("https://fxbug.dev/452453565"))
892 }
893 PolicyCap::NetlinkXperm => PolicyCapSupport::Configurable,
894 PolicyCap::NetworkPeerControls => PolicyCapSupport::NotImplemented,
895 PolicyCap::NnpNosuidTransition => PolicyCapSupport::Configurable,
896 PolicyCap::OpenPerms => PolicyCapSupport::AlwaysOn(bug_ref!("https://fxbug.dev/452453565")),
897 PolicyCap::UserspaceInitialContext => {
898 PolicyCapSupport::AlwaysOn(bug_ref!("https://fxbug.dev/452453565"))
899 }
900 }
901}