c linux assembly mmap

Permiso de ejecución inesperado de mmap cuando se incluyen archivos de ensamblaje incluidos en el proyecto



linux assembly (2)

Estoy golpeando mi cabeza contra la pared con esto.

En mi proyecto, cuando estoy asignando memoria con mmap el mapeo ( /proc/self/maps ) muestra que es una región legible y ejecutable a pesar de que solo solicité memoria legible.

Después de analizar strace (que se veía bien) y otra depuración, pude identificar lo único que parece evitar este extraño problema: eliminar archivos de ensamblaje del proyecto y dejar solo C. (¡¿qué ?!)

Así que aquí está mi extraño ejemplo, estoy trabajando en Ubunbtu 19.04 y gcc por defecto.

Si compila el ejecutable de destino con el archivo ASM (que está vacío), entonces mmap devuelve una región legible y ejecutable, si construye sin él se comportará correctamente. Vea la salida de /proc/self/maps que he incrustado en mi ejemplo.

ejemplo.c

#include <stdio.h> #include <string.h> #include <sys/mman.h> int main() { void* p; p = mmap(NULL, 8192,PROT_READ,MAP_ANONYMOUS|MAP_PRIVATE,-1,0); { FILE *f; char line[512], s_search[17]; snprintf(s_search,16,"%lx",(long)p); f = fopen("/proc/self/maps","r"); while (fgets(line,512,f)) { if (strstr(line,s_search)) fputs(line,stderr); } fclose(f); } return 0; }

example.s : es un archivo vacío!

Salidas

Con la versión ASM incluida

VirtualBox:~/mechanics/build$ gcc example.c example.s -o example && ./example 7f78d6e08000-7f78d6e0a000 r-xp 00000000 00:00 0

Sin la versión incluida de ASM

VirtualBox:~/mechanics/build$ gcc example.c -o example && ./example 7f1569296000-7f1569298000 r--p 00000000 00:00 0


Como alternativa a la modificación de sus archivos de ensamblaje con variantes de directivas de sección específicas de GNU, puede agregar -Wa,--noexecstack a su línea de comando para construir archivos de ensamblaje. Por ejemplo, vea cómo lo hago en musl''s configure :

https://git.musl-libc.org/cgit/musl/commit/configure?id=adefe830dd376be386df5650a09c313c483adf1a

Creo que al menos algunas versiones de clang con ensamblador integrado pueden requerir que se pase como --noexecstack (sin -Wa ), por lo que su script de configuración probablemente debería verificar ambos y ver cuál es aceptado.

También puede usar -Wl,-z,noexecstack en el momento del enlace (en LDFLAGS ) para obtener el mismo resultado. La desventaja de esto es que no ayuda si su proyecto produce archivos de biblioteca estáticos ( .a ) para su uso por otro software, ya que luego no controla las opciones de tiempo de enlace cuando lo utilizan otros programas.


Linux tiene un dominio de ejecución llamado READ_IMPLIES_EXEC , que hace que todas las páginas asignadas con PROT_READ también reciban PROT_EXEC . Este programa le mostrará si está habilitado para sí mismo:

#include <stdio.h> #include <sys/personality.h> int main(void) { printf("Read-implies-exec is %s/n", personality(0xffffffff) & READ_IMPLIES_EXEC ? "true" : "false"); return 0; }

Si compila eso junto con un archivo .s vacío, verá que está habilitado, pero sin uno, estará deshabilitado. El valor inicial de esto proviene de la metainformación ELF en su binario . Hacer readelf -Wl example . Verá esta línea cuando compiló sin el archivo .s vacío:

GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10

Pero este cuando lo compiló:

GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x10

Tenga en cuenta RWE lugar de solo RW . La razón de esto es que el enlazador supone que sus archivos de ensamblaje requieren read-implica-exec a menos que se indique explícitamente que no lo hacen, y si alguna parte de su programa requiere read-implica-exec, entonces está habilitado para todo su programa . Los archivos de ensamblaje que compila GCC le dicen que no necesita esto, con esta línea (verá esto si compila con -S ):

.section .note.GNU-stack,"",@progbits

Ponga esa línea en example.s , y servirá para decirle al enlazador que tampoco la necesita, y su programa funcionará como se esperaba.