Durante décadas, C e seus descendentes imediatos foram as linguagens de programação preferidas para programação de sistemas. No início da década de 1970, quando C foi desenvolvido, foi um importante avanço em relação à linguagem assembly. Cinquenta anos depois, podemos fazer melhor.
A segurança de computadores não estava no radar da maioria das pessoas em 1970 e por muitos anos depois disso. A primeira grande vulnerabilidade de segurança na internet ocorreu muitos anos depois, em 1988. Ele era conhecido como worm da internet e se aproveitava de um estouro de buffer, onde uma matriz na memória era indexada fora de seus limites.
Na família da linguagem C, que inclui C++, os arrays não têm seus limites verificados. Cabe ao programador garantir que o array seja acessado corretamente. Portanto, erros de estouro de buffer são comuns. Pior, é fácil causar deliberadamente um estouro de buffer e, assim, acessar memória que não deveria.
O estouro de buffer é apenas um exemplo de insegurança de memória . Outros exemplos relacionados incluem aritmética de ponteiros e ponteiros pendurados (também conhecidos como bugs de uso após liberação). Hoje, temos muitas linguagens de programação que empregam uma variedade de técnicas para garantir que qualquer programa escrito nessas linguagens esteja livre de problemas de segurança de memória. A família de linguagens C não oferece tal garantia; a segurança da memória nunca foi um objetivo de design dessas linguagens.
Cerca de 70% das vulnerabilidades de segurança são devidas a violações da segurança da memória. Essa afirmação é apoiada por dados esmagadores. A segurança da memória é responsável por:
Em julho de 2022, 5/6 das vulnerabilidades corrigidas no Chrome 103.0.5060.134 eram problemas de segurança de memória. Claramente, eliminar bugs de segurança de memória seria extremamente útil. A indústria sabe como fazer isso há muitos anos: usar linguagens de programação com segurança de memória. Historicamente, o problema sempre foi o custo associado em termos de desempenho. Devido à importância da segurança da memória, as pessoas têm trabalhado em novas estratégias para alcançá-la sem a sobrecarga tradicional. Hoje sabemos como eliminar erros de segurança de memória com pouco ou nenhum custo de tempo de execução. Linguagens como Rust usam inovações no design do sistema de tipos para garantir a segurança da memória sem suporte de tempo de execução dispendioso.
Isso leva a uma conclusão inevitável: pare de escrever novos códigos de sistemas em C/C++ (ou, mais genericamente, em linguagens inseguras em termos de memória).
Isto não é um apelo para reescritas massivas e indiscriminadas do código existente. Substituir software existente é caro e não isento de riscos. No entanto, a indústria deve parar de agravar o problema adicionando mais código inseguro em termos de memória às bases de código existentes. Para o código existente, priorize a reescrita dos componentes mais sensíveis: aqueles que são responsáveis por validar ou consumir entradas de usuários não confiáveis, aqueles que são executados em um contexto privilegiado, aqueles que são executados fora de uma sandbox, etc.
Essa posição, embora amplamente defendida, ainda é controversa para alguns. Aqui estão alguns dos argumentos comuns apresentados em favor do status quo e nossas respostas a eles.
Veja Quantificação da Insegurança da Memória e Reações a Ela para uma discussão detalhada dos pontos acima.
Apesar das objeções, o ímpeto para as mudanças necessárias está crescendo. Grandes investimentos estão sendo feitos na Open Source Software Security Foundation (apoiada pela Linux Foundation), por exemplo. A segurança da memória foi discutida nos EUA Relatórios do Senado e da NSA . A Consumer Reports também trabalha para identificar os vários incentivos que poderiam acelerar esse movimento, oferecendo uma série de recomendações para empresas e agências estaduais.
Para resumir:
A importância da computação para a sociedade cresceu enormemente nos últimos cinquenta anos. O cenário de ameaças à nossa infraestrutura de computação também mudou radicalmente nas últimas décadas. Entretanto, as linguagens de programação que usamos para construir nossos sistemas de computação não mudaram de acordo. A falta de segurança de memória é a maior fonte de vulnerabilidades de segurança em software. Isso não é peculiar a nenhum tipo específico de software, pois em todos os lugares onde linguagens inseguras de memória são usadas, problemas de segurança de memória abundam. E em números, nenhuma outra classe de vulnerabilidade chega perto.
Agora temos os meios para resolver esse problema crescente e é crucial que nós, como indústria, façamos isso. Felizmente, o reconhecimento da situação está se espalhando, mas o problema é urgente e não há tempo a perder.