Files
Elyz/kernel/docs/capability/introduction.md
2026-07-07 16:40:41 +03:00

5.3 KiB
Raw Permalink Blame History

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

cnode.mint(src, dest, relation, rights)
  • src — исходный слот (должен иметь GRANT).
  • dest — целевой слот (должен быть пустым).
  • relation — как наследник связан с родителем.
  • rights — права наследника (∩ с правами родителя).

Revoke — отзыв capability

cnode.revoke(slot_idx)
  1. Рекурсивно находит всех потомков и уничтожает их.
  2. Уничтожает сам capability.
  3. Отправляет token_sig в глобальную MMU_REVOCATION_QUEUE.
  4. VMM при следующем page fault обрабатывает все накопленные отзывы.

Lock Ranking — предотвращение дедлоков

В mint() захватываются две блокировки (src и dest). Чтобы избежать инверсии блокировок, используется строгий порядок:

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()

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);