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