Archived
134 lines
4.4 KiB
Rust
134 lines
4.4 KiB
Rust
//! Capability System.
|
|
//!
|
|
//! Capability — это токен (unforgeable token), дающий право на определённую
|
|
//! операцию над определённым объектом ядра.
|
|
|
|
use alloc::vec::Vec;
|
|
use bitflags::bitflags;
|
|
use core::sync::atomic::{AtomicU64, Ordering};
|
|
|
|
bitflags! {
|
|
/// Набор прав, которые даёт capability.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub struct Rights: u32 {
|
|
/// Право на чтение (read / receive).
|
|
const READ = 1 << 0;
|
|
/// Право на запись (write / send).
|
|
const WRITE = 1 << 1;
|
|
/// Право на передачу capability другому процессу.
|
|
const GRANT = 1 << 2;
|
|
/// Право маппировать память объекта в адресное пространство.
|
|
const MAP = 1 << 3;
|
|
/// Право управлять объектом (изменять параметры).
|
|
const MANAGE = 1 << 4;
|
|
|
|
/// Полный набор прав.
|
|
const ALL = Self::READ.bits() | Self::WRITE.bits()
|
|
| Self::GRANT.bits() | Self::MAP.bits()
|
|
| Self::MANAGE.bits();
|
|
}
|
|
}
|
|
|
|
/// Тип объекта ядра, на который ссылается capability.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum KernelObject {
|
|
/// Канал IPC (для обмена сообщениями).
|
|
Channel(u64),
|
|
/// Регион физической памяти.
|
|
MemoryObject { phys: u64, size: usize },
|
|
/// Прерывание (IRQ).
|
|
Interrupt(u8),
|
|
/// Поток выполнения.
|
|
Thread(u64),
|
|
/// Адресное пространство (процесс).
|
|
AddressSpace(u64),
|
|
}
|
|
|
|
/// Capability — токен доступа к объекту ядра.
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct Capability {
|
|
/// Уникальный идентификатор capability.
|
|
pub id: u64,
|
|
/// Набор прав.
|
|
pub rights: Rights,
|
|
/// Объект, к которому даётся доступ.
|
|
pub object: KernelObject,
|
|
}
|
|
|
|
static CAP_ID_COUNTER: AtomicU64 = AtomicU64::new(1);
|
|
|
|
impl Capability {
|
|
/// Создать capability с полными правами (только ядро).
|
|
pub fn new_full(object: KernelObject) -> Self {
|
|
let id = CAP_ID_COUNTER.fetch_add(1, Ordering::Relaxed);
|
|
Capability { id, rights: Rights::ALL, object }
|
|
}
|
|
|
|
/// Создать capability с заданными правами.
|
|
pub fn new(rights: Rights, object: KernelObject) -> Self {
|
|
let id = CAP_ID_COUNTER.fetch_add(1, Ordering::Relaxed);
|
|
Capability { id, rights, object }
|
|
}
|
|
|
|
/// Проверить наличие права.
|
|
pub fn has(&self, right: Rights) -> bool {
|
|
self.rights.contains(right)
|
|
}
|
|
|
|
/// Создать производный capability с урезанными правами.
|
|
pub fn derive(&self, restrict_to: Rights) -> Option<Capability> {
|
|
if !self.has(Rights::GRANT) {
|
|
return None;
|
|
}
|
|
let id = CAP_ID_COUNTER.fetch_add(1, Ordering::Relaxed);
|
|
Some(Capability {
|
|
id,
|
|
rights: self.rights & restrict_to,
|
|
object: self.object,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// Таблица capabilities процесса.
|
|
#[derive(Debug, Clone)]
|
|
pub struct CapabilityTable {
|
|
entries: Vec<Option<Capability>>,
|
|
}
|
|
|
|
impl CapabilityTable {
|
|
pub fn new() -> Self {
|
|
CapabilityTable {
|
|
entries: Vec::new(),
|
|
}
|
|
}
|
|
|
|
/// Получить capability по индексу.
|
|
pub fn get(&self, index: usize) -> Option<&Capability> {
|
|
self.entries.get(index).and_then(|opt| opt.as_ref())
|
|
}
|
|
|
|
/// Добавить capability, вернуть индекс в таблице.
|
|
pub fn insert(&mut self, cap: Capability) -> usize {
|
|
for (i, entry) in self.entries.iter_mut().enumerate() {
|
|
if entry.is_none() {
|
|
*entry = Some(cap);
|
|
return i;
|
|
}
|
|
}
|
|
let idx = self.entries.len();
|
|
self.entries.push(Some(cap));
|
|
idx
|
|
}
|
|
|
|
/// Отозвать capability по индексу.
|
|
pub fn revoke(&mut self, index: usize) -> bool {
|
|
if let Some(entry) = self.entries.get_mut(index) {
|
|
if entry.is_some() {
|
|
*entry = None;
|
|
return true;
|
|
}
|
|
}
|
|
false
|
|
}
|
|
}
|