programa ejecutar con compilar como comando c security gcc

ejecutar - ¿Usar un compilador de C obsoleto es un riesgo de seguridad?



compilar y ejecutar c en linux gcc (11)

Tenemos algunos sistemas de construcción en producción que a nadie le importan y estas máquinas ejecutan versiones antiguas de GCC como GCC 3 o GCC 2.

Y no puedo persuadir a la gerencia para que lo actualice a uno más reciente: dicen, "si no está roto, no lo arregles".

Como mantenemos una base de código muy antigua (escrita en los años 80), este código C89 se compila muy bien en estos compiladores.

Pero no estoy seguro de que sea buena idea usar estas cosas viejas.

Mi pregunta es:

¿El uso de un antiguo compilador de C puede comprometer la seguridad del programa compilado?

ACTUALIZAR:

Visual Studio 2008 creó el mismo código para los objetivos de Windows, y MSVC aún no es compatible con C99 o C11 (no sé si MSVC más reciente sí lo hace), y puedo construirlo en mi caja de Linux usando el último GCC. Entonces, si simplemente añadiéramos un GCC más nuevo, probablemente se construiría tan bien como antes.


¿El uso de un antiguo compilador de C puede comprometer la seguridad del programa compilado?

Por supuesto que puede, si el compilador anterior contiene errores conocidos que usted podría afectar a su programa.

La pregunta es, ¿verdad? Para estar seguro, tendría que leer todo el registro de cambios desde su versión hasta la fecha actual y verificar cada error solucionado a lo largo de los años.

Si no encuentra evidencia de errores del compilador que afecten a su programa, actualizar GCC solo por el simple hecho de que parezca un poco paranoico. Debería tener en cuenta que las versiones más nuevas pueden contener nuevos errores que aún no se han descubierto. Se hicieron muchos cambios recientemente con el soporte de GCC 5 y C11.

Dicho esto, el código escrito en los años 80 probablemente ya esté lleno hasta el borde con agujeros de seguridad y dependencia de un comportamiento mal definido, sin importar el compilador. Estamos hablando de pre-estándar C aquí.


No

La razón es simple, el compilador antiguo puede tener errores y exploits antiguos, pero el nuevo compilador tendrá errores y exploits nuevos.

No está "arreglando" ningún error al actualizar a un nuevo compilador. Su cambio de viejos errores y exploits por nuevos errores y exploits.


Bueno, existe una mayor probabilidad de que cualquier error en el compilador anterior sea bien conocido y documentado en lugar de usar un compilador nuevo, por lo que se pueden tomar medidas para evitar esos errores codificando a su alrededor. Entonces, de una manera que no es suficiente como argumento para actualizar. Tenemos las mismas discusiones donde trabajo, utilizamos GCC 4.6.1 en una base de código para software embebido y existe una gran renuencia (entre la administración) a actualizar al compilador más reciente por temor a nuevos errores no documentados.


En realidad, argumentaría lo contrario.

Hay una serie de casos en los que el estándar C no define el comportamiento, pero es obvio lo que sucedería con un "compilador tonto" en una plataforma determinada. Casos como permitir que un entero con signo se desborde o acceder a la misma memoria a través de variables de dos tipos diferentes.

Las versiones recientes de gcc (y clang) han comenzado a tratar estos casos como oportunidades de optimización sin importarles si cambian el comportamiento del binario en la condición de "comportamiento indefinido". Esto es muy malo si su código base fue escrito por personas que trataron a C como un "ensamblador portátil". A medida que pasó el tiempo, los optimizadores comenzaron a buscar fragmentos de código cada vez más grandes al hacer estas optimizaciones, lo que aumenta las posibilidades de que el binario termine haciendo algo más que "lo que haría un binario construido por un compilador tonto".

Hay modificadores del compilador para restaurar el comportamiento "tradicional" (-fwrapv y -fno-estricto-alias para los dos que mencioné anteriormente), pero primero debe conocerlos.

Si bien, en principio, un error del compilador podría convertir el código compatible en un agujero de seguridad, consideraría que el riesgo de esto es insignificante en el gran esquema de las cosas.


Existe un riesgo de seguridad en el que un desarrollador malintencionado puede colarse por una puerta trasera a través de un error del compilador. Dependiendo de la cantidad de errores conocidos en el compilador en uso, la puerta trasera puede parecer más o menos discreta (en cualquier caso, el punto es que el código es correcto, incluso si es complicado, a nivel fuente. Revisiones y pruebas de código fuente usando un compilador sin errores no encontrará la puerta trasera, porque la puerta trasera no existe en estas condiciones). Para obtener puntos de negación adicionales, el desarrollador malintencionado también puede buscar errores de compilación previamente desconocidos por su cuenta. Una vez más, la calidad del camuflaje dependerá de la elección de los errores del compilador encontrados.

