Skip to main content

starnix_uapi/
auth.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#![allow(dead_code)]
6
7use crate::errors::{Errno, error};
8use crate::selinux::TaskAttrs;
9use crate::{gid_t, uapi, uid_t};
10use bitflags::bitflags;
11use std::ops;
12use std::sync::{Arc, LazyLock};
13
14// We don't use bitflags for this because capability sets can have bits set that don't have defined
15// meaning as capabilities. init has all 64 bits set, even though only 40 of them are valid.
16#[derive(Clone, Copy, Eq, PartialEq)]
17pub struct Capabilities {
18    mask: u64,
19}
20
21impl Capabilities {
22    pub const fn empty() -> Self {
23        Self { mask: 0 }
24    }
25
26    pub const fn all() -> Self {
27        const fn make_mask(cap: u32) -> u64 {
28            let mask = if cap > 0 { make_mask(cap - 1) << 1 } else { 0u64 };
29            mask | 1u64
30        }
31        const ALL_CAPS_MASK: u64 = make_mask(CAP_LAST_CAP);
32        Self { mask: ALL_CAPS_MASK }
33    }
34
35    pub fn union(&self, caps: Capabilities) -> Self {
36        let mut new_caps = *self;
37        new_caps.insert(caps);
38        new_caps
39    }
40
41    pub fn difference(&self, caps: Capabilities) -> Self {
42        let mut new_caps = *self;
43        new_caps.remove(caps);
44        new_caps
45    }
46
47    pub fn contains(self, caps: Capabilities) -> bool {
48        (self & caps) == caps
49    }
50
51    pub fn insert(&mut self, caps: Capabilities) {
52        *self |= caps;
53    }
54
55    pub fn remove(&mut self, caps: Capabilities) {
56        *self &= !caps;
57    }
58
59    pub const fn as_abi_v1(self) -> u32 {
60        self.mask as u32
61    }
62
63    pub fn from_abi_v1(bits: u32) -> Self {
64        Self { mask: bits as u64 } & Self::all()
65    }
66
67    pub const fn as_abi_v3(self) -> (u32, u32) {
68        (self.mask as u32, (self.mask >> 32) as u32)
69    }
70
71    pub fn from_abi_v3(u32s: (u32, u32)) -> Self {
72        Self { mask: u32s.0 as u64 | ((u32s.1 as u64) << 32) } & Self::all()
73    }
74}
75
76impl std::convert::TryFrom<u64> for Capabilities {
77    type Error = Errno;
78
79    fn try_from(capability_num: u64) -> Result<Self, Self::Error> {
80        match 1u64.checked_shl(capability_num as u32) {
81            Some(mask) => Ok(Self { mask }),
82            _ => error!(EINVAL),
83        }
84    }
85}
86
87impl ops::BitAnd for Capabilities {
88    type Output = Self;
89
90    // rhs is the "right-hand side" of the expression `a & b`
91    fn bitand(self, rhs: Self) -> Self::Output {
92        Self { mask: self.mask & rhs.mask }
93    }
94}
95
96impl ops::BitAndAssign for Capabilities {
97    // rhs is the "right-hand side" of the expression `a & b`
98    fn bitand_assign(&mut self, rhs: Self) {
99        self.mask &= rhs.mask;
100    }
101}
102
103impl ops::BitOr for Capabilities {
104    type Output = Self;
105
106    fn bitor(self, rhs: Self) -> Self::Output {
107        Self { mask: self.mask | rhs.mask }
108    }
109}
110
111impl ops::BitOrAssign for Capabilities {
112    fn bitor_assign(&mut self, rhs: Self) {
113        self.mask |= rhs.mask;
114    }
115}
116
117impl ops::Not for Capabilities {
118    type Output = Self;
119
120    fn not(self) -> Self::Output {
121        Self { mask: !self.mask }
122    }
123}
124
125impl std::fmt::Debug for Capabilities {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
127        write!(f, "Capabilities({:#x})", self.mask)
128    }
129}
130
131impl std::fmt::LowerHex for Capabilities {
132    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
133        std::fmt::LowerHex::fmt(&self.mask, f)
134    }
135}
136
137impl std::str::FromStr for Capabilities {
138    type Err = Errno;
139    fn from_str(s: &str) -> Result<Self, Self::Err> {
140        Ok(match s {
141            "CHOWN" => CAP_CHOWN,
142            "DAC_OVERRIDE" => CAP_DAC_OVERRIDE,
143            "DAC_READ_SEARCH" => CAP_DAC_READ_SEARCH,
144            "FOWNER" => CAP_FOWNER,
145            "FSETID" => CAP_FSETID,
146            "KILL" => CAP_KILL,
147            "SETGID" => CAP_SETGID,
148            "SETUID" => CAP_SETUID,
149            "SETPCAP" => CAP_SETPCAP,
150            "LINUX_IMMUTABLE" => CAP_LINUX_IMMUTABLE,
151            "NET_BIND_SERVICE" => CAP_NET_BIND_SERVICE,
152            "NET_BROADCAST" => CAP_NET_BROADCAST,
153            "NET_ADMIN" => CAP_NET_ADMIN,
154            "NET_RAW" => CAP_NET_RAW,
155            "IPC_LOCK" => CAP_IPC_LOCK,
156            "IPC_OWNER" => CAP_IPC_OWNER,
157            "SYS_MODULE" => CAP_SYS_MODULE,
158            "SYS_RAWIO" => CAP_SYS_RAWIO,
159            "SYS_CHROOT" => CAP_SYS_CHROOT,
160            "SYS_PTRACE" => CAP_SYS_PTRACE,
161            "SYS_PACCT" => CAP_SYS_PACCT,
162            "SYS_ADMIN" => CAP_SYS_ADMIN,
163            "SYS_BOOT" => CAP_SYS_BOOT,
164            "SYS_NICE" => CAP_SYS_NICE,
165            "SYS_RESOURCE" => CAP_SYS_RESOURCE,
166            "SYS_TIME" => CAP_SYS_TIME,
167            "SYS_TTY_CONFIG" => CAP_SYS_TTY_CONFIG,
168            "MKNOD" => CAP_MKNOD,
169            "LEASE" => CAP_LEASE,
170            "AUDIT_WRITE" => CAP_AUDIT_WRITE,
171            "AUDIT_CONTROL" => CAP_AUDIT_CONTROL,
172            "SETFCAP" => CAP_SETFCAP,
173            "MAC_OVERRIDE" => CAP_MAC_OVERRIDE,
174            "MAC_ADMIN" => CAP_MAC_ADMIN,
175            "SYSLOG" => CAP_SYSLOG,
176            "WAKE_ALARM" => CAP_WAKE_ALARM,
177            "BLOCK_SUSPEND" => CAP_BLOCK_SUSPEND,
178            "AUDIT_READ" => CAP_AUDIT_READ,
179            "PERFMON" => CAP_PERFMON,
180            "BPF" => CAP_BPF,
181            "CHECKPOINT_RESTORE" => CAP_CHECKPOINT_RESTORE,
182            _ => return error!(EINVAL),
183        })
184    }
185}
186
187pub const CAP_CHOWN: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_CHOWN };
188pub const CAP_DAC_OVERRIDE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_DAC_OVERRIDE };
189pub const CAP_DAC_READ_SEARCH: Capabilities =
190    Capabilities { mask: 1u64 << uapi::CAP_DAC_READ_SEARCH };
191pub const CAP_FOWNER: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_FOWNER };
192pub const CAP_FSETID: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_FSETID };
193pub const CAP_KILL: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_KILL };
194pub const CAP_SETGID: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SETGID };
195pub const CAP_SETUID: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SETUID };
196pub const CAP_SETPCAP: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SETPCAP };
197pub const CAP_LINUX_IMMUTABLE: Capabilities =
198    Capabilities { mask: 1u64 << uapi::CAP_LINUX_IMMUTABLE };
199pub const CAP_NET_BIND_SERVICE: Capabilities =
200    Capabilities { mask: 1u64 << uapi::CAP_NET_BIND_SERVICE };
201pub const CAP_NET_BROADCAST: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_NET_BROADCAST };
202pub const CAP_NET_ADMIN: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_NET_ADMIN };
203pub const CAP_NET_RAW: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_NET_RAW };
204pub const CAP_IPC_LOCK: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_IPC_LOCK };
205pub const CAP_IPC_OWNER: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_IPC_OWNER };
206pub const CAP_SYS_MODULE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_MODULE };
207pub const CAP_SYS_RAWIO: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_RAWIO };
208pub const CAP_SYS_CHROOT: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_CHROOT };
209pub const CAP_SYS_PTRACE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_PTRACE };
210pub const CAP_SYS_PACCT: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_PACCT };
211pub const CAP_SYS_ADMIN: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_ADMIN };
212pub const CAP_SYS_BOOT: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_BOOT };
213pub const CAP_SYS_NICE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_NICE };
214pub const CAP_SYS_RESOURCE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_RESOURCE };
215pub const CAP_SYS_TIME: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_TIME };
216pub const CAP_SYS_TTY_CONFIG: Capabilities =
217    Capabilities { mask: 1u64 << uapi::CAP_SYS_TTY_CONFIG };
218pub const CAP_MKNOD: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_MKNOD };
219pub const CAP_LEASE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_LEASE };
220pub const CAP_AUDIT_WRITE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_AUDIT_WRITE };
221pub const CAP_AUDIT_CONTROL: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_AUDIT_CONTROL };
222pub const CAP_SETFCAP: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SETFCAP };
223pub const CAP_MAC_OVERRIDE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_MAC_OVERRIDE };
224pub const CAP_MAC_ADMIN: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_MAC_ADMIN };
225pub const CAP_SYSLOG: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYSLOG };
226pub const CAP_WAKE_ALARM: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_WAKE_ALARM };
227pub const CAP_BLOCK_SUSPEND: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_BLOCK_SUSPEND };
228pub const CAP_AUDIT_READ: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_AUDIT_READ };
229pub const CAP_PERFMON: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_PERFMON };
230pub const CAP_BPF: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_BPF };
231pub const CAP_CHECKPOINT_RESTORE: Capabilities =
232    Capabilities { mask: 1u64 << uapi::CAP_CHECKPOINT_RESTORE };
233pub const CAP_LAST_CAP: u32 = uapi::CAP_LAST_CAP;
234
235bitflags! {
236    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
237    pub struct PtraceAccessMode: u32 {
238        const READ      = 1 << 0;
239        const ATTACH    = 1 << 1;
240        const FSCREDS   = 1 << 2;
241        const REALCREDS = 1 << 3;
242        const NOAUDIT   = 1 << 4;
243    }
244}
245
246pub const PTRACE_MODE_READ: PtraceAccessMode = PtraceAccessMode::READ;
247pub const PTRACE_MODE_ATTACH: PtraceAccessMode = PtraceAccessMode::ATTACH;
248pub const PTRACE_MODE_FSCREDS: PtraceAccessMode = PtraceAccessMode::FSCREDS;
249pub const PTRACE_MODE_REALCREDS: PtraceAccessMode = PtraceAccessMode::REALCREDS;
250pub const PTRACE_MODE_READ_FSCREDS: PtraceAccessMode = PtraceAccessMode::from_bits_truncate(
251    PtraceAccessMode::READ.bits() | PtraceAccessMode::FSCREDS.bits(),
252);
253pub const PTRACE_MODE_READ_REALCREDS: PtraceAccessMode = PtraceAccessMode::from_bits_truncate(
254    PtraceAccessMode::READ.bits() | PtraceAccessMode::REALCREDS.bits(),
255);
256pub const PTRACE_MODE_ATTACH_FSCREDS: PtraceAccessMode = PtraceAccessMode::from_bits_truncate(
257    PtraceAccessMode::ATTACH.bits() | PtraceAccessMode::FSCREDS.bits(),
258);
259pub const PTRACE_MODE_ATTACH_REALCREDS: PtraceAccessMode = PtraceAccessMode::from_bits_truncate(
260    PtraceAccessMode::ATTACH.bits() | PtraceAccessMode::REALCREDS.bits(),
261);
262pub const PTRACE_MODE_NOAUDIT: PtraceAccessMode = PtraceAccessMode::NOAUDIT;
263
264#[derive(Debug, Clone)]
265pub struct Credentials {
266    pub uid: uid_t,
267    pub gid: gid_t,
268    pub euid: uid_t,
269    pub egid: gid_t,
270    pub saved_uid: uid_t,
271    pub saved_gid: gid_t,
272    pub groups: Vec<gid_t>,
273
274    /// See https://man7.org/linux/man-pages/man2/setfsuid.2.html
275    pub fsuid: uid_t,
276
277    /// See https://man7.org/linux/man-pages/man2/setfsgid.2.html
278    pub fsgid: gid_t,
279
280    /// From https://man7.org/linux/man-pages/man7/capabilities.7.html
281    ///
282    /// > This is a limiting superset for the effective capabilities that the thread may assume. It
283    /// > is also a limiting superset for the capabilities that may be added to the inheritable set
284    /// > by a thread that does not have the CAP_SETPCAP capability in its effective set.
285    ///
286    /// > If a thread drops a capability from its permitted set, it can never reacquire that
287    /// > capability (unless it execve(2)s either a set-user-ID-root program, or a program whose
288    /// > associated file capabilities grant that capability).
289    pub cap_permitted: Capabilities,
290
291    /// From https://man7.org/linux/man-pages/man7/capabilities.7.html
292    ///
293    /// > This is the set of capabilities used by the kernel to perform permission checks for the
294    /// > thread.
295    pub cap_effective: Capabilities,
296
297    /// From https://man7.org/linux/man-pages/man7/capabilities.7.html
298    ///
299    /// > This is a set of capabilities preserved across an execve(2).  Inheritable capabilities
300    /// > remain inheritable when executing any program, and inheritable capabilities are added to
301    /// > the permitted set when executing a program that has the corresponding bits set in the file
302    /// > inheritable set.
303    ///
304    /// > Because inheritable capabilities are not generally preserved across execve(2) when running
305    /// > as a non-root user, applications that wish to run helper programs with elevated
306    /// > capabilities should consider using ambient capabilities, described below.
307    pub cap_inheritable: Capabilities,
308
309    /// From https://man7.org/linux/man-pages/man7/capabilities.7.html
310    ///
311    /// > The capability bounding set is a mechanism that can be used to limit the capabilities that
312    /// > are gained during execve(2).
313    ///
314    /// > Since Linux 2.6.25, this is a per-thread capability set. In older kernels, the capability
315    /// > bounding set was a system wide attribute shared by all threads on the system.
316    pub cap_bounding: Capabilities,
317
318    /// From https://man7.org/linux/man-pages/man7/capabilities.7.html
319    ///
320    /// > This is a set of capabilities that are preserved across an execve(2) of a program that is
321    /// > not privileged.  The ambient capability set obeys the invariant that no capability can
322    /// > ever be ambient if it is not both permitted and inheritable.
323    ///
324    /// > Executing a program that changes UID or GID due to the set-user-ID or set-group-ID bits
325    /// > or executing a program that has any file capabilities set will clear the ambient set.
326    pub cap_ambient: Capabilities,
327
328    /// From https://man7.org/linux/man-pages/man7/capabilities.7.html
329    ///
330    /// > Starting with kernel 2.6.26, and with a kernel in which file capabilities are enabled,
331    /// > Linux implements a set of per-thread securebits flags that can be used to disable special
332    /// > handling of capabilities for UID 0 (root).
333    ///
334    /// > The securebits flags can be modified and retrieved using the prctl(2)
335    /// > PR_SET_SECUREBITS and PR_GET_SECUREBITS operations.  The CAP_SETPCAP capability is
336    /// > required to modify the flags.
337    pub securebits: SecureBits,
338
339    /// The SELinux security state of the task.
340    pub security_state: TaskAttrs,
341}
342
343bitflags! {
344    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
345    pub struct SecureBits: u32 {
346        const KEEP_CAPS = 1 << uapi::SECURE_KEEP_CAPS;
347        const KEEP_CAPS_LOCKED = 1 <<  uapi::SECURE_KEEP_CAPS_LOCKED;
348        const NO_SETUID_FIXUP = 1 << uapi::SECURE_NO_SETUID_FIXUP;
349        const NO_SETUID_FIXUP_LOCKED = 1 << uapi::SECURE_NO_SETUID_FIXUP_LOCKED;
350        const NOROOT = 1 << uapi::SECURE_NOROOT;
351        const NOROOT_LOCKED = 1 << uapi::SECURE_NOROOT_LOCKED;
352        const NO_CAP_AMBIENT_RAISE = 1 << uapi::SECURE_NO_CAP_AMBIENT_RAISE;
353        const NO_CAP_AMBIENT_RAISE_LOCKED = 1 << uapi::SECURE_NO_CAP_AMBIENT_RAISE_LOCKED;
354    }
355}
356
357static ROOT_CREDENTIALS: LazyLock<Arc<Credentials>> =
358    LazyLock::new(|| Arc::new(Credentials::with_ids(0, 0)));
359
360impl Credentials {
361    /// Creates a set of credentials with all possible permissions and capabilities.
362    pub fn root() -> Arc<Self> {
363        ROOT_CREDENTIALS.clone()
364    }
365
366    /// Creates a set of credentials with the given uid and gid. If the uid is 0, the credentials
367    /// will grant superuser access.
368    pub fn with_ids(uid: uid_t, gid: gid_t) -> Credentials {
369        let caps = if uid == 0 { Capabilities::all() } else { Capabilities::empty() };
370        Credentials {
371            uid,
372            gid,
373            euid: uid,
374            egid: gid,
375            saved_uid: uid,
376            saved_gid: gid,
377            groups: vec![],
378            fsuid: uid,
379            fsgid: gid,
380            cap_permitted: caps,
381            cap_effective: caps,
382            cap_inheritable: Capabilities::empty(),
383            cap_bounding: Capabilities::all(),
384            cap_ambient: Capabilities::empty(),
385            securebits: SecureBits::empty(),
386            security_state: TaskAttrs::for_kernel(),
387        }
388    }
389
390    pub fn is_in_group(&self, gid: gid_t) -> bool {
391        self.egid == gid || self.groups.contains(&gid)
392    }
393
394    /// Updates the `securebits` field, taking into account *`_LOCKED` bits.
395    pub fn set_securebits(&mut self, securebits: SecureBits) -> Result<(), Errno> {
396        // If a lock bit is set then neither it nor the corresponding `SECBIT_*` can be changed.
397        let mut locked_bits = SecureBits::empty();
398        if self.securebits.contains(SecureBits::NOROOT_LOCKED) {
399            locked_bits |= SecureBits::NOROOT | SecureBits::NOROOT_LOCKED;
400        }
401        if self.securebits.contains(SecureBits::KEEP_CAPS_LOCKED) {
402            locked_bits |= SecureBits::KEEP_CAPS | SecureBits::KEEP_CAPS_LOCKED;
403        }
404        if self.securebits.contains(SecureBits::NO_SETUID_FIXUP_LOCKED) {
405            locked_bits |= SecureBits::NO_SETUID_FIXUP | SecureBits::NO_SETUID_FIXUP_LOCKED;
406        }
407        if self.securebits.contains(SecureBits::NO_CAP_AMBIENT_RAISE_LOCKED) {
408            locked_bits |=
409                SecureBits::NO_CAP_AMBIENT_RAISE | SecureBits::NO_CAP_AMBIENT_RAISE_LOCKED;
410        }
411
412        if securebits & locked_bits != self.securebits & locked_bits {
413            return error!(EPERM);
414        }
415
416        self.securebits = securebits;
417        Ok(())
418    }
419
420    pub fn as_fscred(&self) -> FsCred {
421        FsCred { uid: self.fsuid, gid: self.fsgid }
422    }
423
424    pub fn euid_as_fscred(&self) -> FsCred {
425        FsCred { uid: self.euid, gid: self.egid }
426    }
427
428    pub fn uid_as_fscred(&self) -> FsCred {
429        FsCred { uid: self.uid, gid: self.gid }
430    }
431
432    /// Adjusts the capability sets (permitted, effective, and ambient) of these credentials
433    /// to reflect changes in user IDs (UID, EUID, Saved UID, or FSUID) from a previous state.
434    ///
435    /// This method compares the current state of these credentials against the `prev`
436    /// credentials to implement the Linux security model rules for UID transitions (as described
437    /// in `capabilities(7)` under "Effect of user ID changes on capabilities"). It is typically
438    /// called when preparing a new set of `Credentials` during `setuid()` family syscalls or
439    /// during `exec` after UID/GID bits have been applied.
440    pub fn update_capabilities(&mut self, prev: &Credentials) {
441        // https://man7.org/linux/man-pages/man7/capabilities.7.html
442        // If one or more of the real, effective, or saved set user IDs
443        // was previously 0, and as a result of the UID changes all of
444        // these IDs have a nonzero value, then all capabilities are
445        // cleared from the permitted, effective, and ambient capability
446        // sets.
447        //
448        // SECBIT_KEEP_CAPS: Setting this flag allows a thread that has one or more 0
449        // UIDs to retain capabilities in its permitted set when it
450        // switches all of its UIDs to nonzero values.
451        // The setting of the SECBIT_KEEP_CAPS flag is ignored if the
452        // SECBIT_NO_SETUID_FIXUP flag is set.  (The latter flag
453        // provides a superset of the effect of the former flag.)
454        // SECBIT_NO_SETUID_FIXUP: Setting  this  flag  stops  the  kernel from adjusting
455        // the process's permitted, effective, and ambient capability sets when the thread's
456        // effective and filesystem UIDs are switched between zero and nonzero values.
457        if self.securebits.contains(SecureBits::NO_SETUID_FIXUP) {
458            return;
459        }
460        let was_any_zero = prev.uid == 0 || prev.euid == 0 || prev.saved_uid == 0;
461        let is_all_nonzero = self.uid != 0 && self.euid != 0 && self.saved_uid != 0;
462
463        if was_any_zero && is_all_nonzero {
464            if !self.securebits.contains(SecureBits::KEEP_CAPS) {
465                self.cap_permitted = Capabilities::empty();
466                self.cap_effective = Capabilities::empty();
467            }
468            self.cap_ambient = Capabilities::empty();
469        }
470        // If the effective user ID is changed from 0 to nonzero, then
471        // all capabilities are cleared from the effective set.
472        if prev.euid == 0 && self.euid != 0 {
473            self.cap_effective = Capabilities::empty();
474        } else if prev.euid != 0 && self.euid == 0 {
475            // If the effective user ID is changed from nonzero to 0, then
476            // the permitted set is copied to the effective set.
477            self.cap_effective = self.cap_permitted;
478        }
479
480        // If the filesystem user ID is changed from 0 to nonzero (see
481        // setfsuid(2)), then the following capabilities are cleared from
482        // the effective set: CAP_CHOWN, CAP_DAC_OVERRIDE,
483        // CAP_DAC_READ_SEARCH, CAP_FOWNER, CAP_FSETID,
484        // CAP_LINUX_IMMUTABLE (since Linux 2.6.30), CAP_MAC_OVERRIDE,
485        // and CAP_MKNOD (since Linux 2.6.30).
486        let fs_capabilities = CAP_CHOWN
487            | CAP_DAC_OVERRIDE
488            | CAP_DAC_READ_SEARCH
489            | CAP_FOWNER
490            | CAP_FSETID
491            | CAP_LINUX_IMMUTABLE
492            | CAP_MAC_OVERRIDE
493            | CAP_MKNOD;
494        if prev.fsuid == 0 && self.fsuid != 0 {
495            self.cap_effective &= !fs_capabilities;
496        } else if prev.fsuid != 0 && self.fsuid == 0 {
497            // If the filesystem UID is changed from nonzero to 0, then any
498            // of these capabilities that are enabled in the permitted set
499            // are enabled in the effective set.
500            self.cap_effective |= self.cap_permitted & fs_capabilities;
501        }
502    }
503}
504
505/// The owner and group of a file. Used as a parameter for functions that create files.
506#[derive(Debug, Clone, Copy)]
507pub struct FsCred {
508    pub uid: uid_t,
509    pub gid: gid_t,
510}
511
512impl FsCred {
513    pub const fn root() -> Self {
514        Self { uid: 0, gid: 0 }
515    }
516}
517
518impl From<Credentials> for FsCred {
519    fn from(c: Credentials) -> Self {
520        c.as_fscred()
521    }
522}
523
524#[derive(Debug, Default, Clone)]
525pub struct UserAndOrGroupId {
526    pub uid: Option<uid_t>,
527    pub gid: Option<gid_t>,
528}
529
530impl UserAndOrGroupId {
531    pub fn is_none(&self) -> bool {
532        self.uid.is_none() && self.gid.is_none()
533    }
534
535    pub fn is_some(&self) -> bool {
536        !self.is_none()
537    }
538
539    pub fn clear(&mut self) {
540        self.uid = None;
541        self.gid = None;
542    }
543}
544
545#[cfg(test)]
546mod tests {
547    use super::*;
548
549    #[::fuchsia::test]
550    fn test_empty() {
551        assert_eq!(Capabilities::empty().mask, 0);
552    }
553
554    #[::fuchsia::test]
555    fn test_union() {
556        let expected = Capabilities { mask: CAP_BLOCK_SUSPEND.mask | CAP_AUDIT_READ.mask };
557        assert_eq!(CAP_BLOCK_SUSPEND.union(CAP_AUDIT_READ), expected);
558        assert_eq!(CAP_BLOCK_SUSPEND.union(CAP_BLOCK_SUSPEND), CAP_BLOCK_SUSPEND);
559    }
560
561    #[::fuchsia::test]
562    fn test_difference() {
563        let base = CAP_BPF | CAP_AUDIT_WRITE;
564        let expected = CAP_BPF;
565        assert_eq!(base.difference(CAP_AUDIT_WRITE), expected);
566        assert_eq!(base.difference(CAP_AUDIT_WRITE | CAP_BPF), Capabilities::empty());
567    }
568
569    #[::fuchsia::test]
570    fn test_contains() {
571        let base = CAP_BPF | CAP_AUDIT_WRITE;
572        assert!(base.contains(CAP_AUDIT_WRITE));
573        assert!(base.contains(CAP_BPF));
574        assert!(base.contains(CAP_AUDIT_WRITE | CAP_BPF));
575
576        assert!(!base.contains(CAP_AUDIT_CONTROL));
577        assert!(!base.contains(CAP_AUDIT_WRITE | CAP_BPF | CAP_AUDIT_CONTROL));
578    }
579
580    #[::fuchsia::test]
581    fn test_insert() {
582        let mut capabilities = CAP_BLOCK_SUSPEND;
583        capabilities.insert(CAP_BLOCK_SUSPEND);
584        assert_eq!(capabilities, CAP_BLOCK_SUSPEND);
585
586        capabilities.insert(CAP_AUDIT_READ);
587        let expected = Capabilities { mask: CAP_BLOCK_SUSPEND.mask | CAP_AUDIT_READ.mask };
588        assert_eq!(capabilities, expected);
589    }
590
591    #[::fuchsia::test]
592    fn test_remove() {
593        let mut capabilities = CAP_BLOCK_SUSPEND;
594        capabilities.remove(CAP_BLOCK_SUSPEND);
595        assert_eq!(capabilities, Capabilities::empty());
596
597        let mut capabilities = CAP_BLOCK_SUSPEND | CAP_AUDIT_READ;
598        capabilities.remove(CAP_AUDIT_READ);
599        assert_eq!(capabilities, CAP_BLOCK_SUSPEND);
600    }
601
602    #[::fuchsia::test]
603    fn test_try_from() {
604        let capabilities = CAP_BLOCK_SUSPEND;
605        assert_eq!(Capabilities::try_from(uapi::CAP_BLOCK_SUSPEND as u64), Ok(capabilities));
606
607        assert_eq!(Capabilities::try_from(200000), error!(EINVAL));
608    }
609}