Cómo difieren los CVE de seguridad de memoria entre Rust y C/C++

Rust, comportamiento indefinido y unsafe

  • Algunos sostienen que el comportamiento indefinido (UB) puede ocurrir en Rust sin usar directamente unsafe en tu crate: a través de no_std, agujeros de corrección del lenguaje, UB en dependencias o en la biblioteca estándar, o errores del compilador/LLVM.
  • Otros enfatizan el modelo de Rust: el UB debe originarse en algún unsafe en alguna parte (incluidas dependencias o std); la ventaja es que unsafe queda localizado y es revisable.

Semántica del desbordamiento de enteros

  • Disputa sobre el comportamiento de Rust de “panic en debug, wrap en release”.
  • Los críticos dicen que tener dos comportamientos hace que el desbordamiento sea prácticamente tan poco fiable como el UB y desean que el desbordamiento siempre provocara panic.
  • Otros subrayan que esto está definido por la implementación, no es UB: el comportamiento está acotado y es configurable (overflow-checks = true), a diferencia del UB en C/C++ que puede llevar a desoptimizaciones extremas.

Cómo interpretar los CVE de Rust

  • Las bibliotecas de Rust tienden a tratar cualquier uso incorrecto que pueda causar UB como un CVE, incluso si la explotación es poco realista.
  • Los ecosistemas de C/C++ rara vez clasifican estos problemas como CVE, así que el número bruto de “CVE” se considera una métrica engañosa para la seguridad del lenguaje.
  • Algunos temen que esto pueda extenderse a que los panics se traten como vulnerabilidades DoS; otros lo ven como parte de una cultura que prioriza la corrección.

Prevalencia e importancia de los errores de seguridad de memoria

  • Un comentarista afirma que los errores de memoria son una fracción diminuta de las vulnerabilidades “promedio”; otros lo disputan y citan datos (dentro del hilo) que indican que los problemas de seguridad de memoria dominan los zero-days de alto impacto.
  • Se debate si portar grandes bases de código a Rust es una sobreoptimización o si está justificado para software de alto valor y muy atacado (navegadores, componentes del sistema operativo, Android).

Estrategias de seguridad en Rust frente a C++ moderno

  • Una postura sostiene que C++ moderno más bibliotecas endurecidas, sanitizers y guías puede resolver en gran medida los errores de memoria si se usa de forma consistente.
  • Puntos de contraste:
    • En la práctica, muchas bases de código grandes en C/C++ siguen siendo inseguras (Android, Chromium, bibliotecas del sistema).
    • La seguridad en Rust es el valor predeterminado; en C++ la seguridad a menudo requiere opt-in, disciplina cuidadosa y toolchains que los equipos suelen relajar bajo presión de entrega.
    • Se citan informes del mundo real (por ejemplo, Android) como evidencia de que Rust produce grandes reducciones en vulnerabilidades de memoria frente al código heredado en C/C++.

Nulls, assertions y contratos

  • Discusión en torno a funciones como curl_getenv y si conviene usar assert sobre entradas nulas.
  • Algunos defienden comprobaciones de precondiciones en todas partes; otros argumentan que en C esto se vuelve ruidoso y a menudo degenera en “crashear igual por una desreferencia nula”.
  • Se contrasta Option<T> de Rust y las referencias no anulables: las APIs deben optar explícitamente por None, y el uso incorrecto lleva a panics con trazas claras en lugar de UB.

Rendimiento y tendencias de adopción

  • Ejemplos como la reescritura del parser HTML de Ladybird muestran Rust sustituyendo a C++ con rendimiento igual o mejor.
  • Se debate si las ganancias de velocidad provienen de Rust en sí o de las oportunidades de rediseño durante las reescrituras.
  • Se considera que C y C++ están perdiendo terreno en algunos dominios (navegadores, kernels), aunque muchos ámbitos (HPC, HFT, stacks guiados por estándares) todavía giran en torno a C/C++.

Complejidad de Rust y preocupaciones sobre dependencias

  • Los críticos destacan la complejidad conceptual de Rust (ownership, lifetimes, tipos avanzados) y el esfuerzo dedicado a dar forma a los tipos para satisfacer al borrow checker.
  • Los partidarios lo presentan como “hacer explícita la complejidad” en lugar de ocultarla, logrando código más seguro y más fácil de depurar.
  • Hay una preocupación general por árboles de dependencias grandes y profundos en Rust (stdlib delgada, muchos crates, build.rs, publicación ligada a GitHub) y el riesgo correspondiente para la cadena de suministro.
  • Los defensores señalan que C/C++ a menudo “resuelven” esto vendorizando o copiando y pegando código, lo que oculta las dependencias en lugar de eliminarlas.