Il s'agit d'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
$
Pour les non initiés: gcc crée un segment destructeur,, .dtors
dans l'exécutable elf, qui est appelé après les main()
sorties. Ce tableau est accessible en écriture depuis longtemps, et il semble qu'il devrait l'être dans mon cas (voir la readelf
sortie). Mais tenter d'écrire dans la table provoque une erreur de segmentation.
Je me rends compte qu'il y a eu un mouvement vers les .dtors, plt, en lecture seule récemment, mais ce que je ne comprends pas, c'est l'inadéquation entre readelf
et la faute de segmentation.
memory
gcc
segmentation-fault
Fixee
la source
la source
Réponses:
Ces sections sont marquées GNU_RELRO (relocations en lecture seule), ce qui signifie que dès que le chargeur dynamique a corrigé (au moment du chargement, il n'y a pas de relocalisation paresseuse) toutes les délocalisations, il marque ces sections en lecture seule. Notez que la plupart se
.got.plt
trouve sur une autre page, donc ne reçoit pas le traitement.Vous pouvez voir le script de l'éditeur de liens avec
ld --verbose
, si vous recherchez RELRO, vous trouverez quelque chose de similaire à:ce qui signifie que les sections RELRO se terminent sur 12 octets
.got.plt
(les pointeurs vers les fonctions de l'éditeur de liens dynamiques sont déjà résolus, ils peuvent donc être marqués en lecture seule).Le projet Gentoo durci contient de la documentation sur RELRO à http://www.gentoo.at/proj/en/hardened/hardened-toolchain.xml#RELRO .
la source
Je peux dire pourquoi cela échoue, même si je ne sais pas vraiment quelle partie du système est responsable. Bien qu'il
.dtors
soit marqué en écriture dans le binaire, il semble qu'il (avec.ctors
le GOT et quelques autres choses) soit mappé dans une page séparée et non inscriptible en mémoire. Sur mon système,.dtors
se met à0x8049f14
:Si je lance l'exécutable et vérifie
/proc/PID/maps
, je vois:.data
/.bss
sont toujours inscriptibles dans leur propre page, mais les autres0x8049000-0x804a000
ne le sont pas. Je suppose que c'est une fonctionnalité de sécurité dans le noyau (comme vous l'avez dit, "il y a eu un mouvement vers readonly .dtors, plt, got dernièrement"), mais je ne sais pas précisément comment il s'appelle (OpenBSD a quelque chose de très similaire appelé W ^ X ; Linux a PaX , mais n'est pas intégré à la plupart des noyaux)Vous pouvez le contourner avec
mprotect
, ce qui vous permet de modifier les attributs en mémoire d'une page:Avec cela, mon programme de test ne plante pas, mais si j'essaie d'écraser la sentinelle de fin de
.dtors
(0x8049f18
) avec l'adresse d'une autre fonction, cette fonction ne s'exécute toujours pas; cette partie que je ne peux pas comprendre.J'espère que quelqu'un d'autre sait ce qui est responsable de rendre la page en lecture seule, et pourquoi la modification
.dtors
ne semble rien faire sur mon systèmela source
mprotect
ne peut pas rendre une page exécutable accessible en écriture ou rendre une page exécutable qui était accessible en écriture avant, sauf si cette fonctionnalité est désactivée avecpaxctl -m
.