blob: c013c280875c88913843bf029e2cea0b23a5537a [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![allow(dead_code)]
use std::ops;
use crate::types::*;
// We don't use bitflags for this because capability sets can have bits set that don't have defined
// meaning as capabilities. init has all 64 bits set, even though only 40 of them are valid.
#[derive(Clone, Copy, PartialEq)]
pub struct Capabilities {
mask: u64,
}
impl Capabilities {
pub fn empty() -> Self {
Self { mask: 0 }
}
pub fn all() -> Self {
Self { mask: u64::MAX }
}
pub fn union(&self, caps: Capabilities) -> Self {
let mut new_caps = *self;
new_caps.insert(caps);
new_caps
}
pub fn difference(&self, caps: Capabilities) -> Self {
let mut new_caps = *self;
new_caps.remove(caps);
new_caps
}
pub fn contains(self, caps: Capabilities) -> bool {
(self & caps) == caps
}
pub fn insert(&mut self, caps: Capabilities) {
*self |= caps;
}
pub fn remove(&mut self, caps: Capabilities) {
*self &= !caps;
}
pub fn as_abi_v3(self) -> (u32, u32) {
(self.mask as u32, (self.mask >> 32) as u32)
}
pub fn from_abi_v3(u32s: (u32, u32)) -> Self {
Self { mask: u32s.0 as u64 | ((u32s.1 as u64) << 32) }
}
}
impl std::convert::TryFrom<u64> for Capabilities {
type Error = Errno;
fn try_from(capability_num: u64) -> Result<Self, Self::Error> {
match 1u64.checked_shl(capability_num as u32) {
Some(mask) => Ok(Self { mask }),
_ => error!(EINVAL),
}
}
}
impl ops::BitAnd for Capabilities {
type Output = Self;
// rhs is the "right-hand side" of the expression `a & b`
fn bitand(self, rhs: Self) -> Self::Output {
Self { mask: self.mask & rhs.mask }
}
}
impl ops::BitAndAssign for Capabilities {
// rhs is the "right-hand side" of the expression `a & b`
fn bitand_assign(&mut self, rhs: Self) {
self.mask &= rhs.mask;
}
}
impl ops::BitOr for Capabilities {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self { mask: self.mask | rhs.mask }
}
}
impl ops::BitOrAssign for Capabilities {
fn bitor_assign(&mut self, rhs: Self) {
self.mask |= rhs.mask;
}
}
impl ops::Not for Capabilities {
type Output = Self;
fn not(self) -> Self::Output {
Self { mask: !self.mask }
}
}
impl std::fmt::Debug for Capabilities {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "Capabilities({:#x})", self.mask)
}
}
pub const CAP_CHOWN: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_CHOWN };
pub const CAP_DAC_OVERRIDE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_DAC_OVERRIDE };
pub const CAP_DAC_READ_SEARCH: Capabilities =
Capabilities { mask: 1u64 << uapi::CAP_DAC_READ_SEARCH };
pub const CAP_FOWNER: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_FOWNER };
pub const CAP_FSETID: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_FSETID };
pub const CAP_KILL: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_KILL };
pub const CAP_SETGID: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SETGID };
pub const CAP_SETUID: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SETUID };
pub const CAP_SETPCAP: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SETPCAP };
pub const CAP_LINUX_IMMUTABLE: Capabilities =
Capabilities { mask: 1u64 << uapi::CAP_LINUX_IMMUTABLE };
pub const CAP_NET_BIND_SERVICE: Capabilities =
Capabilities { mask: 1u64 << uapi::CAP_NET_BIND_SERVICE };
pub const CAP_NET_BROADCAST: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_NET_BROADCAST };
pub const CAP_NET_ADMIN: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_NET_ADMIN };
pub const CAP_NET_RAW: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_NET_RAW };
pub const CAP_IPC_LOCK: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_IPC_LOCK };
pub const CAP_IPC_OWNER: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_IPC_OWNER };
pub const CAP_SYS_MODULE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_MODULE };
pub const CAP_SYS_RAWIO: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_RAWIO };
pub const CAP_SYS_CHROOT: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_CHROOT };
pub const CAP_SYS_PTRACE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_PTRACE };
pub const CAP_SYS_PACCT: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_PACCT };
pub const CAP_SYS_ADMIN: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_ADMIN };
pub const CAP_SYS_BOOT: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_BOOT };
pub const CAP_SYS_NICE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_NICE };
pub const CAP_SYS_RESOURCE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_RESOURCE };
pub const CAP_SYS_TIME: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYS_TIME };
pub const CAP_SYS_TTY_CONFIG: Capabilities =
Capabilities { mask: 1u64 << uapi::CAP_SYS_TTY_CONFIG };
pub const CAP_MKNOD: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_MKNOD };
pub const CAP_LEASE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_LEASE };
pub const CAP_AUDIT_WRITE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_AUDIT_WRITE };
pub const CAP_AUDIT_CONTROL: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_AUDIT_CONTROL };
pub const CAP_SETFCAP: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SETFCAP };
pub const CAP_MAC_OVERRIDE: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_MAC_OVERRIDE };
pub const CAP_MAC_ADMIN: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_MAC_ADMIN };
pub const CAP_SYSLOG: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_SYSLOG };
pub const CAP_WAKE_ALARM: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_WAKE_ALARM };
pub const CAP_BLOCK_SUSPEND: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_BLOCK_SUSPEND };
pub const CAP_AUDIT_READ: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_AUDIT_READ };
pub const CAP_PERFMON: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_PERFMON };
pub const CAP_BPF: Capabilities = Capabilities { mask: 1u64 << uapi::CAP_BPF };
pub const CAP_CHECKPOINT_RESTORE: Capabilities =
Capabilities { mask: 1u64 << uapi::CAP_CHECKPOINT_RESTORE };
#[cfg(test)]
mod tests {
use super::*;
#[::fuchsia::test]
fn test_empty() {
assert_eq!(Capabilities::empty().mask, 0);
}
#[::fuchsia::test]
fn test_all() {
// all() should be every bit set, not just all the CAP_* constants.
assert_eq!(Capabilities::all().mask, u64::MAX);
}
#[::fuchsia::test]
fn test_union() {
let expected = Capabilities { mask: CAP_BLOCK_SUSPEND.mask | CAP_AUDIT_READ.mask };
assert_eq!(CAP_BLOCK_SUSPEND.union(CAP_AUDIT_READ), expected);
assert_eq!(CAP_BLOCK_SUSPEND.union(CAP_BLOCK_SUSPEND), CAP_BLOCK_SUSPEND);
}
#[::fuchsia::test]
fn test_difference() {
let base = CAP_BPF | CAP_AUDIT_WRITE;
let expected = CAP_BPF;
assert_eq!(base.difference(CAP_AUDIT_WRITE), expected);
assert_eq!(base.difference(CAP_AUDIT_WRITE | CAP_BPF), Capabilities::empty());
}
#[::fuchsia::test]
fn test_contains() {
let base = CAP_BPF | CAP_AUDIT_WRITE;
assert_eq!(base.contains(CAP_AUDIT_WRITE), true);
assert_eq!(base.contains(CAP_BPF), true);
assert_eq!(base.contains(CAP_AUDIT_WRITE | CAP_BPF), true);
assert_eq!(base.contains(CAP_AUDIT_CONTROL), false);
assert_eq!(base.contains(CAP_AUDIT_WRITE | CAP_BPF | CAP_AUDIT_CONTROL), false);
}
#[::fuchsia::test]
fn test_insert() {
let mut capabilities = CAP_BLOCK_SUSPEND;
capabilities.insert(CAP_BLOCK_SUSPEND);
assert_eq!(capabilities, CAP_BLOCK_SUSPEND);
capabilities.insert(CAP_AUDIT_READ);
let expected = Capabilities { mask: CAP_BLOCK_SUSPEND.mask | CAP_AUDIT_READ.mask };
assert_eq!(capabilities, expected);
}
#[::fuchsia::test]
fn test_remove() {
let mut capabilities = CAP_BLOCK_SUSPEND;
capabilities.remove(CAP_BLOCK_SUSPEND);
assert_eq!(capabilities, Capabilities::empty());
let mut capabilities = CAP_BLOCK_SUSPEND | CAP_AUDIT_READ;
capabilities.remove(CAP_AUDIT_READ);
assert_eq!(capabilities, CAP_BLOCK_SUSPEND);
}
#[::fuchsia::test]
fn test_try_from() {
let capabilities = CAP_BLOCK_SUSPEND;
assert_eq!(Capabilities::try_from(CAP_BLOCK_SUSPEND), Ok(capabilities));
assert_eq!(Capabilities::try_from(200000), Err(EINVAL));
}
}