Os sistemas operacionais modernos impõem limites de segurança entre processos, arquivos, dispositivos e usuários. No entanto, a forma como esses limites são implementados varia significativamente entre diferentes projetos de sistema.

A maioria dos sistemas operacionais convencionais depende de controle de acesso baseado em identidade e de espaços de nomes globais. Sistemas operacionais baseados em capacidades adotam uma abordagem fundamentalmente diferente: representam a autoridade explicitamente e a tornam um conceito de primeira classe.

Este artigo apresenta sistemas baseados em capacidades, explica como eles diferem de modelos tradicionais e descreve por que são centrais para o design do EriX.


O problema: autoridade ambiente

Em sistemas tradicionais, processos frequentemente têm acesso a recursos por meio de autoridade ambiente.

Autoridade ambiente significa que um programa pode acessar um recurso simplesmente porque ele existe em um espaço de nomes compartilhado e o sistema determina que o programa tem permissão para usá-lo.

Por exemplo:

  • Um processo pode abrir /etc/passwd se tiver permissões suficientes.
  • Um programa pode se conectar a um socket de rede se o sistema operacional permitir.
  • Um serviço pode acessar arquivos com base na identidade do usuário ou na associação a grupos.

Em todos esses casos, a autoridade para acessar o recurso é implícita.

O processo não possui uma referência direta e explícita ao recurso. Em vez disso, depende de:

  • nomes globais (caminhos de arquivo, portas, identificadores de dispositivo)
  • verificações de acesso (IDs de usuário, permissões, ACLs)

Esse modelo cria vários problemas:

1. Problema do delegado confuso

Um programa pode acidentalmente usar sua autoridade de forma indevida em nome de outro programa.

Por exemplo, um serviço privilegiado pode ler um arquivo solicitado por um cliente não confiável, mesmo que esse cliente não devesse ter acesso a ele.

2. Autoridade ampla demais

Programas frequentemente executam com mais permissões do que realmente precisam. Isso aumenta o impacto de bugs ou comprometimentos.

3. Raciocínio difícil

É difícil determinar o que um processo pode fazer sem analisar o estado global, as identidades de usuário e as políticas de controle de acesso.


A ideia central: capacidades

Uma capacidade é um token não falsificável que concede acesso a um objeto específico com direitos específicos.

Em vez de perguntar:

“Este processo tem permissão para acessar este recurso?”

um sistema baseado em capacidades pergunta:

“Este processo possui uma capacidade que autoriza esta operação?”

Se a resposta for não, a operação não pode prosseguir.


Propriedades das capacidades

Capacidades têm várias propriedades definidoras:

1. Não falsificabilidade

Um processo não pode criar uma capacidade válida do nada.

Capacidades são criadas e gerenciadas pelo kernel, o que garante que não possam ser falsificadas nem adivinhadas.


2. Autoridade explícita

Toda autoridade é representada explicitamente por meio de capacidades.

Se um processo pode executar uma operação, ele deve possuir uma capacidade que a permita. Não existe acesso implícito por meio de espaços de nomes globais.


3. Direitos granulares

Capacidades podem codificar permissões específicas, como:

  • acesso somente leitura
  • acesso de escrita
  • permissões de execução
  • subconjuntos limitados de operações

Isso permite controle preciso sobre o que cada processo pode fazer.


4. Transferibilidade

Capacidades podem ser transferidas entre processos, normalmente por meio de comunicação entre processos (IPC).

Isso permite delegação controlada de autoridade.


Objetos e capacidades

Em um sistema baseado em capacidades, tudo é modelado como um objeto:

  • regiões de memória
  • arquivos
  • dispositivos
  • endpoints de IPC
  • processos

Uma capacidade é uma referência a um objeto combinada com um conjunto de direitos.

Um processo interage com o sistema invocando operações sobre objetos por meio de suas capacidades.

Não há necessidade de nomes globais como caminhos de arquivo ou identificadores de dispositivo dentro do kernel. Todo acesso é mediado por capacidades.


Como sistemas baseados em capacidades funcionam

Em alto nível, um sistema baseado em capacidades funciona assim:

  1. O kernel cria objetos e capacidades.
  2. Cada processo possui um espaço de capacidades (frequentemente chamado de CSpace), que armazena suas capacidades.
  3. Um processo só pode operar sobre objetos para os quais possui capacidades.
  4. Capacidades podem ser transferidas entre processos por meio de IPC.
  5. O kernel impõe todas as verificações de capacidades.