Este ataque se ilustra en el programa sudo en este artículo . bcrypt escribió un excelente seguimiento para los minificadores de Javascript .

Además de esta preocupación, la evolución de los compiladores de C ha sido para explotar un comportamiento indefinido more y more y more agresiva, tan viejo código C que fue escrito de buena fe en realidad sería seguro compilado más con un compilador C del tiempo, o recopilada en el -O0 (pero algunas nuevas optimizaciones para explotar UB que rompen el programa se introducen en nuevas versiones de compiladores incluso en -O0 ).


Existen riesgos en ambos cursos de acción.

Los compiladores más antiguos tienen la ventaja de la madurez, y todo lo que se rompió en ellos probablemente (pero no hay garantía) se ha trabajado con éxito.

En este caso, un nuevo compilador es una fuente potencial de nuevos errores.

Por otro lado, los compiladores más nuevos vienen con herramientas adicionales :

  • GCC y Clang ahora cuentan con desinfectantes que pueden instrumentar el tiempo de ejecución para detectar comportamientos indefinidos de diversos tipos (Chandler Carruth, del equipo de compiladores de Google, afirmó el año pasado que espera que hayan alcanzado una cobertura total)
  • Clang, al menos, presenta endurecimiento , por ejemplo, Control Flow Integrity se trata de detectar hi-jacks de control de flujo, también hay implementos de endurecimiento para proteger contra ataques de aplastamiento de pila (separando la parte de flujo de control de la pila de la parte de datos) ; Las características de endurecimiento son generalmente una baja sobrecarga (<1% sobrecarga de la CPU)
  • Clang / LLVM también está trabajando en libFuzzer , una herramienta para crear pruebas unitarias de fuzzing instrumentadas que exploran el espacio de entrada de la función bajo prueba de manera inteligente (ajustando la entrada para tomar rutas de ejecución aún no exploradas)

Instrumentar su binario con los desinfectantes (Address Sanitizer, Memory Sanitizer o Undefined Behavior Sanitizer) y luego difuminarlo (usando American Fuzzy Lop, por ejemplo) ha descubierto vulnerabilidades en varios softwares de alto perfil, consulte, por ejemplo, este artículo de LWN.net .

Estas nuevas herramientas, y todas las herramientas futuras, son inaccesibles para usted a menos que actualice su compilador.

Al permanecer en un compilador de baja potencia, está metiendo la cabeza en la arena y cruzando los dedos para que no se encuentre ninguna vulnerabilidad. Si su producto es un objetivo de alto valor, le insto a que lo reconsidere.

Nota: incluso si NO actualiza el compilador de producción, es posible que desee utilizar un nuevo compilador para verificar la vulnerabilidad de todos modos; Tenga en cuenta que, dado que se trata de compiladores diferentes, las garantías se reducen.


Los compiladores más antiguos pueden no tener protección contra ataques de piratería conocidos. La protección de aplastamiento de la pila, por ejemplo, no se introdujo hasta GCC 4.1 . Entonces, sí, el código compilado con compiladores más antiguos puede ser vulnerable en formas contra las cuales los compiladores más nuevos protegen.


Otro aspecto de qué preocuparse es el desarrollo de un nuevo código .

Los compiladores más antiguos pueden tener un comportamiento diferente para algunas características del lenguaje que lo que el programador estandariza y espera. Este desajuste puede retrasar el desarrollo e introducir errores sutiles que pueden ser explotados.

Los compiladores más antiguos ofrecen menos funciones (¡incluidas las funciones de idioma!) Y no se optimizan también. Los programadores resolverán estas deficiencias, por ejemplo, reimplementando características faltantes o escribiendo código inteligente que sea oscuro pero se ejecute más rápido, creando nuevas oportunidades para la creación de errores sutiles.


Su código compilado contiene errores que podrían ser explotados. Los errores provienen de tres fuentes: errores en su código fuente, errores en el compilador y bibliotecas, y un comportamiento indefinido en su código fuente que el compilador convierte en un error. (El comportamiento indefinido es un error, pero aún no es un error en el código compilado. Como ejemplo, i = i ++; en C o C ++ es un error, pero en su código compilado puede aumentar i en 1 y estar bien, o establecer yo a un poco de basura y ser un error).

