127 lines
5.3 KiB
Markdown
127 lines
5.3 KiB
Markdown
# Capability-система: концептуальная модель
|
||
|
||
## Философия
|
||
|
||
**Capability** (дескриптор возможности) — это **неподделываемый токен**,
|
||
дающий право выполнить определённую операцию над определённым объектом.
|
||
|
||
В традиционных ОС (Linux, Windows) доступ контролируется через:
|
||
- PID + UID/GID + проверка при каждом системном вызове.
|
||
- MMU: page tables определяют, что отображено, но не кто отобразил.
|
||
|
||
В модели capabilities:
|
||
- **Если у вас нет capability — у вас нет доступа.**
|
||
- Capability хранятся в CNode — защищённой таблице, доступной только ядру.
|
||
- Capability можно создавать только от родительского capability
|
||
(иерархия наследования).
|
||
- Права можно только **урезать** (mint), но не расширить.
|
||
- Capability можно **отозвать** (revoke), что уничтожает его
|
||
и всех его потомков.
|
||
|
||
## Основные понятия
|
||
|
||
```
|
||
Capability {
|
||
object: CapObject, // на что указывает (Memory, CNode, PMActor...)
|
||
rights: CapRights, // права (R, W, X, G)
|
||
relation: Relation, // Strong (владеет), Borrow (заём), Transfer
|
||
token_sig: u64, // уникальный идентификатор (для revoke)
|
||
}
|
||
|
||
Relation {
|
||
Strong: владеет объектом (capability владеет памятью)
|
||
Borrow: заём — временный доступ без права распоряжаться
|
||
Transfer: передача — владение переходит получателю
|
||
}
|
||
|
||
CapRights {
|
||
READ = 0x1,
|
||
WRITE = 0x2,
|
||
EXECUTE = 0x4,
|
||
GRANT = 0x8, // разрешение создавать дочерние capability
|
||
}
|
||
```
|
||
|
||
## Иерархия и отзыв
|
||
|
||
```
|
||
CNode (массив слотов)
|
||
┌────────┬────────┬────────┬────────┐
|
||
│ slot 0 │ slot 1 │ slot 2 │ slot 3 │ ...
|
||
├────────┼────────┼────────┼────────┤
|
||
│ cap │ cap │ cap │ cap │
|
||
│ parent:│ parent:│ parent:│ parent:│
|
||
│ None │ Some(0)│ Some(0)│ Some(1)│
|
||
└────────┴────────┴────────┴────────┘
|
||
│
|
||
┌────────┴────────┐
|
||
▼ ▼
|
||
slot 1 slot 2
|
||
(mint from 0) (mint from 0)
|
||
|
||
revoke(0) → slot 0 уничтожается
|
||
→ рекурсивно: slot 1, slot 2 тоже уничтожаются
|
||
→ token_sig slot 0 отправляется в MMU_REVOCATION_QUEUE
|
||
→ VMM обработает отзыв при следующем page fault
|
||
```
|
||
|
||
### Mint — создание дочернего capability
|
||
|
||
```rust
|
||
cnode.mint(src, dest, relation, rights)
|
||
```
|
||
|
||
- `src` — исходный слот (должен иметь GRANT).
|
||
- `dest` — целевой слот (должен быть пустым).
|
||
- `relation` — как наследник связан с родителем.
|
||
- `rights` — права наследника (∩ с правами родителя).
|
||
|
||
### Revoke — отзыв capability
|
||
|
||
```rust
|
||
cnode.revoke(slot_idx)
|
||
```
|
||
|
||
1. Рекурсивно находит всех потомков и уничтожает их.
|
||
2. Уничтожает сам capability.
|
||
3. Отправляет `token_sig` в глобальную `MMU_REVOCATION_QUEUE`.
|
||
4. VMM при следующем page fault обрабатывает все накопленные отзывы.
|
||
|
||
## Lock Ranking — предотвращение дедлоков
|
||
|
||
В `mint()` захватываются две блокировки (src и dest). Чтобы избежать
|
||
инверсии блокировок, используется строгий порядок:
|
||
|
||
```rust
|
||
let (src_slot, dest_slot) = if src < dest {
|
||
// Захватываем меньший индекс первым
|
||
_guard_low = self.slots[src].lock();
|
||
_guard_high = self.slots[dest].lock();
|
||
} else {
|
||
_guard_low = self.slots[dest].lock();
|
||
_guard_high = self.slots[src].lock();
|
||
};
|
||
```
|
||
|
||
## Интеграция с VMM
|
||
|
||
При отзыве capability, VMM должна аннулировать все VMA, связанные
|
||
с отозванным токеном. Для этого:
|
||
|
||
1. `revoke()` пушит `token_sig` в lock-free очередь.
|
||
2. При page fault: `process_pending_revocations()` дренирует очередь.
|
||
3. VMA с `cap_token == token_sig` удаляются из AddressSpace.
|
||
4. TLB flush для синхронизации MMU.
|
||
|
||
## Использование в kmain()
|
||
|
||
```rust
|
||
let root_cnode = CNode::new(256);
|
||
// Вставка capability на фрейм
|
||
root_cnode.insert(0, mem_cap).unwrap();
|
||
// Mint с урезанными правами
|
||
root_cnode.mint(0, 10, Relation::Borrow, R | W).unwrap();
|
||
// Revoke — отзыв всех потомков
|
||
root_cnode.revoke(0);
|
||
```
|