selinux/
lib.rs

1// Copyright 2024 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
5pub mod permission_check;
6pub mod policy;
7pub mod security_server;
8
9pub use security_server::SecurityServer;
10
11mod access_vector_cache;
12mod exceptions_config;
13mod fifo_cache;
14mod sid_table;
15mod sync;
16
17use policy::arrays::FsUseType;
18
19use std::num::NonZeroU32;
20
21/// Numeric class Ids are provided to the userspace AVC surfaces (e.g. "create", "access", etc).
22pub use policy::ClassId;
23
24/// The Security ID (SID) used internally to refer to a security context.
25#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
26pub struct SecurityId(NonZeroU32);
27
28impl SecurityId {
29    /// Returns a `SecurityId` encoding the specified initial Security Context.
30    /// These are used when labeling kernel resources created before policy
31    /// load, allowing the policy to determine the Security Context to use.
32    pub fn initial(initial_sid: InitialSid) -> Self {
33        Self(NonZeroU32::new(initial_sid as u32).unwrap())
34    }
35}
36
37/// Identifies a specific class by its policy-defined Id, or as a kernel object class enum Id.
38#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
39pub enum ObjectClass {
40    /// Refers to a well-known SELinux kernel object class (e.g. "process", "file", "capability").
41    Kernel(KernelClass),
42    /// Refers to a policy-defined class by its policy-defined numeric Id. This is most commonly
43    /// used when handling queries from userspace, which refer to classes by-Id.
44    ClassId(ClassId),
45}
46
47impl From<ClassId> for ObjectClass {
48    fn from(id: ClassId) -> Self {
49        Self::ClassId(id)
50    }
51}
52
53impl<T: Into<KernelClass>> From<T> for ObjectClass {
54    fn from(class: T) -> Self {
55        Self::Kernel(class.into())
56    }
57}
58
59/// Declares an `enum` and implements an `all_variants()` API for it.
60macro_rules! enumerable_enum {
61    ($(#[$meta:meta])* $name:ident $(extends $common_name:ident)? {
62        $($(#[$variant_meta:meta])* $variant:ident,)*
63    }) => {
64        $(#[$meta])*
65        pub enum $name {
66            $($(#[$variant_meta])* $variant,)*
67            $(Common($common_name),)?
68        }
69
70        impl $name {
71            pub fn all_variants() -> Vec<Self> {
72                let all_variants = vec![$($name::$variant),*];
73                $(let mut all_variants = all_variants; all_variants.extend($common_name::all_variants().into_iter().map(Self::Common));)?
74                all_variants
75            }
76        }
77    }
78}
79
80enumerable_enum! {
81    /// A well-known class in SELinux policy that has a particular meaning in policy enforcement
82    /// hooks.
83    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
84    KernelClass {
85        // keep-sorted start
86        /// The SELinux "anon_inode" object class.
87        AnonFsNode,
88        /// The SELinux "blk_file" object class.
89        Block,
90        /// The SELinux "bpf" object class.
91        Bpf,
92        /// The SELinux "capability" object class.
93        Capability,
94        /// The SELinux "capability2" object class.
95        Capability2,
96        /// The SELinux "chr_file" object class.
97        Character,
98        /// The SELinux "dir" object class.
99        Dir,
100        /// The SELinux "fd" object class.
101        Fd,
102        /// The SELinux "fifo_file" object class.
103        Fifo,
104        /// The SELinux "file" object class.
105        File,
106        /// The SELinux "filesystem" object class.
107        FileSystem,
108        /// The SELinux "key_socket" object class.
109        KeySocket,
110        /// The SELinux "lnk_file" object class.
111        Link,
112        /// The SELinux "netlink_audit_socket" object class.
113        NetlinkAuditSocket,
114        /// The SELinux "netlink_connector_socket" object class.
115        NetlinkConnectorSocket,
116        /// The SELinux "netlink_crypto_socket" object class.
117        NetlinkCryptoSocket,
118        /// The SELinux "netlink_dnrt_socket" object class.
119        NetlinkDnrtSocket,
120        /// The SELinux "netlink_fib_lookup_socket" object class.
121        NetlinkFibLookupSocket,
122        /// The SELinux "netlink_firewall_socket" object class.
123        NetlinkFirewallSocket,
124        /// The SELinux "netlink_generic_socket" object class.
125        NetlinkGenericSocket,
126        /// The SELinux "netlink_ip6fw_socket" object class.
127        NetlinkIp6FwSocket,
128        /// The SELinux "netlink_iscsi_socket" object class.
129        NetlinkIscsiSocket,
130        /// The SELinux "netlink_kobject_uevent_socket" object class.
131        NetlinkKobjectUeventSocket,
132        /// The SELinux "netlink_netfilter_socket" object class.
133        NetlinkNetfilterSocket,
134        /// The SELinux "netlink_nflog_socket" object class.
135        NetlinkNflogSocket,
136        /// The SELinux "netlink_rdma_socket" object class.
137        NetlinkRdmaSocket,
138        /// The SELinux "netlink_route_socket" object class.
139        NetlinkRouteSocket,
140        /// The SELinux "netlink_scsitransport_socket" object class.
141        NetlinkScsitransportSocket,
142        /// The SELinux "netlink_selinux_socket" object class.
143        NetlinkSelinuxSocket,
144        /// The SELinux "netlink_socket" object class.
145        NetlinkSocket,
146        /// The SELinux "netlink_tcpdiag_socket" object class.
147        NetlinkTcpDiagSocket,
148        /// The SELinux "netlink_xfrm_socket" object class.
149        NetlinkXfrmSocket,
150        /// The SELinux "packet_socket" object class.
151        PacketSocket,
152        /// The SELinux "process" object class.
153        Process,
154        /// The SELinux "rawip_socket" object class.
155        RawIpSocket,
156        /// The SELinux "security" object class.
157        Security,
158        /// The SELinux "sock_file" object class.
159        SockFile,
160        /// The SELinux "socket" object class.
161        Socket,
162        /// The SELinux "tcp_socket" object class.
163        TcpSocket,
164        /// The SELinux "udp_socket" object class.
165        UdpSocket,
166        /// The SELinux "unix_dgram_socket" object class.
167        UnixDgramSocket,
168        /// The SELinux "unix_stream_socket" object class.
169        UnixStreamSocket,
170        /// The SELinux "vsock_socket" object class.
171        VSockSocket,
172        // keep-sorted end
173    }
174}
175
176impl KernelClass {
177    /// Returns the name used to refer to this object class in the SELinux binary policy.
178    pub fn name(&self) -> &'static str {
179        match self {
180            // keep-sorted start
181            Self::AnonFsNode => "anon_inode",
182            Self::Block => "blk_file",
183            Self::Bpf => "bpf",
184            Self::Capability => "capability",
185            Self::Capability2 => "capability2",
186            Self::Character => "chr_file",
187            Self::Dir => "dir",
188            Self::Fd => "fd",
189            Self::Fifo => "fifo_file",
190            Self::File => "file",
191            Self::FileSystem => "filesystem",
192            Self::KeySocket => "key_socket",
193            Self::Link => "lnk_file",
194            Self::NetlinkAuditSocket => "netlink_audit_socket",
195            Self::NetlinkConnectorSocket => "netlink_connector_socket",
196            Self::NetlinkCryptoSocket => "netlink_crypto_socket",
197            Self::NetlinkDnrtSocket => "netlink_dnrt_socket",
198            Self::NetlinkFibLookupSocket => "netlink_fib_lookup_socket",
199            Self::NetlinkFirewallSocket => "netlink_firewall_socket",
200            Self::NetlinkGenericSocket => "netlink_generic_socket",
201            Self::NetlinkIp6FwSocket => "netlink_ip6fw_socket",
202            Self::NetlinkIscsiSocket => "netlink_iscsi_socket",
203            Self::NetlinkKobjectUeventSocket => "netlink_kobject_uevent_socket",
204            Self::NetlinkNetfilterSocket => "netlink_netfilter_socket",
205            Self::NetlinkNflogSocket => "netlink_nflog_socket",
206            Self::NetlinkRdmaSocket => "netlink_rdma_socket",
207            Self::NetlinkRouteSocket => "netlink_route_socket",
208            Self::NetlinkScsitransportSocket => "netlink_scsitransport_socket",
209            Self::NetlinkSelinuxSocket => "netlink_selinux_socket",
210            Self::NetlinkSocket => "netlink_socket",
211            Self::NetlinkTcpDiagSocket => "netlink_tcpdiag_socket",
212            Self::NetlinkXfrmSocket => "netlink_xfrm_socket",
213            Self::PacketSocket => "packet_socket",
214            Self::Process => "process",
215            Self::RawIpSocket => "rawip_socket",
216            Self::Security => "security",
217            Self::SockFile => "sock_file",
218            Self::Socket => "socket",
219            Self::TcpSocket => "tcp_socket",
220            Self::UdpSocket => "udp_socket",
221            Self::UnixDgramSocket => "unix_dgram_socket",
222            Self::UnixStreamSocket => "unix_stream_socket",
223            Self::VSockSocket => "vsock_socket",
224            // keep-sorted end
225        }
226    }
227}
228
229enumerable_enum! {
230    /// Covers the set of classes that inherit from the common "cap" symbol (e.g. "capability" for
231    /// now and "cap_userns" after Starnix gains user namespacing support).
232    #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
233    CapClass {
234        // keep-sorted start
235        /// The SELinux "capability" object class.
236        Capability,
237        // keep-sorted end
238    }
239}
240
241impl From<CapClass> for KernelClass {
242    fn from(cap_class: CapClass) -> Self {
243        match cap_class {
244            // keep-sorted start
245            CapClass::Capability => Self::Capability,
246            // keep-sorted end
247        }
248    }
249}
250
251enumerable_enum! {
252    /// Covers the set of classes that inherit from the common "cap2" symbol (e.g. "capability2" for
253    /// now and "cap2_userns" after Starnix gains user namespacing support).
254    #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
255    Cap2Class {
256        // keep-sorted start
257        /// The SELinux "capability2" object class.
258        Capability2,
259        // keep-sorted end
260    }
261}
262
263impl From<Cap2Class> for KernelClass {
264    fn from(cap2_class: Cap2Class) -> Self {
265        match cap2_class {
266            // keep-sorted start
267            Cap2Class::Capability2 => Self::Capability2,
268            // keep-sorted end
269        }
270    }
271}
272
273enumerable_enum! {
274    /// A well-known file-like class in SELinux policy that has a particular meaning in policy
275    /// enforcement hooks.
276    #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
277    FileClass {
278        // keep-sorted start
279        /// The SELinux "anon_inode" object class.
280        AnonFsNode,
281        /// The SELinux "blk_file" object class.
282        Block,
283        /// The SELinux "chr_file" object class.
284        Character,
285        /// The SELinux "dir" object class.
286        Dir,
287        /// The SELinux "fifo_file" object class.
288        Fifo,
289        /// The SELinux "file" object class.
290        File,
291        /// The SELinux "lnk_file" object class.
292        Link,
293        /// The SELinux "sock_file" object class.
294        SockFile,
295        // keep-sorted end
296    }
297}
298
299impl From<FileClass> for KernelClass {
300    fn from(file_class: FileClass) -> Self {
301        match file_class {
302            // keep-sorted start
303            FileClass::AnonFsNode => Self::AnonFsNode,
304            FileClass::Block => Self::Block,
305            FileClass::Character => Self::Character,
306            FileClass::Dir => Self::Dir,
307            FileClass::Fifo => Self::Fifo,
308            FileClass::File => Self::File,
309            FileClass::Link => Self::Link,
310            FileClass::SockFile => Self::SockFile,
311            // keep-sorted end
312        }
313    }
314}
315
316enumerable_enum! {
317    /// Distinguishes socket-like kernel object classes defined in SELinux policy.
318    #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
319    SocketClass {
320        // keep-sorted start
321        Key,
322        Netlink,
323        NetlinkAudit,
324        NetlinkConnector,
325        NetlinkCrypto,
326        NetlinkDnrt,
327        NetlinkFibLookup,
328        NetlinkFirewall,
329        NetlinkGeneric,
330        NetlinkIp6Fw,
331        NetlinkIscsi,
332        NetlinkKobjectUevent,
333        NetlinkNetfilter,
334        NetlinkNflog,
335        NetlinkRdma,
336        NetlinkRoute,
337        NetlinkScsitransport,
338        NetlinkSelinux,
339        NetlinkTcpDiag,
340        NetlinkXfrm,
341        Packet,
342        RawIp,
343        /// Generic socket class applied to all socket-like objects for which no more specific
344        /// class is defined.
345        Socket,
346        Tcp,
347        Udp,
348        UnixDgram,
349        UnixStream,
350        Vsock,
351        // keep-sorted end
352    }
353}
354
355impl From<SocketClass> for KernelClass {
356    fn from(socket_class: SocketClass) -> Self {
357        match socket_class {
358            // keep-sorted start
359            SocketClass::Key => Self::KeySocket,
360            SocketClass::Netlink => Self::NetlinkSocket,
361            SocketClass::NetlinkAudit => Self::NetlinkAuditSocket,
362            SocketClass::NetlinkConnector => Self::NetlinkConnectorSocket,
363            SocketClass::NetlinkCrypto => Self::NetlinkCryptoSocket,
364            SocketClass::NetlinkDnrt => Self::NetlinkDnrtSocket,
365            SocketClass::NetlinkFibLookup => Self::NetlinkFibLookupSocket,
366            SocketClass::NetlinkFirewall => Self::NetlinkFirewallSocket,
367            SocketClass::NetlinkGeneric => Self::NetlinkGenericSocket,
368            SocketClass::NetlinkIp6Fw => Self::NetlinkIp6FwSocket,
369            SocketClass::NetlinkIscsi => Self::NetlinkIscsiSocket,
370            SocketClass::NetlinkKobjectUevent => Self::NetlinkDnrtSocket,
371            SocketClass::NetlinkNetfilter => Self::NetlinkNetfilterSocket,
372            SocketClass::NetlinkNflog => Self::NetlinkNflogSocket,
373            SocketClass::NetlinkRdma => Self::NetlinkRdmaSocket,
374            SocketClass::NetlinkRoute => Self::NetlinkRouteSocket,
375            SocketClass::NetlinkScsitransport => Self::NetlinkScsitransportSocket,
376            SocketClass::NetlinkSelinux => Self::NetlinkSelinuxSocket,
377            SocketClass::NetlinkTcpDiag => Self::NetlinkTcpDiagSocket,
378            SocketClass::NetlinkXfrm => Self::NetlinkXfrmSocket,
379            SocketClass::Packet => Self::PacketSocket,
380            SocketClass::RawIp => Self::RawIpSocket,
381            SocketClass::Socket => Self::Socket,
382            SocketClass::Tcp => Self::TcpSocket,
383            SocketClass::Udp => Self::UdpSocket,
384            SocketClass::UnixDgram => Self::UnixDgramSocket,
385            SocketClass::UnixStream => Self::UnixStreamSocket,
386            SocketClass::Vsock => Self::VSockSocket,
387            // keep-sorted end
388        }
389    }
390}
391
392/// Container for a security class that could be associated with a [`crate::vfs::FsNode`], to allow
393/// permissions common to both file-like and socket-like classes to be generated easily by hooks.
394#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
395pub enum FsNodeClass {
396    File(FileClass),
397    Socket(SocketClass),
398}
399
400impl From<FsNodeClass> for KernelClass {
401    fn from(class: FsNodeClass) -> Self {
402        match class {
403            FsNodeClass::File(file_class) => file_class.into(),
404            FsNodeClass::Socket(sock_class) => sock_class.into(),
405        }
406    }
407}
408
409impl From<FileClass> for FsNodeClass {
410    fn from(file_class: FileClass) -> Self {
411        FsNodeClass::File(file_class)
412    }
413}
414
415impl From<SocketClass> for FsNodeClass {
416    fn from(sock_class: SocketClass) -> Self {
417        FsNodeClass::Socket(sock_class)
418    }
419}
420
421pub trait ClassPermission {
422    fn class(&self) -> KernelClass;
423}
424
425macro_rules! permission_enum {
426    ($(#[$meta:meta])* $name:ident {
427        $($(#[$variant_meta:meta])* $variant:ident($inner:ident)),*,
428    }) => {
429        $(#[$meta])*
430        pub enum $name {
431            $($(#[$variant_meta])* $variant($inner)),*
432        }
433
434        $(impl From<$inner> for $name {
435            fn from(v: $inner) -> Self {
436                Self::$variant(v)
437            }
438        })*
439
440        impl ClassPermission for $name {
441            fn class(&self) -> KernelClass {
442                match self {
443                    $($name::$variant(_) => KernelClass::$variant),*
444                }
445            }
446        }
447
448        impl $name {
449            pub fn name(&self) -> &'static str {
450                match self {
451                    $($name::$variant(v) => v.name()),*
452                }
453            }
454
455            pub fn all_variants() -> Vec<Self> {
456                let mut all_variants = vec![];
457                $(all_variants.extend($inner::all_variants().into_iter().map($name::from));)*
458                all_variants
459            }
460        }
461    }
462}
463
464permission_enum! {
465    /// A well-known `(class, permission)` pair in SELinux policy that has a particular meaning in
466    /// policy enforcement hooks.
467    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
468    KernelPermission {
469        // keep-sorted start
470        /// Permissions for the well-known SELinux "anon_inode" file-like object class.
471        AnonFsNode(AnonFsNodePermission),
472        /// Permissions for the well-known SELinux "blk_file" file-like object class.
473        Block(BlockFilePermission),
474        /// Permissions for the well-known SELinux "bpf" file-like object class.
475        Bpf(BpfPermission),
476        /// Permissions for the well-known SELinux "capability" object class.
477        Capability(CapabilityPermission),
478        /// Permissions for the well-known SELinux "capability2" object class.
479        Capability2(Capability2Permission),
480        /// Permissions for the well-known SELinux "chr_file" file-like object class.
481        Character(CharacterFilePermission),
482        /// Permissions for the well-known SELinux "dir" file-like object class.
483        Dir(DirPermission),
484        /// Permissions for the well-known SELinux "fd" object class.
485        Fd(FdPermission),
486        /// Permissions for the well-known SELinux "fifo_file" file-like object class.
487        Fifo(FifoFilePermission),
488        /// Permissions for the well-known SELinux "file" object class.
489        File(FilePermission),
490        /// Permissions for the well-known SELinux "filesystem" object class.
491        FileSystem(FileSystemPermission),
492        /// Permissions for the well-known SELinux "packet_socket" object class.
493        KeySocket(KeySocketPermission),
494        /// Permissions for the well-known SELinux "lnk_file" file-like object class.
495        Link(LinkFilePermission),
496        /// Permissions for the well-known SELinux "netlink_audit_socket" file-like object class.
497        NetlinkAuditSocket(NetlinkAuditSocketPermission),
498        /// Permissions for the well-known SELinux "netlink_connector_socket" file-like object class.
499        NetlinkConnectorSocket(NetlinkConnectorSocketPermission),
500        /// Permissions for the well-known SELinux "netlink_crypto_socket" file-like object class.
501        NetlinkCryptoSocket(NetlinkCryptoSocketPermission),
502        /// Permissions for the well-known SELinux "netlink_dnrt_socket" file-like object class.
503        NetlinkDnrtSocket(NetlinkDnrtSocketPermission),
504        /// Permissions for the well-known SELinux "netlink_fib_lookup_socket" file-like object class.
505        NetlinkFibLookupSocket(NetlinkFibLookupSocketPermission),
506        /// Permissions for the well-known SELinux "netlink_firewall_socket" file-like object class.
507        NetlinkFirewallSocket(NetlinkFirewallSocketPermission),
508        /// Permissions for the well-known SELinux "netlink_generic_socket" file-like object class.
509        NetlinkGenericSocket(NetlinkGenericSocketPermission),
510        /// Permissions for the well-known SELinux "netlink_ip6fw_socket" file-like object class.
511        NetlinkIp6FwSocket(NetlinkIp6FwSocketPermission),
512        /// Permissions for the well-known SELinux "netlink_iscsi_socket" file-like object class.
513        NetlinkIscsiSocket(NetlinkIscsiSocketPermission),
514        /// Permissions for the well-known SELinux "netlink_kobject_uevent_socket" file-like object class.
515        NetlinkKobjectUeventSocket(NetlinkKobjectUeventSocketPermission),
516        /// Permissions for the well-known SELinux "netlink_netfilter_socket" file-like object class.
517        NetlinkNetfilterSocket(NetlinkNetfilterSocketPermission),
518        /// Permissions for the well-known SELinux "netlink_nflog_socket" file-like object class.
519        NetlinkNflogSocket(NetlinkNflogSocketPermission),
520        /// Permissions for the well-known SELinux "netlink_rdma_socket" file-like object class.
521        NetlinkRdmaSocket(NetlinkRdmaSocketPermission),
522        /// Permissions for the well-known SELinux "netlink_route_socket" file-like object class.
523        NetlinkRouteSocket(NetlinkRouteSocketPermission),
524        /// Permissions for the well-known SELinux "netlink_scsitransport_socket" file-like object class.
525        NetlinkScsitransportSocket(NetlinkScsitransportSocketPermission),
526        /// Permissions for the well-known SELinux "netlink_selinux_socket" file-like object class.
527        NetlinkSelinuxSocket(NetlinkSelinuxSocketPermission),
528        /// Permissions for the well-known SELinux "netlink_socket" file-like object class.
529        NetlinkSocket(NetlinkSocketPermission),
530        /// Permissions for the well-known SELinux "netlink_tcpdiag_socket" file-like object class.
531        NetlinkTcpDiagSocket(NetlinkTcpDiagSocketPermission),
532        /// Permissions for the well-known SELinux "netlink_xfrm_socket" file-like object class.
533        NetlinkXfrmSocket(NetlinkXfrmSocketPermission),
534        /// Permissions for the well-known SELinux "packet_socket" object class.
535        PacketSocket(PacketSocketPermission),
536        /// Permissions for the well-known SELinux "process" object class.
537        Process(ProcessPermission),
538        /// Permissions for the well-known SELinux "rawip_socket" object class.
539        RawIpSocket(RawIpSocketPermission),
540        /// Permissions for access to parts of the "selinuxfs" used to administer and query SELinux.
541        Security(SecurityPermission),
542        /// Permissions for the well-known SELinux "sock_file" file-like object class.
543        SockFile(SockFilePermission),
544        /// Permissions for the well-known SELinux "socket" object class.
545        Socket(SocketPermission),
546        /// Permissions for the well-known SELinux "tcp_socket" object class.
547        TcpSocket(TcpSocketPermission),
548        /// Permissions for the well-known SELinux "udp_socket" object class.
549        UdpSocket(UdpSocketPermission),
550        /// Permissions for the well-known SELinux "unix_dgram_socket" object class.
551        UnixDgramSocket(UnixDgramSocketPermission),
552        /// Permissions for the well-known SELinux "unix_stream_socket" object class.
553        UnixStreamSocket(UnixStreamSocketPermission),
554        /// Permissions for the well-known SELinux "vsock_socket" object class.
555        VSockSocket(VsockSocketPermission),
556        // keep-sorted end
557    }
558}
559
560/// Helper used to define an enum of permission values, with specified names.
561/// Uses of this macro should not rely on "extends", which is solely for use to express permission
562/// inheritance in `class_permission_enum`.
563macro_rules! common_permission_enum {
564    ($(#[$meta:meta])* $name:ident $(extends $common_name:ident)? {
565        $($(#[$variant_meta:meta])* $variant:ident ($variant_name:literal),)*
566    }) => {
567        enumerable_enum! {
568            $(#[$meta])* $name $(extends $common_name)? {
569                $($(#[$variant_meta])* $variant,)*
570            }
571        }
572
573        impl $name {
574            fn name(&self) -> &'static str {
575                match self {
576                    $($name::$variant => $variant_name,)*
577                    $(Self::Common(v) => {let v:$common_name = v.clone(); v.name()},)?
578                }
579            }
580        }
581    }
582}
583
584/// Helper used to declare the set of named permissions associated with an SELinux class.
585/// The `ClassType` trait is implemented on the declared `enum`, enabling values to be wrapped into
586/// the generic `KernelPermission` container.
587/// If an "extends" type is specified then a `Common` enum case is added, encapsulating the values
588/// of that underlying permission type. This is used to represent e.g. SELinux "dir" class deriving
589/// a basic set of permissions from the common "file" symbol.
590macro_rules! class_permission_enum {
591    ($(#[$meta:meta])* $name:ident $(extends $common_name:ident)? {
592        $($(#[$variant_meta:meta])* $variant:ident ($variant_name:literal),)*
593    }) => {
594        common_permission_enum! {
595            $(#[$meta])* $name $(extends $common_name)? {
596                $($(#[$variant_meta])* $variant ($variant_name),)*
597            }
598        }
599
600        impl ClassPermission for $name {
601            fn class(&self) -> KernelClass {
602                KernelPermission::from(self.clone()).class()
603            }
604        }
605    }
606}
607
608common_permission_enum! {
609    /// Permissions common to all cap-like object classes (e.g. "capability" for now and
610    /// "cap_userns" after Starnix gains user namespacing support). These are combined with a
611    /// specific `CapabilityClass` by policy enforcement hooks, to obtain class-affine permission
612    /// values to check.
613    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
614    CommonCapPermission {
615        // keep-sorted start
616
617        AuditControl("audit_control"),
618        AuditWrite("audit_write"),
619        Chown("chown"),
620        DacOverride("dac_override"),
621        DacReadSearch("dac_read_search"),
622        Fowner("fowner"),
623        Fsetid("fsetid"),
624        IpcLock("ipc_lock"),
625        IpcOwner("ipc_owner"),
626        Kill("kill"),
627        Lease("lease"),
628        LinuxImmutable("linux_immutable"),
629        Mknod("mknod"),
630        NetAdmin("net_admin"),
631        NetBindService("net_bind_service"),
632        NetBroadcast("net_broadcast"),
633        NetRaw("net_raw"),
634        Setfcap("setfcap"),
635        Setgid("setgid"),
636        Setpcap("setpcap"),
637        Setuid("setuid"),
638        SysAdmin("sys_admin"),
639        SysBoot("sys_boot"),
640        SysChroot("sys_chroot"),
641        SysModule("sys_module"),
642        SysNice("sys_nice"),
643        SysPacct("sys_pacct"),
644        SysPtrace("sys_ptrace"),
645        SysRawio("sys_rawio"),
646        SysResource("sys_resource"),
647        SysTime("sys_time"),
648        SysTtyConfig("sys_tty_config"),
649
650        // keep-sorted end
651    }
652}
653
654class_permission_enum! {
655    /// A well-known "capability" class permission in SELinux policy that has a particular meaning
656    /// in policy enforcement hooks.
657    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
658    CapabilityPermission extends CommonCapPermission {}
659}
660
661impl CommonCapPermission {
662    /// Returns the `class`-affine `KernelPermission` value corresponding to this common permission.
663    /// This is used to allow hooks to resolve e.g. common "sys_nice" permission access based on the
664    /// "allow" rules for the correct target object class.
665    pub fn for_class(&self, class: CapClass) -> KernelPermission {
666        match class {
667            CapClass::Capability => CapabilityPermission::Common(self.clone()).into(),
668        }
669    }
670}
671
672common_permission_enum! {
673    /// Permissions common to all cap2-like object classes (e.g. "capability2" for now and
674    /// "cap2_userns" after Starnix gains user namespacing support). These are combined with a
675    /// specific `Capability2Class` by policy enforcement hooks, to obtain class-affine permission
676    /// values to check.
677    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
678    CommonCap2Permission {
679        // keep-sorted start
680
681        AuditRead("audit_read"),
682        BlockSuspend("block_suspend"),
683        Bpf("bpf"),
684        MacAdmin("mac_admin"),
685        MacOverride("mac_override"),
686        Syslog("syslog"),
687        WakeAlarm("wake_alarm"),
688
689        // keep-sorted end
690    }
691}
692
693class_permission_enum! {
694    /// A well-known "capability2" class permission in SELinux policy that has a particular meaning
695    /// in policy enforcement hooks.
696    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
697    Capability2Permission extends CommonCap2Permission {}
698}
699
700impl CommonCap2Permission {
701    /// Returns the `class`-affine `KernelPermission` value corresponding to this common permission.
702    /// This is used to allow hooks to resolve e.g. common "mac_admin" permission access based on
703    /// the "allow" rules for the correct target object class.
704    pub fn for_class(&self, class: Cap2Class) -> KernelPermission {
705        match class {
706            Cap2Class::Capability2 => Capability2Permission::Common(self.clone()).into(),
707        }
708    }
709}
710
711common_permission_enum! {
712    /// Permissions meaningful for all [`crate::vfs::FsNode`]s, whether file- or socket-like.
713    ///
714    /// This extra layer of common permissions is not reflected in the hierarchy defined by the
715    /// SELinux Reference Policy. Because even common permissions are mapped per-class, by name, to
716    /// the policy equivalents, the implementation and policy notions of common permissions need not
717    /// be identical.
718    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
719    CommonFsNodePermission {
720        // keep-sorted start
721        /// Permission to append to a file or socket.
722        Append("append"),
723        /// Permission to create a file or socket.
724        Create("create"),
725        /// Permission to query attributes, including uid, gid and extended attributes.
726        GetAttr("getattr"),
727        /// Permission to execute ioctls on the file or socket.
728        Ioctl("ioctl"),
729        /// Permission to set and unset file or socket locks.
730        Lock("lock"),
731        /// Permission to map a file.
732        Map("map"),
733        /// Permission to read content from a file or socket, as well as reading or following links.
734        Read("read"),
735        /// Permission checked against the existing label when updating a node's security label.
736        RelabelFrom("relabelfrom"),
737        /// Permission checked against the new label when updating a node's security label.
738        RelabelTo("relabelto"),
739        /// Permission to modify attributes, including uid, gid and extended attributes.
740        SetAttr("setattr"),
741        /// Permission to write contents to the file or socket.
742        Write("write"),
743        // keep-sorted end
744    }
745}
746
747impl CommonFsNodePermission {
748    /// Returns the `class`-affine `KernelPermission` value corresponding to this common permission.
749    /// This is used to allow hooks to resolve e.g. common "read" permission access based on the
750    /// "allow" rules for the correct target object class.
751    pub fn for_class(&self, class: impl Into<FsNodeClass>) -> KernelPermission {
752        match class.into() {
753            FsNodeClass::File(file_class) => {
754                CommonFilePermission::Common(self.clone()).for_class(file_class)
755            }
756            FsNodeClass::Socket(sock_class) => {
757                CommonSocketPermission::Common(self.clone()).for_class(sock_class)
758            }
759        }
760    }
761}
762common_permission_enum! {
763    /// Permissions common to all socket-like object classes. These are combined with a specific
764    /// `SocketClass` by policy enforcement hooks, to obtain class-affine permission values.
765    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
766    CommonSocketPermission extends CommonFsNodePermission {
767        // keep-sorted start
768        /// Permission to bind to a name.
769        Bind("bind"),
770        /// Permission to initiate a connection.
771        Connect("connect"),
772        /// Permission to get socket options.
773        GetOpt("getopt"),
774        /// Permission to listen for connections.
775        Listen("listen"),
776        /// Permission to send datagrams to the socket.
777        SendTo("sendto"),
778        /// Permission to set socket options.
779        SetOpt("setopt"),
780        /// Permission to terminate connection.
781        Shutdown("shutdown"),
782        // keep-sorted end
783    }
784}
785
786impl CommonSocketPermission {
787    /// Returns the `class`-affine `KernelPermission` value corresponding to this common permission.
788    /// This is used to allow hooks to resolve e.g. common "read" permission access based on the
789    /// "allow" rules for the correct target object class.
790    pub fn for_class(&self, class: SocketClass) -> KernelPermission {
791        match class {
792            SocketClass::Key => KeySocketPermission::Common(self.clone()).into(),
793            SocketClass::Netlink => NetlinkSocketPermission::Common(self.clone()).into(),
794            SocketClass::NetlinkAudit => NetlinkAuditSocketPermission::Common(self.clone()).into(),
795            SocketClass::NetlinkConnector => {
796                NetlinkConnectorSocketPermission::Common(self.clone()).into()
797            }
798            SocketClass::NetlinkCrypto => {
799                NetlinkCryptoSocketPermission::Common(self.clone()).into()
800            }
801            SocketClass::NetlinkDnrt => NetlinkDnrtSocketPermission::Common(self.clone()).into(),
802            SocketClass::NetlinkFibLookup => {
803                NetlinkFibLookupSocketPermission::Common(self.clone()).into()
804            }
805            SocketClass::NetlinkFirewall => {
806                NetlinkFirewallSocketPermission::Common(self.clone()).into()
807            }
808            SocketClass::NetlinkGeneric => {
809                NetlinkGenericSocketPermission::Common(self.clone()).into()
810            }
811            SocketClass::NetlinkIp6Fw => NetlinkIp6FwSocketPermission::Common(self.clone()).into(),
812            SocketClass::NetlinkIscsi => NetlinkIscsiSocketPermission::Common(self.clone()).into(),
813            SocketClass::NetlinkKobjectUevent => {
814                NetlinkKobjectUeventSocketPermission::Common(self.clone()).into()
815            }
816            SocketClass::NetlinkNetfilter => {
817                NetlinkNetfilterSocketPermission::Common(self.clone()).into()
818            }
819            SocketClass::NetlinkNflog => NetlinkNflogSocketPermission::Common(self.clone()).into(),
820            SocketClass::NetlinkRdma => NetlinkRdmaSocketPermission::Common(self.clone()).into(),
821            SocketClass::NetlinkRoute => NetlinkRouteSocketPermission::Common(self.clone()).into(),
822            SocketClass::NetlinkScsitransport => {
823                NetlinkScsitransportSocketPermission::Common(self.clone()).into()
824            }
825            SocketClass::NetlinkSelinux => {
826                NetlinkSelinuxSocketPermission::Common(self.clone()).into()
827            }
828            SocketClass::NetlinkTcpDiag => {
829                NetlinkTcpDiagSocketPermission::Common(self.clone()).into()
830            }
831            SocketClass::NetlinkXfrm => NetlinkXfrmSocketPermission::Common(self.clone()).into(),
832            SocketClass::Packet => PacketSocketPermission::Common(self.clone()).into(),
833            SocketClass::RawIp => RawIpSocketPermission::Common(self.clone()).into(),
834            SocketClass::Socket => SocketPermission::Common(self.clone()).into(),
835            SocketClass::Tcp => TcpSocketPermission::Common(self.clone()).into(),
836            SocketClass::Udp => UdpSocketPermission::Common(self.clone()).into(),
837            SocketClass::UnixDgram => UnixDgramSocketPermission::Common(self.clone()).into(),
838            SocketClass::UnixStream => UnixStreamSocketPermission::Common(self.clone()).into(),
839            SocketClass::Vsock => VsockSocketPermission::Common(self.clone()).into(),
840        }
841    }
842}
843
844class_permission_enum! {
845    /// A well-known "key_socket" class permission in SELinux policy that has a particular meaning in
846    /// policy enforcement hooks.
847    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
848    KeySocketPermission extends CommonSocketPermission {
849    }
850}
851class_permission_enum! {
852    /// A well-known "netlink_socket" class permission in SELinux policy that has a particular meaning in
853    /// policy enforcement hooks.
854    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
855    NetlinkSocketPermission extends CommonSocketPermission {
856    }
857}
858
859class_permission_enum! {
860    /// A well-known "netlink_route_socket" class permission in SELinux policy that has a particular meaning in
861    /// policy enforcement hooks.
862    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
863    NetlinkRouteSocketPermission extends CommonSocketPermission {
864    }
865}
866
867class_permission_enum! {
868    /// A well-known "netlink_firewall_socket" class permission in SELinux policy that has a particular meaning in
869    /// policy enforcement hooks.
870    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
871    NetlinkFirewallSocketPermission extends CommonSocketPermission {
872    }
873}
874
875class_permission_enum! {
876    /// A well-known "netlink_tcpdiag_socket" class permission in SELinux policy that has a particular meaning in
877    /// policy enforcement hooks.
878    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
879    NetlinkTcpDiagSocketPermission extends CommonSocketPermission {
880    }
881}
882
883class_permission_enum! {
884    /// A well-known "netlink_nflog_socket" class permission in SELinux policy that has a particular meaning in
885    /// policy enforcement hooks.
886    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
887    NetlinkNflogSocketPermission extends CommonSocketPermission {
888    }
889}
890
891class_permission_enum! {
892    /// A well-known "netlink_xfrm_socket" class permission in SELinux policy that has a particular meaning in
893    /// policy enforcement hooks.
894    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
895    NetlinkXfrmSocketPermission extends CommonSocketPermission {
896    }
897}
898
899class_permission_enum! {
900    /// A well-known "netlink_selinux_socket" class permission in SELinux policy that has a particular meaning in
901    /// policy enforcement hooks.
902    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
903    NetlinkSelinuxSocketPermission extends CommonSocketPermission {
904    }
905}
906
907class_permission_enum! {
908    /// A well-known "netlink_iscsi_socket" class permission in SELinux policy that has a particular meaning in
909    /// policy enforcement hooks.
910    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
911    NetlinkIscsiSocketPermission extends CommonSocketPermission {
912    }
913}
914
915class_permission_enum! {
916    /// A well-known "netlink_audit_socket" class permission in SELinux policy that has a particular meaning in
917    /// policy enforcement hooks.
918    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
919    NetlinkAuditSocketPermission extends CommonSocketPermission {
920    }
921}
922
923class_permission_enum! {
924    /// A well-known "netlink_fib_lookup_socket" class permission in SELinux policy that has a particular meaning in
925    /// policy enforcement hooks.
926    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
927    NetlinkFibLookupSocketPermission extends CommonSocketPermission {
928    }
929}
930
931class_permission_enum! {
932    /// A well-known "netlink_connector_socket" class permission in SELinux policy that has a particular meaning in
933    /// policy enforcement hooks.
934    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
935    NetlinkConnectorSocketPermission extends CommonSocketPermission {
936    }
937}
938
939class_permission_enum! {
940    /// A well-known "netlink_netfilter_socket" class permission in SELinux policy that has a particular meaning in
941    /// policy enforcement hooks.
942    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
943    NetlinkNetfilterSocketPermission extends CommonSocketPermission {
944    }
945}
946
947class_permission_enum! {
948    /// A well-known "netlink_ip6fw_socket" class permission in SELinux policy that has a particular meaning in
949    /// policy enforcement hooks.
950    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
951    NetlinkIp6FwSocketPermission extends CommonSocketPermission {
952    }
953}
954
955class_permission_enum! {
956    /// A well-known "netlink_dnrt_socket" class permission in SELinux policy that has a particular meaning in
957    /// policy enforcement hooks.
958    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
959    NetlinkDnrtSocketPermission extends CommonSocketPermission {
960    }
961}
962
963class_permission_enum! {
964    /// A well-known "netlink_kobject_uevent_socket" class permission in SELinux policy that has a particular meaning in
965    /// policy enforcement hooks.
966    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
967    NetlinkKobjectUeventSocketPermission extends CommonSocketPermission {
968    }
969}
970
971class_permission_enum! {
972    /// A well-known "netlink_generic_socket" class permission in SELinux policy that has a particular meaning in
973    /// policy enforcement hooks.
974    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
975    NetlinkGenericSocketPermission extends CommonSocketPermission {
976    }
977}
978
979class_permission_enum! {
980    /// A well-known "netlink_scsitransport_socket" class permission in SELinux policy that has a particular meaning in
981    /// policy enforcement hooks.
982    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
983    NetlinkScsitransportSocketPermission extends CommonSocketPermission {
984    }
985}
986
987class_permission_enum! {
988    /// A well-known "netlink_rdma_socket" class permission in SELinux policy that has a particular meaning in
989    /// policy enforcement hooks.
990    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
991    NetlinkRdmaSocketPermission extends CommonSocketPermission {
992    }
993}
994
995class_permission_enum! {
996    /// A well-known "netlink_crypto_socket" class permission in SELinux policy that has a particular meaning in
997    /// policy enforcement hooks.
998    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
999    NetlinkCryptoSocketPermission extends CommonSocketPermission {
1000    }
1001}
1002
1003class_permission_enum! {
1004    /// A well-known "packet_socket" class permission in SELinux policy that has a particular meaning in
1005    /// policy enforcement hooks.
1006    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1007    PacketSocketPermission extends CommonSocketPermission {
1008    }
1009}
1010
1011class_permission_enum! {
1012    /// A well-known "rawip_socket" class permission in SELinux policy that has a particular meaning in
1013    /// policy enforcement hooks.
1014    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1015    RawIpSocketPermission extends CommonSocketPermission {
1016    }
1017}
1018
1019class_permission_enum! {
1020    /// A well-known "socket" class permission in SELinux policy that has a particular meaning in
1021    /// policy enforcement hooks.
1022    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1023    SocketPermission extends CommonSocketPermission {
1024    }
1025}
1026
1027class_permission_enum! {
1028    /// A well-known "tcp_socket" class permission in SELinux policy that has a particular meaning in
1029    /// policy enforcement hooks.
1030    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1031    TcpSocketPermission extends CommonSocketPermission {
1032    }
1033}
1034
1035class_permission_enum! {
1036    /// A well-known "udp_socket" class permission in SELinux policy that has a particular meaning in
1037    /// policy enforcement hooks.
1038    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1039    UdpSocketPermission extends CommonSocketPermission {
1040    }
1041}
1042
1043class_permission_enum! {
1044    /// A well-known "unix_stream_socket" class permission in SELinux policy that has a particular meaning in
1045    /// policy enforcement hooks.
1046    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1047    UnixStreamSocketPermission extends CommonSocketPermission {
1048        // keep-sorted start
1049        /// Permission to connect a streaming Unix-domain socket.
1050        ConnectTo("connectto"),
1051        // keep-sorted end
1052    }
1053}
1054
1055class_permission_enum! {
1056    /// A well-known "unix_dgram_socket" class permission in SELinux policy that has a particular meaning in
1057    /// policy enforcement hooks.
1058    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1059    UnixDgramSocketPermission extends CommonSocketPermission {
1060    }
1061}
1062
1063class_permission_enum! {
1064    /// A well-known "vsock_socket" class permission in SELinux policy that has a particular meaning in
1065    /// policy enforcement hooks.
1066    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1067    VsockSocketPermission extends CommonSocketPermission {
1068    }
1069}
1070
1071common_permission_enum! {
1072    /// Permissions common to all file-like object classes (e.g. "lnk_file", "dir"). These are
1073    /// combined with a specific `FileClass` by policy enforcement hooks, to obtain class-affine
1074    /// permission values to check.
1075    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1076    CommonFilePermission extends CommonFsNodePermission {
1077        // keep-sorted start
1078        /// Permission to execute a file with domain transition.
1079        Execute("execute"),
1080        /// Permissions to create hard link.
1081        Link("link"),
1082        /// Permission to use as mount point; only useful for directories and files.
1083        MountOn("mounton"),
1084        /// Permission to open a file.
1085        Open("open"),
1086        /// Permission to rename a file.
1087        Rename("rename"),
1088        /// Permission to delete a file or remove a hard link.
1089        Unlink("unlink"),
1090        // keep-sorted end
1091    }
1092}
1093
1094impl CommonFilePermission {
1095    /// Returns the `class`-affine `KernelPermission` value corresponding to this common permission.
1096    /// This is used to allow hooks to resolve e.g. common "read" permission access based on the
1097    /// "allow" rules for the correct target object class.
1098    pub fn for_class(&self, class: FileClass) -> KernelPermission {
1099        match class {
1100            FileClass::AnonFsNode => AnonFsNodePermission::Common(self.clone()).into(),
1101            FileClass::Block => BlockFilePermission::Common(self.clone()).into(),
1102            FileClass::Character => CharacterFilePermission::Common(self.clone()).into(),
1103            FileClass::Dir => DirPermission::Common(self.clone()).into(),
1104            FileClass::Fifo => FifoFilePermission::Common(self.clone()).into(),
1105            FileClass::File => FilePermission::Common(self.clone()).into(),
1106            FileClass::Link => LinkFilePermission::Common(self.clone()).into(),
1107            FileClass::SockFile => SockFilePermission::Common(self.clone()).into(),
1108        }
1109    }
1110}
1111
1112class_permission_enum! {
1113    /// A well-known "anon_file" class permission used to manage special file-like nodes not linked
1114    /// into any directory structures.
1115    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1116    AnonFsNodePermission extends CommonFilePermission {
1117    }
1118}
1119
1120class_permission_enum! {
1121    /// A well-known "blk_file" class permission in SELinux policy that has a particular meaning in
1122    /// policy enforcement hooks.
1123    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1124    BlockFilePermission extends CommonFilePermission {
1125    }
1126}
1127
1128class_permission_enum! {
1129    /// A well-known "chr_file" class permission in SELinux policy that has a particular meaning in
1130    /// policy enforcement hooks.
1131    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1132    CharacterFilePermission extends CommonFilePermission {
1133    }
1134}
1135
1136class_permission_enum! {
1137    /// A well-known "dir" class permission in SELinux policy that has a particular meaning in
1138    /// policy enforcement hooks.
1139    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1140    DirPermission extends CommonFilePermission {
1141        // keep-sorted start
1142        /// Permission to add a file to the directory.
1143        AddName("add_name"),
1144        /// Permission to remove a directory.
1145        RemoveDir("rmdir"),
1146        /// Permission to remove an entry from a directory.
1147        RemoveName("remove_name"),
1148        /// Permission to change parent directory.
1149        Reparent("reparent"),
1150        /// Search access to the directory.
1151        Search("search"),
1152        // keep-sorted end
1153    }
1154}
1155
1156class_permission_enum! {
1157    /// A well-known "fd" class permission in SELinux policy that has a particular meaning in policy
1158    /// enforcement hooks.
1159    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1160    FdPermission {
1161        // keep-sorted start
1162        /// Permission to use file descriptors copied/retained/inherited from another security
1163        /// context. This permission is generally used to control whether an `exec*()` call from a
1164        /// cloned process that retained a copy of the file descriptor table should succeed.
1165        Use("use"),
1166        // keep-sorted end
1167    }
1168}
1169
1170class_permission_enum! {
1171    /// A well-known "bpf" class permission in SELinux policy that has a particular meaning in
1172    /// policy enforcement hooks.
1173    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1174    BpfPermission {
1175        // keep-sorted start
1176        /// Permission to create a map.
1177        MapCreate("map_create"),
1178        /// Permission to read from a map.
1179        MapRead("map_read"),
1180        /// Permission to write on a map.
1181        MapWrite("map_write"),
1182        /// Permission to load a program.
1183        ProgLoad("prog_load"),
1184        /// Permission to run a program.
1185        ProgRun("prog_run"),
1186        // keep-sorted end
1187    }
1188}
1189
1190class_permission_enum! {
1191    /// A well-known "fifo_file" class permission in SELinux policy that has a particular meaning in
1192    /// policy enforcement hooks.
1193    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1194    FifoFilePermission extends CommonFilePermission {
1195    }
1196}
1197
1198class_permission_enum! {
1199    /// A well-known "file" class permission in SELinux policy that has a particular meaning in
1200    /// policy enforcement hooks.
1201    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1202    FilePermission extends CommonFilePermission {
1203        // keep-sorted start
1204        /// Permission to use a file as an entry point into the new domain on transition.
1205        Entrypoint("entrypoint"),
1206        /// Permission to use a file as an entry point to the calling domain without performing a
1207        /// transition.
1208        ExecuteNoTrans("execute_no_trans"),
1209        // keep-sorted end
1210    }
1211}
1212
1213class_permission_enum! {
1214    /// A well-known "filesystem" class permission in SELinux policy that has a particular meaning in
1215    /// policy enforcement hooks.
1216    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1217    FileSystemPermission {
1218        // keep-sorted start
1219        /// Permission to associate a file to the filesystem.
1220        Associate("associate"),
1221        /// Permission to get filesystem attributes.
1222        GetAttr("getattr"),
1223        /// Permission mount a filesystem.
1224        Mount("mount"),
1225        /// Permission to remount a filesystem with different flags.
1226        Remount("remount"),
1227        /// Permission to unmount a filesystem.
1228        Unmount("unmount"),
1229        // keep-sorted end
1230    }
1231}
1232
1233class_permission_enum! {
1234    /// A well-known "lnk_file" class permission in SELinux policy that has a particular meaning in
1235    /// policy enforcement hooks.
1236    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1237    LinkFilePermission extends CommonFilePermission {
1238    }
1239}
1240
1241class_permission_enum! {
1242    /// A well-known "sock_file" class permission in SELinux policy that has a particular meaning in
1243    /// policy enforcement hooks.
1244    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1245    SockFilePermission extends CommonFilePermission {
1246    }
1247}
1248
1249class_permission_enum! {
1250    /// A well-known "process" class permission in SELinux policy that has a particular meaning in
1251    /// policy enforcement hooks.
1252    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1253    ProcessPermission {
1254        // keep-sorted start
1255        /// Permission to dynamically transition a process to a different security domain.
1256        DynTransition("dyntransition"),
1257        /// Permission to execute arbitrary code from memory.
1258        ExecMem("execmem"),
1259        /// Permission to fork the current running process.
1260        Fork("fork"),
1261        /// Permission to get the process group ID.
1262        GetPgid("getpgid"),
1263        /// Permission to get the resource limits on a process.
1264        GetRlimit("getrlimit"),
1265        /// Permission to get scheduling policy currently applied to a process.
1266        GetSched("getsched"),
1267        /// Permission to get the session ID.
1268        GetSession("getsession"),
1269        /// Permission to trace a process.
1270        Ptrace("ptrace"),
1271        /// Permission to inherit the parent process's resource limits on exec.
1272        RlimitInh("rlimitinh"),
1273        /// Permission to set the calling task's current Security Context.
1274        /// The "dyntransition" permission separately limits which Contexts "setcurrent" may be used to transition to.
1275        SetCurrent("setcurrent"),
1276        /// Permission to set the Security Context used by `exec()`.
1277        SetExec("setexec"),
1278        /// Permission to set the Security Context used when creating filesystem objects.
1279        SetFsCreate("setfscreate"),
1280        /// Permission to set the Security Context used when creating kernel keyrings.
1281        SetKeyCreate("setkeycreate"),
1282        /// Permission to set the process group ID.
1283        SetPgid("setpgid"),
1284        /// Permission to set the resource limits on a process.
1285        SetRlimit("setrlimit"),
1286        /// Permission to set scheduling policy for a process.
1287        SetSched("setsched"),
1288        /// Permission to set the Security Context used when creating new labeled sockets.
1289        SetSockCreate("setsockcreate"),
1290        /// Permission to share resources (e.g. FD table, address-space, etc) with a process.
1291        Share("share"),
1292        /// Permission to send SIGCHLD to a process.
1293        SigChld("sigchld"),
1294        /// Permission to send SIGKILL to a process.
1295        SigKill("sigkill"),
1296        /// Permission to send SIGSTOP to a process.
1297        SigStop("sigstop"),
1298        /// Permission to send a signal other than SIGKILL, SIGSTOP, or SIGCHLD to a process.
1299        Signal("signal"),
1300        /// Permission to transition to a different security domain.
1301        Transition("transition"),
1302        // keep-sorted end
1303    }
1304}
1305
1306class_permission_enum! {
1307    /// A well-known "security" class permission in SELinux policy, used to control access to
1308    /// sensitive administrative and query API surfaces in the "selinuxfs".
1309    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1310    SecurityPermission {
1311        // keep-sorted start
1312        /// Permission to validate Security Context using the "context" API.
1313        CheckContext("check_context"),
1314        /// Permission to compute access vectors via the "access" API.
1315        ComputeAv("compute_av"),
1316        /// Permission to compute security contexts based on `type_transition` rules via "create".
1317        ComputeCreate("compute_create"),
1318        /// Permission to compute security contexts based on `type_member` rules via "member".
1319        ComputeMember("compute_member"),
1320        /// Permission to compute security contexts based on `type_change` rules via "relabel".
1321        ComputeRelabel("compute_relabel"),
1322        /// Permission to compute user decisions via "user".
1323        ComputeUser("compute_user"),
1324        /// Permission to load a new binary policy into the kernel via the "load" API.
1325        LoadPolicy("load_policy"),
1326        /// Permission to commit booleans to control conditional elements of the policy.
1327        SetBool("setbool"),
1328        /// Permission to change the way permissions are validated for `mmap()` operations.
1329        SetCheckReqProt("setcheckreqprot"),
1330        /// Permission to switch the system between permissive and enforcing modes, via "enforce".
1331        SetEnforce("setenforce"),
1332        // keep-sorted end
1333     }
1334}
1335
1336/// Initial Security Identifier (SID) values defined by the SELinux Reference Policy.
1337/// Where the SELinux Reference Policy retains definitions for some deprecated initial SIDs, this
1338/// enum omits deprecated entries for clarity.
1339#[repr(u64)]
1340enum ReferenceInitialSid {
1341    Kernel = 1,
1342    Security = 2,
1343    Unlabeled = 3,
1344    _Fs = 4,
1345    File = 5,
1346    _AnySocket = 6,
1347    _Port = 7,
1348    _Netif = 8,
1349    _Netmsg = 9,
1350    _Node = 10,
1351    _Sysctl = 15,
1352    _Devnull = 25,
1353
1354    FirstUnused,
1355}
1356
1357/// Lowest Security Identifier value guaranteed not to be used by this
1358/// implementation to refer to an initial Security Context.
1359pub const FIRST_UNUSED_SID: u32 = ReferenceInitialSid::FirstUnused as u32;
1360
1361macro_rules! initial_sid_enum {
1362    ($(#[$meta:meta])* $name:ident {
1363        $($(#[$variant_meta:meta])* $variant:ident ($variant_name: literal)),*,
1364    }) => {
1365        $(#[$meta])*
1366        pub enum $name {
1367            $($(#[$variant_meta])* $variant = ReferenceInitialSid::$variant as isize),*
1368        }
1369
1370        impl $name {
1371            pub fn all_variants() -> Vec<Self> {
1372                vec![
1373                    $($name::$variant),*
1374                ]
1375            }
1376
1377            pub fn name(&self) -> &'static str {
1378                match self {
1379                    $($name::$variant => $variant_name),*
1380                }
1381            }
1382        }
1383    }
1384}
1385
1386initial_sid_enum! {
1387/// Initial Security Identifier (SID) values actually used by this implementation.
1388/// These must be present in the policy, for it to be valid.
1389#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
1390    InitialSid {
1391        // keep-sorted start
1392        File("file"),
1393        Kernel("kernel"),
1394        Security("security"),
1395        Unlabeled("unlabeled"),
1396        // keep-sorted end
1397    }
1398}
1399
1400/// A borrowed byte slice that contains no `NUL` characters by truncating the input slice at the
1401/// first `NUL` (if any) upon construction.
1402#[derive(Clone, Copy, Debug, PartialEq)]
1403pub struct NullessByteStr<'a>(&'a [u8]);
1404
1405impl<'a> NullessByteStr<'a> {
1406    /// Returns a non-null-terminated representation of the security context string.
1407    pub fn as_bytes(&self) -> &[u8] {
1408        &self.0
1409    }
1410}
1411
1412impl<'a, S: AsRef<[u8]> + ?Sized> From<&'a S> for NullessByteStr<'a> {
1413    /// Any `AsRef<[u8]>` can be processed into a [`NullessByteStr`]. The [`NullessByteStr`] will
1414    /// retain everything up to (but not including) a null character, or else the complete byte
1415    /// string.
1416    fn from(s: &'a S) -> Self {
1417        let value = s.as_ref();
1418        match value.iter().position(|c| *c == 0) {
1419            Some(end) => Self(&value[..end]),
1420            None => Self(value),
1421        }
1422    }
1423}
1424
1425#[derive(Clone, Debug, PartialEq)]
1426pub struct FileSystemMountSids {
1427    pub context: Option<SecurityId>,
1428    pub fs_context: Option<SecurityId>,
1429    pub def_context: Option<SecurityId>,
1430    pub root_context: Option<SecurityId>,
1431}
1432
1433#[derive(Clone, Debug, PartialEq)]
1434pub struct FileSystemLabel {
1435    pub sid: SecurityId,
1436    pub scheme: FileSystemLabelingScheme,
1437    // Sids obtained by parsing the mount options of the FileSystem.
1438    pub mount_sids: FileSystemMountSids,
1439}
1440
1441#[derive(Clone, Debug, PartialEq)]
1442pub enum FileSystemLabelingScheme {
1443    /// This filesystem was mounted with "context=".
1444    Mountpoint { sid: SecurityId },
1445    /// This filesystem has an "fs_use_xattr", "fs_use_task", or "fs_use_trans" entry in the
1446    /// policy. `root_sid` identifies the context for the root of the filesystem and
1447    /// `computed_def_sid`  identifies the context to use for unlabeled files in the filesystem
1448    /// (the "default context").
1449    FsUse { fs_use_type: FsUseType, computed_def_sid: SecurityId },
1450    /// This filesystem has one or more "genfscon" statements associated with it in the policy.
1451    GenFsCon,
1452}
1453
1454/// SELinux security context-related filesystem mount options. These options are documented in the
1455/// `context=context, fscontext=context, defcontext=context, and rootcontext=context` section of
1456/// the `mount(8)` manpage.
1457#[derive(Clone, Debug, Default, PartialEq)]
1458pub struct FileSystemMountOptions {
1459    /// Specifies the effective security context to use for all nodes in the filesystem, and the
1460    /// filesystem itself. If the filesystem already contains security attributes then these are
1461    /// ignored. May not be combined with any of the other options.
1462    pub context: Option<Vec<u8>>,
1463    /// Specifies an effective security context to use for un-labeled nodes in the filesystem,
1464    /// rather than falling-back to the policy-defined "file" context.
1465    pub def_context: Option<Vec<u8>>,
1466    /// The value of the `fscontext=[security-context]` mount option. This option is used to
1467    /// label the filesystem (superblock) itself.
1468    pub fs_context: Option<Vec<u8>>,
1469    /// The value of the `rootcontext=[security-context]` mount option. This option is used to
1470    /// (re)label the inode located at the filesystem mountpoint.
1471    pub root_context: Option<Vec<u8>>,
1472}
1473
1474/// Status information parameter for the [`SeLinuxStatusPublisher`] interface.
1475pub struct SeLinuxStatus {
1476    /// SELinux-wide enforcing vs. permissive mode  bit.
1477    pub is_enforcing: bool,
1478    /// Number of times the policy has been changed since SELinux started.
1479    pub change_count: u32,
1480    /// Bit indicating whether operations unknown SELinux abstractions will be denied.
1481    pub deny_unknown: bool,
1482}
1483
1484/// Interface for security server to interact with selinuxfs status file.
1485pub trait SeLinuxStatusPublisher: Send {
1486    /// Sets the value part of the associated selinuxfs status file.
1487    fn set_status(&mut self, policy_status: SeLinuxStatus);
1488}
1489
1490#[cfg(test)]
1491mod tests {
1492    use super::*;
1493
1494    #[test]
1495    fn object_class_permissions() {
1496        let test_class_id = ClassId::new(NonZeroU32::new(20).unwrap());
1497        assert_eq!(ObjectClass::ClassId(test_class_id), test_class_id.into());
1498        for variant in ProcessPermission::all_variants().into_iter() {
1499            assert_eq!(KernelClass::Process, variant.class());
1500            assert_eq!("process", variant.class().name());
1501            let permission: KernelPermission = variant.clone().into();
1502            assert_eq!(KernelPermission::Process(variant.clone()), permission);
1503            assert_eq!(ObjectClass::Kernel(KernelClass::Process), variant.class().into());
1504        }
1505    }
1506
1507    #[test]
1508    fn nulless_byte_str_equivalence() {
1509        let unterminated: NullessByteStr<'_> = b"u:object_r:test_valid_t:s0".into();
1510        let nul_terminated: NullessByteStr<'_> = b"u:object_r:test_valid_t:s0\0".into();
1511        let nul_containing: NullessByteStr<'_> =
1512            b"u:object_r:test_valid_t:s0\0IGNORE THIS\0!\0".into();
1513
1514        for context in [nul_terminated, nul_containing] {
1515            assert_eq!(unterminated, context);
1516            assert_eq!(unterminated.as_bytes(), context.as_bytes());
1517        }
1518    }
1519}