OpenBSD – fixando todas as chamadas de sistema

O novo recurso de “pinning” de syscalls do OpenBSD — que restringe de onde e quais chamadas de sistema um binário pode invocar — está gerando debate sobre quanta proteção real ele oferece contra técnicas modernas de exploração como ROP, e se ele apenas reforça caminhos de ataque já raros. Os comentaristas contrapõem o histórico do OpenBSD de mitigações proativas, às vezes especulativas, a preocupações com complexidade adicional, modelos de ameaça pouco claros e a descoberta de um overflow de buffer nesta própria implementação. O debate também aborda questões mais amplas de prática de engenharia de segurança, incluindo a dependência de C versus a adoção de Rust ou verificações mais fortes do compilador, e como medir o valor de mitigações que podem prevenir, e não apenas corrigir, vulnerabilidades.

Escopo da nova fixação de syscalls

  • O kernel agora restringe syscalls de forma mais rigorosa:
    • Antes: syscalls só eram permitidas a partir da região de texto da libc dos processos.
    • Agora: fixadas a stubs específicos de syscall da libc.
    • Para binários estáticos: apenas as syscalls efetivamente referenciadas no binário são permitidas; as demais ficam, na prática, desativadas.
  • O .text do programa não pode mais executar syscalls diretamente; elas precisam passar pela libc (ou pelo ld.so durante a inicialização).
  • Runtimes de linguagem normalmente chamam a libc, então continuam utilizáveis; runtimes “weirdo” ou JITs que sintetizam syscalls brutas em tempo de execução podem ser bloqueados.

Impacto na segurança e técnicas de exploração

  • A fixação reduz alguma liberdade de ROP/JOP:
    • Não dá mais para transformar qualquer instrução syscall alcançável em uma syscall arbitrária; apenas o número de syscall registrado é permitido.
    • Ainda é possível abusar dos argumentos da syscall permitida (por exemplo, ainda chamar execve se o programa normalmente o faz).
  • Para binários estáticos, atacantes não podem fazer ROP para syscalls que o programa nunca usou (por exemplo, execve se estiver ausente), o que é visto como um confinamento útil.
  • JITs ainda podem saltar para thunks de syscall permitidos; JavaScript no navegador, em geral, não faz syscalls diretamente de qualquer forma.
  • Outro efeito de mitigação: syscalls restringidas à libc complicam o bypass de ASLR quando o atacante só conhece o layout do binário principal e procura por padrões de bytes syscall no texto.

Debate sobre eficácia e modelagem de ameaças

  • Visões favoráveis:
    • Se a mitigação é barata e não adiciona superfície de ataque, vale a pena incluí-la.
    • O OpenBSD historicamente implantou mitigações antes de classes de ataques serem públicas (por exemplo, desativar hyperthreading antes de Spectre/Meltdown; aleatoriedade “desnecessária” que mais tarde bloqueou ataques a cache DNS).
    • Baixos números de CVE e mitigações que antecipam vulnerabilidades são citados como evidência de boa intuição.
  • Visões céticas:
    • Mitigações sem mapeamento explícito para explorações reais/CVEs e cadeias de exploração testadas são criticadas como “amorfas” e potencialmente “teatro de segurança”.
    • Toda mitigação adiciona complexidade e custo de manutenção de longo prazo; sem um modelo de ameaça claro, isso pode degradar a segurança no geral.
    • Alguns argumentam que, se uma mitigação não interrompe claramente técnicas atuais em circulação, é em grande parte um exercício acadêmico.
    • Outros respondem que focar estreitamente em “CVEs corrigidas” recompensa erros do passado e subestima bugs evitados.

Bug de implementação descoberto

  • Um bug trivial, mas real, foi encontrado no novo código:
    • Mistura de signed/unsigned em uma macro MAX permite que um atacante force uma contagem interna (npins) a ficar negativa, levando a subalocação e escritas fora dos limites no heap indexadas por números de syscall controlados pelo atacante.
    • Um esboço de exploração exemplo usa entradas de tabela de “pinned syscall” cuidadosamente forjadas para primeiro envenenar a memória e depois forçar npins a -1, que é então limitado a um pequeno valor positivo antes da alocação.
  • Discussão sobre ferramentas:
    • Alguns observam que verificações de inteiros/tipagem no estilo Rust poderiam ter evitado essa classe de bug.
    • Outros apontam que compiladores C já têm flags (por exemplo, warnings de comparação com sinal, sanitizers, traps de overflow) que poderiam ter detectado isso, mas que não estão universalmente habilitadas.

C vs. Rust e as restrições do OpenBSD

  • Rust é elogiado por semântica de inteiros mais segura e verificação de tipos, mas:
    • O OpenBSD tem ~dezenas de milhões de linhas de C, muitas plataformas e pouquíssima mão de obra.
    • Reescrever ou integrar profundamente Rust no código central do SO é visto como de alto risco e intensivo em recursos.
  • Alguns argumentam que novos sistemas operacionais voltados para segurança deveriam começar com Rust; outros enfatizam que Rust não é bala de prata e que código C maduro, com ferramentas cuidadosas, ainda pode ser viável.

Meta: postura de segurança e ecossistema do OpenBSD

  • Alguns participantes dizem que a base de usuários do OpenBSD é pequena demais para existir um rico “meta” de exploração conhecido empiricamente, então boa parte disso é extrapolada de outras plataformas.
  • Há tensão entre:
    • Pessoas que veem o slogan e a reputação do OpenBSD como exagerados ou enganosos.
    • Pessoas que veem o trabalho contínuo de hardening e o número relativamente baixo de falhas graves como justificativa suficiente, e ficam intrigadas com tentativas agressivas de desencorajar outros a usá-lo.