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".
Dado que 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 una buena idea usar estas cosas viejas.
Mi pregunta es:
¿El uso de un compilador de C antiguo puede comprometer la seguridad del programa compilado?
ACTUALIZAR:
Visual Studio 2008 crea el mismo código para los destinos de Windows, y MSVC aún no es compatible con C99 o C11 (no sé si el MSVC más nuevo lo hace), y puedo compilarlo en mi caja de Linux usando el último GCC. Entonces, si colocáramos un GCC más nuevo, probablemente se construiría tan bien como antes.
-O3 -Wall -Wextra -fsanitize=undefined
gcc moderno y clang debería ayudar.Respuestas:
En realidad, yo dirí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 base de código fue escrita por personas que trataron a C como un "ensamblador portátil". Con el paso del tiempo, los optimizadores han comenzado a buscar fragmentos de código cada vez más grandes al hacer estas optimizaciones, lo que aumenta la posibilidad de que el binario termine haciendo algo diferente de "lo que haría un binario creado por un compilador tonto".
Hay modificadores de compilación para restaurar el comportamiento "tradicional" (-fwrapv y -fno-estricto-aliasing para los dos que mencioné anteriormente), pero primero debes 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.
fuente
people who treated C like a "portable assembler"
¿No es lo que es C?Hay 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 solucionado 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 :
Instrumentar su binario con los desinfectantes (Address Sanitizer, Memory Sanitizer o Undefined Behavior Sanitizer) y luego confundirlo (usando American Fuzzy Lop, por ejemplo) ha descubierto vulnerabilidades en una serie de softwares de alto perfil, consulte, por ejemplo, este artículo de LWN.net .
Esas nuevas herramientas, y todas las herramientas futuras, son inaccesibles para usted a menos que actualice su compilador.
Al permanecer en un compilador de poca 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 comprobar la vulnerabilidad de todos modos; tenga en cuenta que, dado que son compiladores diferentes, las garantías se reducen.
fuente
Su código compilado contiene errores que podrían explotarse. Los errores provienen de tres fuentes: errores en su código fuente, errores en el compilador y bibliotecas, y 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. Por 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 la corrección de errores debido a los informes de errores de los clientes. Por lo tanto, es posible que haya habido una gran cantidad de errores inicialmente, pero eso se ha ido.
Si actualiza a un compilador más nuevo, puede perder errores que fueron introducidos por errores del compilador. Pero estos errores serían todos errores que, según tu conocimiento, nadie encontró y nadie explotó. Pero el nuevo compilador puede tener errores por sí solo 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.
Por lo que tendrá muchos errores nuevos en su código compilado; todos los errores que los piratas informáticos podrían encontrar y explotar. Y a menos que realice muchas pruebas y deje su código a los clientes para que encuentren errores durante mucho tiempo, será menos seguro.
fuente
getaddrinfo()
: access.redhat.com/articles/2161461 . Ese ejemplo no es en realidad una falla de seguridad del compilador, pero durante más de 10 años seguramente habrá algunas fallas corregidas conocidas.Si no está roto, no lo arregles
Su jefe suena correcto al decir esto, sin embargo, lo más importante factor es salvaguardar las entradas, salidas y desbordamientos de 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 del código es antigua, y se trabajó para mitigar las debilidades del K&R C utilizado, como la falta de seguridad de tipos, fgets inseguros, etc., sopese la pregunta " ¿Actualizaría el compilador a un C99 más moderno? / ¿Los estándares C11 lo rompen todo? "
Siempre que haya un camino claro para migrar a los estándares C más nuevos, lo que podría inducir efectos secundarios, lo mejor sería intentar una bifurcación del código base anterior, evaluarlo y realizar verificaciones de tipo adicionales, verificaciones de cordura y determinar si se actualiza a el compilador más nuevo tiene algún efecto en los conjuntos de datos de entrada / salida.
Luego puede mostrárselo a su jefe, " Aquí está el código base actualizado, refactorizado, más en línea con los estándares C99 / C11 aceptados por la industria ... ".
Esa es la apuesta en la que habría que sopesar, con mucho cuidado , la resistencia al cambio podría mostrarse allí en ese entorno y podría negarse a tocar las cosas más nuevas.
EDITAR
Me senté unos minutos, me di cuenta de esto, el código generado por K&R podría estar ejecutándose en una plataforma de 16 bits, lo más probable es que la actualización a un compilador más moderno 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 los conjuntos de datos de entrada / salida, que es otro gran factor que se debe 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 Linux, entonces sería Vale la pena intentarlo, es posible que tenga que incluir cambios adicionales en el compilador para minimizar el ruido en la base del código K&R antiguo, la otra cosa importante es realizar muchas pruebas para asegurarse de que no se rompa ninguna funcionalidad, puede resultar un ejercicio doloroso.
fuente
Por supuesto que puede, si el compilador antiguo contiene errores conocidos que usted sabe que afectarían 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 corregido a lo largo de los años.
Si no encuentra evidencia de errores del compilador que puedan afectar su programa, actualizar GCC por el simple hecho de hacerlo parece un poco paranoico. Debería tener en cuenta que las versiones más recientes pueden contener errores nuevos que aún no se han descubierto. Recientemente se realizaron muchos cambios con el soporte de GCC 5 y C11.
Dicho esto, es muy probable que el código escrito en los años 80 ya esté lleno hasta el borde con agujeros de seguridad y dependencia de un comportamiento mal definido, sin importar el compilador. Estamos hablando de C preestándar aquí.
fuente
Existe un riesgo de seguridad en el que un desarrollador malintencionado puede colarse por la 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, en el nivel fuente. Revisiones y pruebas del código fuente usando un compilador sin errores no encontrará la puerta trasera, porque la puerta trasera no existe en estas condiciones). Para puntos de negación adicionales, el desarrollador malintencionado también puede buscar errores del compilador previamente desconocidos por su cuenta. Nuevamente, 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 más y más y más agresiva, por lo que el código C de edad que fue escrito de buena fe en realidad sería segura compilado más con un compilador C del tiempo, o recopilada en el -O0 (pero algunas optimizaciones nuevas de explotación de UB que rompen el programa se introducen en nuevas versiones de compiladores incluso en -O0 ).
fuente
Es posible que los compiladores más antiguos no tengan protección contra ataques de piratería conocidos. La protección contra la rotura de pilas, por ejemplo, no se introdujo hasta GCC 4.1 . Así que sí, el código compilado con compiladores más antiguos puede ser vulnerable en formas contra las que los compiladores más nuevos protegen.
fuente
Otro aspecto del que preocuparse es el desarrollo de nuevo código .
Los compiladores más antiguos pueden tener un comportamiento diferente para algunas características del lenguaje de lo que está estandarizado y esperado por el programador. Este desajuste puede ralentizar el desarrollo e introducir errores sutiles que se pueden aprovechar.
Los compiladores más antiguos ofrecen menos funciones (¡incluidas funciones de lenguaje!) Y no optimizan tan bien. Los programadores solucionarán estas deficiencias, por ejemplo, reimplementando las funciones faltantes o escribiendo código inteligente que es oscuro pero se ejecuta más rápido, creando nuevas oportunidades para la creación de errores sutiles.
fuente
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 actualizando a un nuevo compilador. Su cambio de errores y exploits antiguos por nuevos errores y exploits.
fuente
Bueno, existe una mayor probabilidad de que cualquier error en el compilador antiguo sea bien conocido y documentado en lugar de usar un compilador nuevo, por lo que se pueden tomar acciones para evitar esos errores codificando alrededor de ellos. Entonces, de alguna manera, eso no es suficiente como argumento para actualizar. Tenemos las mismas discusiones donde yo trabajo, usamos GCC 4.6.1 en una base de código para software embebido y hay una gran renuencia (entre la administración) a actualizar al último compilador por temor a errores nuevos e indocumentados.
fuente
Tu pregunta se divide en dos partes:
Quizás pueda responder tanto encontrando un defecto explotable en su base de código existente como mostrando que un compilador más nuevo lo habría detectado. Por supuesto, su administración puede decir "lo encontró con el compilador antiguo", pero puede señalar que costó un esfuerzo considerable. O lo ejecuta a través del nuevo compilador para encontrar la vulnerabilidad, luego explótelo, si puede / tiene permiso para 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 mostrarles el código (y usar el nuevo compilador).
Pero si su sistema no está expuesto a 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 de 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.fuente