1#![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::sync::{Arc, LazyLock};
12
13bitflags! {
14 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
20 pub struct Capabilities: u64 {
21 const AUDIT_CONTROL = 1 << uapi::CAP_AUDIT_CONTROL;
23 const AUDIT_READ = 1 << uapi::CAP_AUDIT_READ;
24 const AUDIT_WRITE = 1 << uapi::CAP_AUDIT_WRITE;
25 const BLOCK_SUSPEND = 1 << uapi::CAP_BLOCK_SUSPEND;
26 const BPF = 1 << uapi::CAP_BPF;
27 const CHECKPOINT_RESTORE = 1 << uapi::CAP_CHECKPOINT_RESTORE;
28 const CHOWN = 1 << uapi::CAP_CHOWN;
29 const DAC_OVERRIDE = 1 << uapi::CAP_DAC_OVERRIDE;
30 const DAC_READ_SEARCH = 1 << uapi::CAP_DAC_READ_SEARCH;
31 const FOWNER = 1 << uapi::CAP_FOWNER;
32 const FSETID = 1 << uapi::CAP_FSETID;
33 const IPC_LOCK = 1 << uapi::CAP_IPC_LOCK;
34 const IPC_OWNER = 1 << uapi::CAP_IPC_OWNER;
35 const KILL = 1 << uapi::CAP_KILL;
36 const LEASE = 1 << uapi::CAP_LEASE;
37 const LINUX_IMMUTABLE = 1 << uapi::CAP_LINUX_IMMUTABLE;
38 const MAC_ADMIN = 1 << uapi::CAP_MAC_ADMIN;
39 const MAC_OVERRIDE = 1 << uapi::CAP_MAC_OVERRIDE;
40 const MKNOD = 1 << uapi::CAP_MKNOD;
41 const NET_ADMIN = 1 << uapi::CAP_NET_ADMIN;
42 const NET_BIND_SERVICE = 1 << uapi::CAP_NET_BIND_SERVICE;
43 const NET_BROADCAST = 1 << uapi::CAP_NET_BROADCAST;
44 const NET_RAW = 1 << uapi::CAP_NET_RAW;
45 const PERFMON = 1 << uapi::CAP_PERFMON;
46 const SETFCAP = 1 << uapi::CAP_SETFCAP;
47 const SETGID = 1 << uapi::CAP_SETGID;
48 const SETPCAP = 1 << uapi::CAP_SETPCAP;
49 const SETUID = 1 << uapi::CAP_SETUID;
50 const SYSLOG = 1 << uapi::CAP_SYSLOG;
51 const SYS_ADMIN = 1 << uapi::CAP_SYS_ADMIN;
52 const SYS_BOOT = 1 << uapi::CAP_SYS_BOOT;
53 const SYS_CHROOT = 1 << uapi::CAP_SYS_CHROOT;
54 const SYS_MODULE = 1 << uapi::CAP_SYS_MODULE;
55 const SYS_NICE = 1 << uapi::CAP_SYS_NICE;
56 const SYS_PACCT = 1 << uapi::CAP_SYS_PACCT;
57 const SYS_PTRACE = 1 << uapi::CAP_SYS_PTRACE;
58 const SYS_RAWIO = 1 << uapi::CAP_SYS_RAWIO;
59 const SYS_RESOURCE = 1 << uapi::CAP_SYS_RESOURCE;
60 const SYS_TIME = 1 << uapi::CAP_SYS_TIME;
61 const SYS_TTY_CONFIG = 1 << uapi::CAP_SYS_TTY_CONFIG;
62 const WAKE_ALARM = 1 << uapi::CAP_WAKE_ALARM;
63 }
65}
66
67impl Capabilities {
68 pub const fn as_abi_v1(self) -> u32 {
69 self.bits() as u32
70 }
71
72 pub fn from_abi_v1(bits: u32) -> Self {
73 Self::from_bits_truncate(bits as u64)
74 }
75
76 pub const fn as_abi_v3(self) -> (u32, u32) {
77 (self.bits() as u32, (self.bits() >> 32) as u32)
78 }
79
80 pub fn from_abi_v3(u32s: (u32, u32)) -> Self {
81 let mask = u32s.0 as u64 | ((u32s.1 as u64) << 32);
82 Self::from_bits_truncate(mask)
83 }
84}
85
86impl std::convert::TryFrom<u64> for Capabilities {
87 type Error = Errno;
88
89 fn try_from(capability_num: u64) -> Result<Self, Self::Error> {
90 match 1u64.checked_shl(capability_num as u32) {
91 Some(mask) => {
92 let caps = Self::from_bits_truncate(mask);
93 if caps.is_empty() { error!(EINVAL) } else { Ok(caps) }
94 }
95 _ => error!(EINVAL),
96 }
97 }
98}
99
100impl std::str::FromStr for Capabilities {
101 type Err = Errno;
102 fn from_str(s: &str) -> Result<Self, Self::Err> {
103 Ok(match s {
104 "AUDIT_CONTROL" => Self::AUDIT_CONTROL,
106 "AUDIT_READ" => Self::AUDIT_READ,
107 "AUDIT_WRITE" => Self::AUDIT_WRITE,
108 "BLOCK_SUSPEND" => Self::BLOCK_SUSPEND,
109 "BPF" => Self::BPF,
110 "CHECKPOINT_RESTORE" => Self::CHECKPOINT_RESTORE,
111 "CHOWN" => Self::CHOWN,
112 "DAC_OVERRIDE" => Self::DAC_OVERRIDE,
113 "DAC_READ_SEARCH" => Self::DAC_READ_SEARCH,
114 "FOWNER" => Self::FOWNER,
115 "FSETID" => Self::FSETID,
116 "IPC_LOCK" => Self::IPC_LOCK,
117 "IPC_OWNER" => Self::IPC_OWNER,
118 "KILL" => Self::KILL,
119 "LEASE" => Self::LEASE,
120 "LINUX_IMMUTABLE" => Self::LINUX_IMMUTABLE,
121 "MAC_ADMIN" => Self::MAC_ADMIN,
122 "MAC_OVERRIDE" => Self::MAC_OVERRIDE,
123 "MKNOD" => Self::MKNOD,
124 "NET_ADMIN" => Self::NET_ADMIN,
125 "NET_BIND_SERVICE" => Self::NET_BIND_SERVICE,
126 "NET_BROADCAST" => Self::NET_BROADCAST,
127 "NET_RAW" => Self::NET_RAW,
128 "PERFMON" => Self::PERFMON,
129 "SETFCAP" => Self::SETFCAP,
130 "SETGID" => Self::SETGID,
131 "SETPCAP" => Self::SETPCAP,
132 "SETUID" => Self::SETUID,
133 "SYSLOG" => Self::SYSLOG,
134 "SYS_ADMIN" => Self::SYS_ADMIN,
135 "SYS_BOOT" => Self::SYS_BOOT,
136 "SYS_CHROOT" => Self::SYS_CHROOT,
137 "SYS_MODULE" => Self::SYS_MODULE,
138 "SYS_NICE" => Self::SYS_NICE,
139 "SYS_PACCT" => Self::SYS_PACCT,
140 "SYS_PTRACE" => Self::SYS_PTRACE,
141 "SYS_RAWIO" => Self::SYS_RAWIO,
142 "SYS_RESOURCE" => Self::SYS_RESOURCE,
143 "SYS_TIME" => Self::SYS_TIME,
144 "SYS_TTY_CONFIG" => Self::SYS_TTY_CONFIG,
145 "WAKE_ALARM" => Self::WAKE_ALARM,
146 _ => return error!(EINVAL),
148 })
149 }
150}
151
152pub const CAP_AUDIT_CONTROL: Capabilities = Capabilities::AUDIT_CONTROL;
154pub const CAP_AUDIT_READ: Capabilities = Capabilities::AUDIT_READ;
155pub const CAP_AUDIT_WRITE: Capabilities = Capabilities::AUDIT_WRITE;
156pub const CAP_BLOCK_SUSPEND: Capabilities = Capabilities::BLOCK_SUSPEND;
157pub const CAP_BPF: Capabilities = Capabilities::BPF;
158pub const CAP_CHECKPOINT_RESTORE: Capabilities = Capabilities::CHECKPOINT_RESTORE;
159pub const CAP_CHOWN: Capabilities = Capabilities::CHOWN;
160pub const CAP_DAC_OVERRIDE: Capabilities = Capabilities::DAC_OVERRIDE;
161pub const CAP_DAC_READ_SEARCH: Capabilities = Capabilities::DAC_READ_SEARCH;
162pub const CAP_FOWNER: Capabilities = Capabilities::FOWNER;
163pub const CAP_FSETID: Capabilities = Capabilities::FSETID;
164pub const CAP_IPC_LOCK: Capabilities = Capabilities::IPC_LOCK;
165pub const CAP_IPC_OWNER: Capabilities = Capabilities::IPC_OWNER;
166pub const CAP_KILL: Capabilities = Capabilities::KILL;
167pub const CAP_LEASE: Capabilities = Capabilities::LEASE;
168pub const CAP_LINUX_IMMUTABLE: Capabilities = Capabilities::LINUX_IMMUTABLE;
169pub const CAP_MAC_ADMIN: Capabilities = Capabilities::MAC_ADMIN;
170pub const CAP_MAC_OVERRIDE: Capabilities = Capabilities::MAC_OVERRIDE;
171pub const CAP_MKNOD: Capabilities = Capabilities::MKNOD;
172pub const CAP_NET_ADMIN: Capabilities = Capabilities::NET_ADMIN;
173pub const CAP_NET_BIND_SERVICE: Capabilities = Capabilities::NET_BIND_SERVICE;
174pub const CAP_NET_BROADCAST: Capabilities = Capabilities::NET_BROADCAST;
175pub const CAP_NET_RAW: Capabilities = Capabilities::NET_RAW;
176pub const CAP_PERFMON: Capabilities = Capabilities::PERFMON;
177pub const CAP_SETFCAP: Capabilities = Capabilities::SETFCAP;
178pub const CAP_SETGID: Capabilities = Capabilities::SETGID;
179pub const CAP_SETPCAP: Capabilities = Capabilities::SETPCAP;
180pub const CAP_SETUID: Capabilities = Capabilities::SETUID;
181pub const CAP_SYSLOG: Capabilities = Capabilities::SYSLOG;
182pub const CAP_SYS_ADMIN: Capabilities = Capabilities::SYS_ADMIN;
183pub const CAP_SYS_BOOT: Capabilities = Capabilities::SYS_BOOT;
184pub const CAP_SYS_CHROOT: Capabilities = Capabilities::SYS_CHROOT;
185pub const CAP_SYS_MODULE: Capabilities = Capabilities::SYS_MODULE;
186pub const CAP_SYS_NICE: Capabilities = Capabilities::SYS_NICE;
187pub const CAP_SYS_PACCT: Capabilities = Capabilities::SYS_PACCT;
188pub const CAP_SYS_PTRACE: Capabilities = Capabilities::SYS_PTRACE;
189pub const CAP_SYS_RAWIO: Capabilities = Capabilities::SYS_RAWIO;
190pub const CAP_SYS_RESOURCE: Capabilities = Capabilities::SYS_RESOURCE;
191pub const CAP_SYS_TIME: Capabilities = Capabilities::SYS_TIME;
192pub const CAP_SYS_TTY_CONFIG: Capabilities = Capabilities::SYS_TTY_CONFIG;
193pub const CAP_WAKE_ALARM: Capabilities = Capabilities::WAKE_ALARM;
194pub const CAP_LAST_CAP: u32 = uapi::CAP_LAST_CAP;
196
197bitflags! {
198 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
199 pub struct PtraceAccessMode: u32 {
200 const READ = 1 << 0;
201 const ATTACH = 1 << 1;
202 const FSCREDS = 1 << 2;
203 const REALCREDS = 1 << 3;
204 const NOAUDIT = 1 << 4;
205 }
206}
207
208pub const PTRACE_MODE_READ: PtraceAccessMode = PtraceAccessMode::READ;
209pub const PTRACE_MODE_ATTACH: PtraceAccessMode = PtraceAccessMode::ATTACH;
210pub const PTRACE_MODE_FSCREDS: PtraceAccessMode = PtraceAccessMode::FSCREDS;
211pub const PTRACE_MODE_REALCREDS: PtraceAccessMode = PtraceAccessMode::REALCREDS;
212pub const PTRACE_MODE_READ_FSCREDS: PtraceAccessMode = PtraceAccessMode::from_bits_truncate(
213 PtraceAccessMode::READ.bits() | PtraceAccessMode::FSCREDS.bits(),
214);
215pub const PTRACE_MODE_READ_REALCREDS: PtraceAccessMode = PtraceAccessMode::from_bits_truncate(
216 PtraceAccessMode::READ.bits() | PtraceAccessMode::REALCREDS.bits(),
217);
218pub const PTRACE_MODE_ATTACH_FSCREDS: PtraceAccessMode = PtraceAccessMode::from_bits_truncate(
219 PtraceAccessMode::ATTACH.bits() | PtraceAccessMode::FSCREDS.bits(),
220);
221pub const PTRACE_MODE_ATTACH_REALCREDS: PtraceAccessMode = PtraceAccessMode::from_bits_truncate(
222 PtraceAccessMode::ATTACH.bits() | PtraceAccessMode::REALCREDS.bits(),
223);
224pub const PTRACE_MODE_NOAUDIT: PtraceAccessMode = PtraceAccessMode::NOAUDIT;
225
226#[derive(Debug, Clone)]
227pub struct Credentials {
228 pub uid: uid_t,
229 pub gid: gid_t,
230 pub euid: uid_t,
231 pub egid: gid_t,
232 pub saved_uid: uid_t,
233 pub saved_gid: gid_t,
234 pub groups: Vec<gid_t>,
235
236 pub fsuid: uid_t,
238
239 pub fsgid: gid_t,
241
242 pub cap_permitted: Capabilities,
252
253 pub cap_effective: Capabilities,
258
259 pub cap_inheritable: Capabilities,
270
271 pub cap_bounding: Capabilities,
279
280 pub cap_ambient: Capabilities,
289
290 pub securebits: SecureBits,
300
301 pub security_state: TaskAttrs,
303}
304
305bitflags! {
306 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
307 pub struct SecureBits: u32 {
308 const KEEP_CAPS = 1 << uapi::SECURE_KEEP_CAPS;
309 const KEEP_CAPS_LOCKED = 1 << uapi::SECURE_KEEP_CAPS_LOCKED;
310 const NO_SETUID_FIXUP = 1 << uapi::SECURE_NO_SETUID_FIXUP;
311 const NO_SETUID_FIXUP_LOCKED = 1 << uapi::SECURE_NO_SETUID_FIXUP_LOCKED;
312 const NOROOT = 1 << uapi::SECURE_NOROOT;
313 const NOROOT_LOCKED = 1 << uapi::SECURE_NOROOT_LOCKED;
314 const NO_CAP_AMBIENT_RAISE = 1 << uapi::SECURE_NO_CAP_AMBIENT_RAISE;
315 const NO_CAP_AMBIENT_RAISE_LOCKED = 1 << uapi::SECURE_NO_CAP_AMBIENT_RAISE_LOCKED;
316 }
317}
318
319static ROOT_CREDENTIALS: LazyLock<Arc<Credentials>> =
320 LazyLock::new(|| Arc::new(Credentials::with_ids(0, 0)));
321
322impl Credentials {
323 pub fn root() -> Arc<Self> {
325 ROOT_CREDENTIALS.clone()
326 }
327
328 pub fn with_ids(uid: uid_t, gid: gid_t) -> Credentials {
331 let caps = if uid == 0 { Capabilities::all() } else { Capabilities::empty() };
332 Credentials {
333 uid,
334 gid,
335 euid: uid,
336 egid: gid,
337 saved_uid: uid,
338 saved_gid: gid,
339 groups: vec![],
340 fsuid: uid,
341 fsgid: gid,
342 cap_permitted: caps,
343 cap_effective: caps,
344 cap_inheritable: Capabilities::empty(),
345 cap_bounding: Capabilities::all(),
346 cap_ambient: Capabilities::empty(),
347 securebits: SecureBits::empty(),
348 security_state: TaskAttrs::for_kernel(),
349 }
350 }
351
352 pub fn is_in_group(&self, gid: gid_t) -> bool {
353 self.egid == gid || self.groups.contains(&gid)
354 }
355
356 pub fn set_securebits(&mut self, securebits: SecureBits) -> Result<(), Errno> {
358 let mut locked_bits = SecureBits::empty();
360 if self.securebits.contains(SecureBits::NOROOT_LOCKED) {
361 locked_bits |= SecureBits::NOROOT | SecureBits::NOROOT_LOCKED;
362 }
363 if self.securebits.contains(SecureBits::KEEP_CAPS_LOCKED) {
364 locked_bits |= SecureBits::KEEP_CAPS | SecureBits::KEEP_CAPS_LOCKED;
365 }
366 if self.securebits.contains(SecureBits::NO_SETUID_FIXUP_LOCKED) {
367 locked_bits |= SecureBits::NO_SETUID_FIXUP | SecureBits::NO_SETUID_FIXUP_LOCKED;
368 }
369 if self.securebits.contains(SecureBits::NO_CAP_AMBIENT_RAISE_LOCKED) {
370 locked_bits |=
371 SecureBits::NO_CAP_AMBIENT_RAISE | SecureBits::NO_CAP_AMBIENT_RAISE_LOCKED;
372 }
373
374 if securebits & locked_bits != self.securebits & locked_bits {
375 return error!(EPERM);
376 }
377
378 self.securebits = securebits;
379 Ok(())
380 }
381
382 pub fn as_fscred(&self) -> FsCred {
383 FsCred { uid: self.fsuid, gid: self.fsgid }
384 }
385
386 pub fn euid_as_fscred(&self) -> FsCred {
387 FsCred { uid: self.euid, gid: self.egid }
388 }
389
390 pub fn uid_as_fscred(&self) -> FsCred {
391 FsCred { uid: self.uid, gid: self.gid }
392 }
393
394 pub fn update_capabilities(&mut self, prev: &Credentials) {
403 if self.securebits.contains(SecureBits::NO_SETUID_FIXUP) {
420 return;
421 }
422 let was_any_zero = prev.uid == 0 || prev.euid == 0 || prev.saved_uid == 0;
423 let is_all_nonzero = self.uid != 0 && self.euid != 0 && self.saved_uid != 0;
424
425 if was_any_zero && is_all_nonzero {
426 if !self.securebits.contains(SecureBits::KEEP_CAPS) {
427 self.cap_permitted = Capabilities::empty();
428 self.cap_effective = Capabilities::empty();
429 }
430 self.cap_ambient = Capabilities::empty();
431 }
432 if prev.euid == 0 && self.euid != 0 {
435 self.cap_effective = Capabilities::empty();
436 } else if prev.euid != 0 && self.euid == 0 {
437 self.cap_effective = self.cap_permitted;
440 }
441
442 let fs_capabilities = CAP_CHOWN
449 | CAP_DAC_OVERRIDE
450 | CAP_DAC_READ_SEARCH
451 | CAP_FOWNER
452 | CAP_FSETID
453 | CAP_LINUX_IMMUTABLE
454 | CAP_MAC_OVERRIDE
455 | CAP_MKNOD;
456 if prev.fsuid == 0 && self.fsuid != 0 {
457 self.cap_effective &= !fs_capabilities;
458 } else if prev.fsuid != 0 && self.fsuid == 0 {
459 self.cap_effective |= self.cap_permitted & fs_capabilities;
463 }
464 }
465}
466
467#[derive(Debug, Clone, Copy)]
469pub struct FsCred {
470 pub uid: uid_t,
471 pub gid: gid_t,
472}
473
474impl FsCred {
475 pub const fn root() -> Self {
476 Self { uid: 0, gid: 0 }
477 }
478}
479
480impl From<Credentials> for FsCred {
481 fn from(c: Credentials) -> Self {
482 c.as_fscred()
483 }
484}
485
486#[derive(Debug, Default, Clone)]
487pub struct UserAndOrGroupId {
488 pub uid: Option<uid_t>,
489 pub gid: Option<gid_t>,
490}
491
492impl UserAndOrGroupId {
493 pub fn is_none(&self) -> bool {
494 self.uid.is_none() && self.gid.is_none()
495 }
496
497 pub fn is_some(&self) -> bool {
498 !self.is_none()
499 }
500
501 pub fn clear(&mut self) {
502 self.uid = None;
503 self.gid = None;
504 }
505}
506
507#[cfg(test)]
508mod tests {
509 use super::*;
510
511 #[::fuchsia::test]
512 fn test_empty() {
513 assert_eq!(Capabilities::empty().bits(), 0);
514 }
515
516 #[::fuchsia::test]
517 fn test_union() {
518 let expected = CAP_BLOCK_SUSPEND | CAP_AUDIT_READ;
519 assert_eq!(CAP_BLOCK_SUSPEND.union(CAP_AUDIT_READ), expected);
520 assert_eq!(CAP_BLOCK_SUSPEND.union(CAP_BLOCK_SUSPEND), CAP_BLOCK_SUSPEND);
521 }
522
523 #[::fuchsia::test]
524 fn test_difference() {
525 let base = CAP_BPF | CAP_AUDIT_WRITE;
526 let expected = CAP_BPF;
527 assert_eq!(base.difference(CAP_AUDIT_WRITE), expected);
528 assert_eq!(base.difference(CAP_AUDIT_WRITE | CAP_BPF), Capabilities::empty());
529 }
530
531 #[::fuchsia::test]
532 fn test_contains() {
533 let base = CAP_BPF | CAP_AUDIT_WRITE;
534 assert!(base.contains(CAP_AUDIT_WRITE));
535 assert!(base.contains(CAP_BPF));
536 assert!(base.contains(CAP_AUDIT_WRITE | CAP_BPF));
537
538 assert!(!base.contains(CAP_AUDIT_CONTROL));
539 assert!(!base.contains(CAP_AUDIT_WRITE | CAP_BPF | CAP_AUDIT_CONTROL));
540 }
541
542 #[::fuchsia::test]
543 fn test_insert() {
544 let mut capabilities = CAP_BLOCK_SUSPEND;
545 capabilities.insert(CAP_BLOCK_SUSPEND);
546 assert_eq!(capabilities, CAP_BLOCK_SUSPEND);
547
548 capabilities.insert(CAP_AUDIT_READ);
549 let expected = CAP_BLOCK_SUSPEND | CAP_AUDIT_READ;
550 assert_eq!(capabilities, expected);
551 }
552
553 #[::fuchsia::test]
554 fn test_remove() {
555 let mut capabilities = CAP_BLOCK_SUSPEND;
556 capabilities.remove(CAP_BLOCK_SUSPEND);
557 assert_eq!(capabilities, Capabilities::empty());
558
559 let mut capabilities = CAP_BLOCK_SUSPEND | CAP_AUDIT_READ;
560 capabilities.remove(CAP_AUDIT_READ);
561 assert_eq!(capabilities, CAP_BLOCK_SUSPEND);
562 }
563
564 #[::fuchsia::test]
565 fn test_try_from() {
566 let capabilities = CAP_BLOCK_SUSPEND;
567 assert_eq!(Capabilities::try_from(uapi::CAP_BLOCK_SUSPEND as u64), Ok(capabilities));
568
569 assert_eq!(Capabilities::try_from(200000), error!(EINVAL));
570 }
571}