Isso resulta em um sistema no qual a autoridade é:

  • explícita
  • localizada
  • transferível
  • fácil de analisar

Exemplo: abrir um arquivo

Modelo tradicional

Em um sistema tradicional:

  1. Um processo chama open("/etc/config")
  2. O kernel verifica permissões:
    • ID de usuário
    • associação a grupos
    • bits de modo do arquivo
  3. Se permitido, um descritor de arquivo é retornado

A autoridade vem de estado global e identidade.


Modelo baseado em capacidades

Em um sistema baseado em capacidades:

  1. Um processo já deve possuir uma capacidade de arquivo
  2. Ele usa essa capacidade para realizar operações de leitura ou escrita

Se o processo não tiver a capacidade, ele não poderá acessar o arquivo, independentemente do nome que usar.

Não existe etapa de busca global dentro do kernel.


Delegação e menor privilégio

Um dos aspectos mais poderosos de sistemas baseados em capacidades é a delegação.

Um processo pode dar a outro processo um subconjunto de sua autoridade transferindo uma capacidade.

Por exemplo:

  • Um servidor de arquivos dá a um cliente acesso somente leitura a um arquivo
  • Um gerenciador de memória concede acesso a uma região específica de memória
  • Um processo concede acesso a um endpoint de IPC

Isso viabiliza o princípio do menor privilégio:

Cada componente recebe apenas a autoridade de que realmente precisa.


Eliminando a autoridade ambiente

Sistemas baseados em capacidades eliminam completamente a autoridade ambiente.

Não há:

  • espaços de nomes globais dentro do kernel
  • acesso implícito baseado em identidade
  • privilégios ocultos

Toda autoridade deve ser passada explicitamente.

Isso torna muito mais fácil analisar:

  • o que um processo pode fazer
  • como a autoridade flui pelo sistema
  • onde podem surgir problemas de segurança

Revogação (um problema difícil)

Um dos desafios em sistemas baseados em capacidades é a revogação.

Depois que uma capacidade é dada a um processo, como ela pode ser retirada?

Diferentes sistemas implementam revogação de maneiras diferentes:

  • camadas de indireção
  • rastreamento de referências
  • árvores de capacidades
  • mecanismos de versionamento

Revogação é uma área importante de pesquisa e será explorada em estágios posteriores do EriX.


Sistemas baseados em capacidades na prática

Ideias baseadas em capacidades não são novas. Vários sistemas as implementaram:

  • KeyKOS / EROS
  • seL4 (um micronúcleo formalmente verificado)
  • CHERI (capacidades assistidas por hardware)
  • Capsicum (extensões de capacidades para FreeBSD)

Esses sistemas demonstram que projetos baseados em capacidades são ao mesmo tempo práticos e poderosos.


Como o EriX usa capacidades

O EriX foi projetado desde o início como um sistema baseado em capacidades.

No EriX:

  • toda autoridade é representada por meio de capacidades
  • capacidades são fortemente tipadas
  • capacidades são imutáveis depois de criadas
  • capacidades são transferidas via IPC
  • o kernel impõe não falsificabilidade e invariantes de segurança

Não há espaços de nomes globais dentro do kernel. Todo acesso a recursos é mediado por capacidades.

Isso se alinha ao objetivo mais amplo de tornar a autoridade:

  • explícita
  • mínima
  • fácil de analisar

Por que isso importa

Sistemas baseados em capacidades fornecem uma base para construir:

  • sistemas mais seguros
  • arquiteturas mais modulares
  • sistemas mais fáceis de analisar e verificar

Ao remover autoridade implícita e tornar todo acesso explícito, eles eliminam classes inteiras de vulnerabilidades comuns em sistemas tradicionais.


Olhando adiante

Capacidades são um conceito fundamental no EriX. Em artigos futuros, exploraremos como elas são implementadas na prática, incluindo:

  • espaços de capacidades (CSpace)
  • comunicação entre processos (IPC)
  • gerenciamento de memória usando capacidades não tipadas
  • delegação e grafos de autoridade

Entender capacidades é o primeiro passo para entender o restante do sistema.