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 fuchsia_rcu::RcuDroppable;
12use std::sync::{Arc, LazyLock};
13
14bitflags! {
15 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
21 pub struct Capabilities: u64 {
22 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 }
66}
67
68unsafe 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 "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 _ => return error!(EINVAL),
152 })
153 }
154}
155
156pub 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;
198pub 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 pub fsuid: uid_t,
242
243 pub fsgid: gid_t,
245
246 pub cap_permitted: Capabilities,
256
257 pub cap_effective: Capabilities,
262
263 pub cap_inheritable: Capabilities,
274
275 pub cap_bounding: Capabilities,
283
284 pub cap_ambient: Capabilities,
293
294 pub securebits: SecureBits,
304
305 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
323unsafe 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 pub fn root() -> Arc<Self> {
332 ROOT_CREDENTIALS.clone()
333 }
334
335 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 pub fn set_securebits(&mut self, securebits: SecureBits) -> Result<(), Errno> {
365 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 pub fn update_capabilities(&mut self, prev: &Credentials) {
410 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 prev.euid == 0 && self.euid != 0 {
442 self.cap_effective = Capabilities::empty();
443 } else if prev.euid != 0 && self.euid == 0 {
444 self.cap_effective = self.cap_permitted;
447 }
448
449 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 self.cap_effective |= self.cap_permitted & fs_capabilities;
470 }
471 }
472}
473
474#[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}