Se ha implementado un modo de verificación de límites de búferes en Clang para el lenguaje C.

Los ingenieros de Apple han anunciado la disponibilidad para pruebas del modo «-fbounds-safety» para el compilador Clang, que proporciona garantías sobre el manejo seguro de los búferes en el código en C. Este modo está incluido en el fork de LLVM, respaldado por Apple para el proyecto Swift. Se planea en el futuro una transición gradual de la funcionalidad «-fbounds-safety» a la base de código principal de LLVM/Clang.

Se destaca que el mecanismo de protección propuesto ya se utiliza activamente en productos de Apple, como el núcleo XNU, firmware, bibliotecas de audio y decodificadores de imágenes. La activación del modo «-fbounds-safety» reduce el rendimiento de las aplicaciones en un promedio del 5% (con un rango de -1% a 29%), incrementa el tamaño del código en un 9.1% (rango de -1.4% a 38%) y ralentiza la compilación en un 11%.

El uso del modo «-fbounds-safety» para la detección automática de desbordamientos de memoria asociados a punteros requiere la adición de anotaciones especiales en el código e incluir el archivo de cabecera «ptrcheck.h». La esencia del método de protección propuesto radica en la adición automática de comprobaciones de cumplimiento de los límites permitidos, que se añaden en función de las anotaciones manuales o de los tamaños conocidos por el compilador.

A diferencia del uso de punteros extendidos (wide pointer) en el código, donde, además de la dirección, se tienen detalles sobre el límite superior e inferior del búfer, el uso del modo «-fbounds-safety» no interfiere con el ABI (Application Binary Interface), no altera el formato de los punteros exportados y no requiere una reestructuración inmediata de todo el proyecto. En el modo «-fbounds-safety», los punteros extendidos se aplican únicamente en áreas que no se cruzan con el ABI, mientras que para los punteros que afectan al ABI, se utilizan punteros normales con comprobaciones generadas en función de las anotaciones sobre los límites.

Las anotaciones deben agregarse a los punteros en los campos de las estructuras y parámetros de funciones que apuntan a una matriz de objetos, así como a variables globales con punteros. No es necesario agregar anotaciones para los punteros en variables locales, ya que se procesan automáticamente como punteros extendidos que ya incluyen información sobre los límites permitidos. El compilador emite sugerencias sobre las construcciones en el código para las cuales se requiere añadir anotaciones al ejecutarse con el flag «-fbounds-safety».

El modelo de protección basado en «-fbounds-safety» se puede implementar gradualmente, archivo por archivo, sin interrumpir el desarrollo de todo el proyecto. La adición de protección al proyecto consiste en especificar anotaciones en un archivo de código específico, eliminar las advertencias del compilador y realizar pruebas de funcionamiento del programa, repitiendo estos pasos para el siguiente archivo. El código con las anotaciones añadidas permanece compatible con el código C normal y con los compiladores que no soportan «-fbounds-safety» (al compilar con otros compiladores o al compilar sin la bandera «-fbounds-safety», simplemente no se agregarán comprobaciones adicionales de límites).

Durante la ejecución del programa, si se detecta un acceso fuera de los límites permitidos, se genera una excepción y el programa finaliza su ejecución. También puede ocurrir un cierre inesperado si se especifican anotaciones incorrectas, por lo que al usar «-fbounds-safety» se debe realizar una prueba adicional de funcionamiento del programa.

En el siguiente ejemplo, en el parámetro «int *p» se insertó la anotación «__counted_by(n)», que agrega una verificación adicional de límites válidos, que se realiza durante la ejecución. Si se intenta compilar el código en modo «-fbounds-safety» sin especificar esta anotación, el compilador emitirá una advertencia sobre la falta de información de los límites del arreglo al procesar la expresión «p[i] = 0». #include void init_buf(int *__counted_by(n) p, int n) { for (int i = 0; i < n; ++i) p[i] = 0; // en modo «-fbounds-safety» el compilador automáticamente insertará una verificación, similar al código «if (i = n) trap();» }

Para las variables locales con punteros, las verificaciones se adjuntan automáticamente, por ejemplo: void foo(int i){ char *buf = (char *)malloc(10); // para el puntero buf se guardará información sobre los límites buf[i] = 0xff; // se insertará automáticamente una verificación «if (buf + i = buf + 10) trap();» }

Siempre que sea posible, el compilador realiza optimizaciones y excluye la adición de código innecesario, si ya hay verificaciones necesarias en el código. Por ejemplo: for (size_t i = 0; i < count; ++i) { buf[i] = i; // la verificación "if (i = count) trap()" no se añadirá, ya que ya existe la condición «i < count" y i no puede ser menor que 0. }

Anotaciones principales:

  • «__counted_by(N)» — define el tamaño del búfer en elementos del tipo de destino.
  • «__sized_by(N)» — define el tamaño del búfer en bytes.
  • » __ended_by(P)» — establece el límite superior del búfer.
  • «__null_terminated» — considera el símbolo nulo como el final del búfer.
  • «__single» — vincula el puntero a un solo objeto. Se usa por defecto para punteros que afectan el ABI, a menos que se especifique explícitamente de otra manera.
  • «__bidi_indexable» — puntero extendido con información sobre los límites superior e inferior. Se usa por defecto para punteros que no afectan el ABI.
  • «__indexable» — puntero extendido con información sobre el límite superior.
  • «__unsafe_indexable» — puntero sin verificación de límites (para compatibilidad con código no seguro, por ejemplo, para obtener punteros de código externo).

Fuente: opennet.ru

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster