College Online
0%

Controle de Acesso

Módulo 8 · Aula 1 ~25 min de leitura Nível: Intermediário

Vídeo da aula estará disponível em breve

Proteção vs Segurança

Proteção é um mecanismo interno do SO: controlar quais processos podem acessar quais recursos. Segurança é mais amplo: garantir integridade do sistema contra ameaças externas (malware, invasores, exploits). Proteção é a base sobre a qual segurança é construída.

Proteção e segurança — escopo
PROTEÇÃO (mecanismos internos):
  ├── Quem pode ler /etc/shadow?
  ├── Quem pode matar o processo do outro usuário?
  ├── Quem pode acessar a porta 80?
  └── Quem pode montar um filesystem?

SEGURANÇA (ameaças externas):
  ├── Como impedir que malware escale privilégios?
  ├── Como detectar um buffer overflow exploit?
  ├── Como autenticar quem diz ser "root"?
  └── Como isolar um processo comprometido?

Princípio fundamental:
  LEAST PRIVILEGE (menor privilégio)
  Cada processo deve ter apenas as permissões mínimas
  necessárias para executar sua tarefa.

  Exemplo: servidor web Apache
    - Precisa: ler /var/www, escutar porta 80
    - NÃO precisa: ler /etc/shadow, carregar módulos do kernel
    - Roda como usuário "www-data", não como root

Domínios de Proteção

Um domínio de proteção define um conjunto de pares (recurso, permissões). Cada processo executa dentro de um domínio que determina o que ele pode fazer.

Diagrama — Domínios de proteção
Domínio D0 (root):
  { (arquivo1, read/write/exec), (arquivo2, read/write),
    (impressora, print), (rede, listen/connect),
    (kernel, load_module) }

Domínio D1 (user marco):
  { (arquivo1, read), (arquivo3, read/write),
    (impressora, print), (rede, connect) }

Domínio D2 (user www-data):
  { (/var/www/*, read), (porta 80, listen),
    (rede, connect) }

No Unix/Linux, o domínio é definido por:
  - UID (User ID): identifica o usuário
  - GID (Group ID): identifica o grupo
  - Supplementary groups: grupos adicionais
  - Capabilities: permissões granulares do kernel

Troca de domínio:
  - su / sudo: muda para domínio de outro usuário
  - setuid: processo assume domínio do dono do arquivo
  - login: após autenticação, cria domínio do usuário

Matriz de Acesso

A matriz de acesso é o modelo teórico de proteção. Linhas representam domínios (sujeitos), colunas representam objetos (recursos), e cada célula contém as operações permitidas.

Diagrama — Matriz de acesso
            │ arquivo1 │ arquivo2 │ arquivo3 │ impressora │ porta80 │
  ──────────┼──────────┼──────────┼──────────┼────────────┼─────────┤
  root      │ r,w,x    │ r,w      │ r,w,x    │ print      │ listen  │
  ──────────┼──────────┼──────────┼──────────┼────────────┼─────────┤
  marco     │ r        │          │ r,w      │ print      │         │
  ──────────┼──────────┼──────────┼──────────┼────────────┼─────────┤
  www-data  │          │          │ r        │            │ listen  │
  ──────────┼──────────┼──────────┼──────────┼────────────┼─────────┤

A matriz é ESPARSA (maioria das células vazia).
Não é prático armazenar como matriz completa.
Duas implementações reais:
  1. ACL: armazena por COLUNA (por objeto)
  2. Capability: armazena por LINHA (por sujeito)

ACLs (Access Control Lists)

ACLs armazenam a matriz por coluna: cada objeto lista quem pode acessá-lo e como. É a abordagem usada pelo Unix/Linux (permissões rwx) e pelo Windows (NTFS ACLs).

Shell — Permissões Unix (ACL simplificada)
# Permissões Unix clássicas: owner, group, others
$ ls -la /etc/passwd /etc/shadow
-rw-r--r-- 1 root root   2847 mai 1 /etc/passwd
-rw-r----- 1 root shadow 1501 mai 1 /etc/shadow

# Decodificando: -rw-r--r--
# tipo│owner│group│others
#  -  │rw-  │r--  │r--
# file│read+│read │read
#     │write│only │only

# /etc/shadow: -rw-r-----
# owner (root): read+write
# group (shadow): read only
# others: NADA (senhas protegidas)

# Modificar permissões
$ chmod 750 script.sh    # rwxr-x--- (owner all, group r+x, others none)
$ chmod u+x,g-w arquivo  # +exec owner, -write group

# ACLs estendidas (POSIX ACLs) — mais granulares
$ getfacl documento.txt
# file: documento.txt
# owner: marco
# group: devs
user::rw-
user:ana:r--         # ana pode ler (além do owner/group/others)
group::rw-
group:qa:r--         # grupo qa pode ler
mask::rw-
other::---

$ setfacl -m u:ana:rw documento.txt  # dar read+write para ana

Capabilities (Capacidades)

Capabilities armazenam a matriz por linha: cada sujeito carrega um token que lista o que pode fazer. Em vez de o arquivo listar quem pode acessá-lo, o processo carrega uma lista do que pode acessar.

ACL vs Capability
ACL (por objeto):
  arquivo.txt: { (marco, rw), (ana, r), (root, rwx) }
  ✓ Fácil ver QUEM tem acesso a um recurso
  ✓ Fácil revogar acesso a um recurso (edita a ACL)
  ✗ Difícil ver tudo que um usuário pode acessar

Capability (por sujeito):
  marco: { (arquivo.txt, rw), (dir/*, r), (porta 8080, listen) }
  ✓ Fácil ver o que um processo pode fazer
  ✓ Fácil delegar: "dê ao subprocess estas capabilities"
  ✗ Difícil revogar: como retirar capability de todos os processos?

Linux usa AMBOS:
  - ACLs: permissões de arquivo (rwx, POSIX ACLs)
  - Capabilities: permissões de kernel (cap_net_bind_service, etc.)

Linux capabilities (granularidade fina em vez de root):
  CAP_NET_BIND_SERVICE  → escutar portas < 1024
  CAP_NET_RAW           → usar raw sockets (ping)
  CAP_SYS_ADMIN         → mount, sethostname, etc.
  CAP_DAC_OVERRIDE      → ignorar permissões de arquivo
  CAP_KILL              → enviar sinais a qualquer processo
Shell — Capabilities no Linux
# Ver capabilities de um executável
$ getcap /usr/bin/ping
/usr/bin/ping cap_net_raw=ep

# Dar capability a um executável (em vez de setuid root)
$ sudo setcap cap_net_bind_service=+ep /usr/bin/node
# Agora node pode escutar porta 80 sem ser root!

# Ver capabilities do processo atual
$ grep Cap /proc/self/status
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 000001ffffffffff

# Decodificar
$ capsh --decode=000001ffffffffff

RBAC (Role-Based Access Control)

Em vez de atribuir permissões diretamente a usuários, RBAC cria papéis (roles) com conjuntos de permissões, e atribui usuários a papéis. É o modelo dominante em sistemas empresariais.

Diagrama — RBAC
Sem RBAC (permissões diretas):
  marco → { ler_código, escrever_código, deploy, ler_logs }
  ana   → { ler_código, escrever_código, ler_logs }
  bob   → { ler_código, ler_logs }
  (cada novo usuário: configurar tudo manualmente)

Com RBAC (via papéis):
  Papéis:
    dev_senior → { ler_código, escrever_código, deploy, ler_logs }
    dev_junior → { ler_código, escrever_código, ler_logs }
    leitor     → { ler_código, ler_logs }

  Atribuições:
    marco → dev_senior
    ana   → dev_junior
    bob   → leitor

  Novo dev junior? Basta: assign(carol, dev_junior)
  Sem editar permissão por permissão.

Implementações:
  Linux: groups (parcialmente RBAC — group = role)
  Postgres: GRANT role TO user
  Kubernetes: RBAC nativo (ClusterRole, RoleBinding)
  AWS IAM: policies attached to roles

setuid e setgid

O bit setuid permite que um processo execute com as permissões do dono do arquivo, não do usuário que o executou. É o mecanismo que permite que programas como passwd e su funcionem.

Shell — setuid na prática
# passwd precisa escrever em /etc/shadow (owned by root)
$ ls -la /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 /usr/bin/passwd
  ↑
  s = setuid bit! Executa como root, independente de quem chamou.

# Quando marco executa passwd:
# 1. Shell de marco (UID=1000) chama exec("/usr/bin/passwd")
# 2. Kernel vê bit setuid → EUID muda para 0 (root)
# 3. passwd roda com EUID=0, pode escrever /etc/shadow
# 4. passwd termina, EUID volta ao normal

# Perigo: setuid root + bug = escalação de privilégios
# Se passwd tiver um buffer overflow, atacante ganha root!

# Listar todos os binários setuid no sistema
$ find / -perm -4000 -type f 2>/dev/null
/usr/bin/passwd
/usr/bin/su
/usr/bin/sudo
/usr/bin/mount
/usr/bin/newgrp

# setgid: mesma ideia, mas com GID
$ ls -la /usr/bin/wall
-rwxr-sr-x 1 root tty 19024 /usr/bin/wall
       ↑ s no grupo = setgid
i
Eliminando setuid com capabilities A tendência moderna é substituir binários setuid root por binários com capabilities específicas. Em vez de ping ser setuid root (acesso total ao sistema), ele recebe apenas CAP_NET_RAW (permissão para raw sockets). Se ping tiver um bug, o atacante ganha apenas raw sockets, não root completo. É o princípio de menor privilégio aplicado.

No harness.os

O controle de acesso do SO tem paralelo direto com como o harness.os gerencia permissões de agentes:

Diagrama — Controle de acesso no harness.os
Modelo de proteção do SO        harness.os
═══════════════════════         ══════════

UID/GID                         Agent ID / Session ID
  Identifica o sujeito            Identifica quem está operando

Domínio de proteção             Escopo do agente
  Conjunto de permissões          Tools disponíveis + regras ativas
  de um processo                  Definidos pelo project_slug

ACL (por recurso)               Row-Level Security (Postgres)
  arquivo: quem pode r/w/x        Tabela: quem pode SELECT/INSERT
  /etc/shadow: root + shadow       decisions: agente vê só suas

Capabilities                    MCP Tools
  Permissões granulares            Cada tool é uma capability
  cap_net_bind → escutar porta     log_decision → pode logar decisão
  cap_sys_admin → mount            run_sql → acesso direto ao banco

RBAC (papéis)                   Agent Roles (futuro)
  dev_senior → deploy              build_agent → build tools
  leitor → read-only               review_agent → read-only + govern

Least privilege:
  Agente de QA não precisa de run_sql
  Agente de build não precisa de govern_audit_decisions
  Cada agente recebe apenas as tools necessárias

Exercícios

  1. Execute find / -perm -4000 -type f 2>/dev/null no seu sistema. Quantos binários setuid existem? Escolha 3 e explique por que precisam de setuid (qual recurso privilegiado acessam).
  2. Crie um arquivo secreto.txt com chmod 600. Verifique que outro usuário não pode lê-lo. Depois, use setfacl -m u:outro_usuario:r secreto.txt para dar acesso de leitura apenas a esse usuário. Explique a diferença entre permissões Unix tradicionais e POSIX ACLs.
  3. Projete um esquema RBAC para um sistema com 3 papéis (admin, dev, viewer) e 4 recursos (código, deploy, logs, config). Desenhe a matriz de acesso e explique como adicionar um novo dev seria mais fácil com RBAC do que com ACLs diretas.

Resumo

Verifique seu entendimento

Qual é o principal risco de segurança dos binários setuid root?

  • Eles ocupam mais espaço em disco por terem permissões extras
  • Eles só podem ser executados pelo root, limitando a usabilidade
  • Se o binário tiver uma vulnerabilidade, um atacante pode obter acesso root completo ao sistema
  • Eles desabilitam o journaling do filesystem enquanto executam