La tasa de errores en su código compilado es presumiblemente baja debido a las pruebas y a la corrección de errores debido a los informes de errores del cliente. Por lo tanto, puede haber una gran cantidad de errores inicialmente, pero eso se ha reducido.

Si actualiza a un compilador más nuevo, puede perder los errores introducidos por los errores del compilador. Pero todos estos errores serían errores que, hasta donde usted sabe, nadie encontró y nadie explotó. Pero el nuevo compilador puede tener errores por sí mismo, y lo que es más importante, los compiladores más nuevos tienen una tendencia más fuerte a convertir el comportamiento indefinido en errores en el código compilado.

Entonces tendrá muchos errores nuevos en su código compilado; todos los errores que los piratas informáticos pueden encontrar y explotar. Y a menos que haga muchas pruebas y deje su código con los clientes para encontrar errores durante mucho tiempo, será menos seguro.


Su pregunta se divide en dos partes:

  • Explícito: "¿Existe un mayor riesgo al utilizar el compilador anterior" (más o menos como en su título)
  • Implícito: "¿Cómo puedo persuadir a la gerencia para que actualice?"

Tal vez pueda responder a ambos encontrando un defecto explotable en su base de código existente y mostrando que un compilador más nuevo lo habría detectado. Por supuesto, su gerencia puede decir "lo encontró con el compilador anterior", pero puede señalar que le costó un esfuerzo considerable. O lo ejecuta a través del nuevo compilador para encontrar la vulnerabilidad, luego explótelo, si puede / permite compilar el código con el nuevo compilador. Es posible que desee la ayuda de un pirata informático amigable, pero eso depende de confiar en ellos y poder / permitirles mostrar el código (y usar el nuevo compilador).

Pero si su sistema no está expuesto a los piratas informáticos, tal vez debería estar más interesado en saber si una actualización del compilador aumentaría su efectividad: el análisis de código MSVS 2013 a menudo encuentra errores potenciales mucho antes que MSVS 2010, y es más o menos compatible con C99 / C11 - No estoy seguro si lo hace oficialmente, pero las declaraciones pueden seguir a las declaraciones y puede declarar variables en for -loops.


Si no está roto, no lo arregles

Su jefe suena bien al decir esto, sin embargo, el factor más importante es la protección de las entradas, salidas, desbordamientos del búfer. La falta de esos es invariablemente el eslabón más débil de la cadena desde ese punto de vista, independientemente del compilador utilizado.

Sin embargo, si la base de código es antiguo, y el trabajo se puso en marcha para mitigar las debilidades de la K & R C utilizados, tales como carentes de seguridad de tipos, fgets inseguros, etc, sopesar la pregunta " ¿Quieres actualizar el compilador más moderna C99 / ¿Los estándares C11 rompen todo? "

Siempre que exista un camino claro para migrar a los estándares C más nuevos, lo que podría provocar efectos secundarios, podría ser mejor intentar una bifurcación de la base de código anterior, evaluarla y poner controles de tipo adicionales, controles de cordura y determinar si se actualiza a el compilador más reciente tiene algún efecto en los conjuntos de datos de entrada / salida.

Luego puede mostrárselo a su jefe, " Aquí está la base de código actualizada, refactorizada, más en línea con los estándares C99 / C11 aceptados por la industria ... ".

Esa es la apuesta que tendría que sopesarse, con mucho cuidado , la resistencia al cambio podría mostrarse allí en ese entorno y puede negarse a tocar las cosas más nuevas.

EDITAR

Solo me recosté unos minutos, me di cuenta de esto, el código generado por K&R podría ejecutarse en una plataforma de 16 bits, lo más probable es que la actualización a un compilador más moderno en realidad podría romper la base del código, estoy pensando en términos de arquitectura, se generaría un código de 32 bits , esto podría tener efectos secundarios divertidos en las estructuras utilizadas para conjuntos de datos de entrada / salida, que es otro gran factor a sopesar cuidadosamente.

Además, dado que OP ha mencionado el uso de Visual Studio 2008 para construir la base de código, el uso de gcc podría inducir la incorporación al entorno de MinGW o Cygwin, lo que podría tener un cambio de impacto en el entorno, a menos que el objetivo sea para Linux, entonces sería vale la pena intentarlo, puede que tenga que incluir interruptores adicionales en el compilador para minimizar el ruido en la antigua base de código K&R, la otra cosa importante es realizar muchas pruebas para garantizar que no se rompa ninguna funcionalidad, puede resultar un ejercicio doloroso.