Como os CVEs de segurança de memória diferem entre Rust e C/C++

Rust, comportamento indefinido e unsafe

  • Alguns argumentam que UB pode ocorrer em Rust sem usar diretamente unsafe no seu crate: via no_std, falhas de correção da linguagem, UB em dependências ou na biblioteca padrão, ou bugs do compilador/LLVM.
  • Outros enfatizam o modelo do Rust: a UB precisa se originar em algum unsafe em algum lugar (incluindo em dependências ou na std); a vantagem é que unsafe fica localizado e pode ser revisado.

Semântica de overflow de inteiros

  • Há disputa sobre o comportamento do Rust de “panic no debug, wrap no release”.
  • Críticos dizem que ter dois comportamentos torna o overflow praticamente tão pouco confiável quanto UB e gostariam que o overflow sempre causasse panic.
  • Outros ressaltam que isso é definido pela implementação, não UB: o comportamento é limitado e configurável (overflow-checks = true), ao contrário da UB em C/C++ que pode levar a otimizações incorretas extremas.

Como interpretar CVEs de Rust

  • Bibliotecas Rust tendem a tratar qualquer uso incorreto que possa causar UB como um CVE, mesmo que a exploração seja irrealista.
  • Ecossistemas C/C++ raramente classificam esses problemas como CVEs, então o número bruto de “CVEs” é visto como uma métrica enganosa para a segurança de uma linguagem.
  • Alguns temem que isso possa se estender a panics serem tratados como vulnerabilidades de DoS; outros veem isso como parte de uma cultura que prioriza correção.

Prevalência e importância de bugs de segurança de memória

  • Um comentarista afirma que bugs de memória são uma fração minúscula das vulnerabilidades “médias”; outros contestam isso e citam dados (na própria thread) de que problemas de segurança de memória dominam zero-days de alto impacto.
  • Há debate sobre se portar grandes bases de código para Rust seria uma sobre-otimização ou algo justificado para software de alto valor e muito atacado (navegadores, componentes de sistema operacional, Android).

Estratégias de segurança em Rust vs C++ moderno

  • Um lado argumenta que C++ moderno, junto com bibliotecas fortalecidas, sanitizers e guidelines, pode em grande parte resolver bugs de memória se usado de forma consistente.
  • Contra-argumentos:
    • Na prática, muitas bases grandes em C/C++ continuam inseguras (Android, Chromium, bibliotecas de sistema).
    • A segurança é o padrão em Rust; em C++ ela costuma exigir opt-in, disciplina cuidadosa e toolchains que as equipes frequentemente afrouxam sob pressão de entrega.
    • Relatos do mundo real (por exemplo, Android) são citados como evidência de que Rust gera grandes reduções em vulnerabilidades de memória em comparação com código legado em C/C++.

Nulls, assertions e contratos

  • Discussão em torno de funções como curl_getenv e se deve haver assert para entradas nulas.
  • Alguns defendem verificações de pré-condição em todo lugar; outros argumentam que, em C, isso vira ruído e muitas vezes descamba para “crash de qualquer forma em uma dereferência nula”.
  • O Option<T> do Rust e referências não nulas são contrastados: APIs precisam optar explicitamente por None, e o uso incorreto leva a panics com backtraces claros em vez de UB.

Desempenho e tendências de adoção

  • Exemplos como a reescrita do parser HTML do Ladybird mostram Rust substituindo C++ com desempenho igual ou melhor.
  • Há debate sobre se os ganhos de velocidade vêm do Rust em si ou das oportunidades de redesenho durante as reescritas.
  • C e C++ são vistos como perdendo espaço em alguns domínios (navegadores, kernels), embora muitos domínios (HPC, HFT, stacks orientadas por padrões) ainda girem em torno de C/C++.

Complexidade do Rust e preocupações com dependências

  • Críticos destacam a complexidade conceitual do Rust (ownership, lifetimes, tipos avançados) e o esforço gasto para moldar tipos a fim de satisfazer o borrow checker.
  • Defensores enquadram isso como “tornar a complexidade explícita” em vez de escondê-la, produzindo código mais seguro e mais fácil de depurar.
  • Há preocupação ampla com grandes árvores profundas de dependências em Rust (stdlib enxuta, muitos crates, build.rs, publicação atrelada ao GitHub) e o risco correspondente de supply chain.
  • Defensores observam que C/C++ muitas vezes “resolvem” isso fazendo vendor ou copy-paste de código, o que obscurece as dependências em vez de eliminá-las.