Esto es Ubuntu 9.04, 2.6.28-11-server, 32bit x86
$ cat test.c
main() { int *dt = (int *)0x08049f18; *dt = 1; }
$ readelf -S ./test
...
[18] .dtors PROGBITS 08049f14 000f14 000008 00 WA 0 0 4
...
$ ./test
Segmentation fault
$
Para los no iniciados: gcc crea un segmento destructor .dtors
, en el ejecutable elf, que se llama después de las main()
salidas. Esta tabla ha sido editable durante mucho tiempo, y parece que debería ser en mi caso (ver readelf
salida). Pero intentar escribir en la tabla causa una falla por defecto.
Me doy cuenta de que ha habido un movimiento hacia los .dtors de solo lectura, plt, que se obtuvieron últimamente, pero lo que no entiendo es la falta de coincidencia entre readelf
y la falla predeterminada.
memory
gcc
segmentation-fault
Fixee
fuente
fuente
Respuestas:
Esas secciones están marcadas GNU_RELRO (reubicaciones de solo lectura), lo que significa que tan pronto como el cargador dinámico haya reparado (en el momento de la carga, no hay reubicaciones diferidas allí) todas las reubicaciones, marca esas secciones como de solo lectura. Tenga en cuenta que la mayor parte
.got.plt
está en otra página, por lo que no recibe el tratamiento.Puede ver el script del enlazador con
ld --verbose
, si busca RELRO encontrará algo similar a:lo que significa que las secciones RELRO terminan en 12 bytes
.got.plt
(los punteros a las funciones del enlazador dinámico ya están resueltos, por lo que pueden marcarse como de solo lectura).El proyecto Gentoo endurecido tiene documentación sobre RELRO en http://www.gentoo.at/proj/en/hardened/hardened-toolchain.xml#RELRO .
fuente
Puedo decir por qué está fallando, aunque en realidad no sé qué parte del sistema es responsable. Si bien
.dtors
está marcado como editable en el binario, parece que (junto con.ctors
el GOT y algunas otras cosas) se están asignando a una página separada y no editable en la memoria. En mi sistema,.dtors
se está poniendo en0x8049f14
:Si ejecuto el ejecutable y compruebo
/proc/PID/maps
, veo:.data
/.bss
todavía se pueden escribir en su propia página, pero los demás0x8049000-0x804a000
no. Supongo que esta es una característica de seguridad en el kernel (como dijiste, "ha habido un movimiento hacia solo .dtors, plt, últimamente"), pero no sé específicamente cómo se llama (OpenBSD tiene algo muy similar llamado W ^ X ; Linux tiene PaX , pero no está integrado en la mayoría de los núcleos)Puede solucionarlo con
mprotect
, lo que le permite cambiar los atributos en memoria de una página:Con eso, mi programa de prueba no se bloquea, pero si intento sobrescribir el centinela final de
.dtors
(0x8049f18
) con la dirección de otra función, esa función aún no se ejecuta; esa parte no puedo entenderlo.Esperemos que alguien más sepa qué es responsable de hacer que la página sea de solo lectura y por qué la modificación
.dtors
no parece hacer nada en mi sistemafuente
mprotect
no puede hacer que una página ejecutable se pueda escribir o hacer que una página sea ejecutable antes, a menos que esa característica esté deshabilitadapaxctl -m
.