Quelle est l’option -fPIE pour les exécutables indépendants de la position dans gcc et ld?

Comment va-t-il changer le code, par exemple les appels de fonction?

Le PIE doit prendre en charge la randomisation de la configuration de l’espace adresse (ASLR) dans les fichiers exécutables.

Avant que le mode PIE ne soit créé, l’exécutable du programme ne pouvait pas être placé à une adresse aléatoire en mémoire, seules les bibliothèques dynamics de code de position indépendant (PIC) pouvaient être déplacées vers un décalage aléatoire. Cela fonctionne beaucoup comme ce que fait PIC pour les bibliothèques dynamics, la différence est qu’une table de liaison de procédure (PLT) n’est pas créée, au lieu de cela, une relocalisation relative à un PC est utilisée.

Après avoir activé le support PIE dans gcc / linkers, le corps du programme est compilé et lié en tant que code indépendant de la position. Un éditeur de liens dynamic effectue un traitement de relocalisation complet sur le module de programme, tout comme les bibliothèques dynamics. Toute utilisation de données globales est convertie en access via la table de décalage global (GOT) et les réinstallations GOT sont ajoutées.

Le PIE est bien décrit dans cette présentation OpenBSD PIE .

Les modifications apscopes aux fonctions sont indiquées dans cette diapositive (PIE vs PIC).

x86 pic vs tarte

Les variables globales locales et les fonctions sont optimisées dans pie

Les variables globales externes et les fonctions sont identiques à pic

et dans cette diapositive (PIE vs ancienne liaison)

x86 pie vs no-flags (corrigé)

Les variables globales locales et les fonctions sont similaires à fixes

Les variables globales externes et les fonctions sont identiques à pic

Notez que PIE peut être incompatible avec -static

Exemple minimal d’exécution: GDB l’exécutable deux fois

Pour ceux qui veulent voir des actions:

 printf ' #include  int main() { puts("hello world"); } ' > main.c gcc -std=c99 -pie -fpie -ggdb3 -o pie main.c gcc -std=c99 -no-pie -fno-pie -ggdb3 -o nopie main.c echo 2 | sudo tee /proc/sys/kernel/randomize_va_space gdb -batch -nh -ex 'set disable-randomization off' \ -ex 'start' -ex 'info line' \ -ex 'start' -ex 'info line' \ ./pie gdb -batch -nh -ex 'set disable-randomization off' \ -ex 'start' -ex 'info line' \ -ex 'start' -ex 'info line' \ ./nopie 

Pour celui avec -pie , on voit que l’adresse des main changements entre les exécutions:

 Temporary breakpoint 1 at 0x7a9: file memory_layout.c, line 31. [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Temporary breakpoint 1, main (argc=1, argv=0x7ffe57d75318) at memory_layout.c:31 31 int main(int argc, char **argv) { Line 31 of "memory_layout.c" starts at address 0x55db0066b79a 
and ends at 0x55db0066b7a9 . Temporary breakpoint 2 at 0x55db0066b7a9: file memory_layout.c, line 31. [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Temporary breakpoint 2, main (argc=1, argv=0x7ffd03b67d68) at memory_layout.c:31 31 int main(int argc, char **argv) { Line 31 of "memory_layout.c" starts at address 0x563910ccd79a
and ends at 0x563910ccd7a9 .

donc dans cet exemple, l’adresse pour la première exécution était 0x55db0066b79a et pour la seconde 0x563910ccd79a .

Mais pour celui avec -no-pie , l’adresse de main rest la même 0x400627 pour les deux exécutions:

 Temporary breakpoint 1 at 0x400636: file ./memory_layout.c, line 28. Temporary breakpoint 1, main (argc=1, argv=0x7ffd5f69c8b8) at ./memory_layout.c:28 warning: Source file is more recent than executable. 28 int bss = 0; Line 28 of "./memory_layout.c" starts at address 0x400627 
and ends at 0x400636 . Temporary breakpoint 2 at 0x400636: file ./memory_layout.c, line 28. Temporary breakpoint 2, main (argc=1, argv=0x7ffdd9f74bd8) at ./memory_layout.c:28 28 int bss = 0; Line 28 of "./memory_layout.c" starts at address 0x400627
and ends at 0x400636 .

echo 2 | sudo tee /proc/sys/kernel/randomize_va_space echo 2 | sudo tee /proc/sys/kernel/randomize_va_space s’assure que ASLR est activé (par défaut dans Ubuntu 17.10): Comment puis-je désactiver temporairement ASLR (randomisation de la disposition de l’espace d’adressage)? | Demandez à Ubuntu .

set disable-randomization off est nécessaire sinon GDB, comme son nom l’indique, désactive ASLR pour que le processus par défaut donne des adresses fixes entre les exécutions pour améliorer l’expérience de débogage: Différence entre les adresses gdb et les “vraies” adresses? | Débordement de stack

readelf plaisir

De plus, nous pouvons également observer que:

 readelf -s ./nopie | grep main 

donne l’adresse de chargement à l’exécution:

 69: 0000000000400627 370 FUNC GLOBAL DEFAULT 13 main 

tandis que:

 readelf -s ./pie | grep main 

donne juste un décalage:

 70: 000000000000079a 401 FUNC GLOBAL DEFAULT 14 main 

En désactivant ASLR (avec randomize_va_space ou set disable-randomization off ), GDB donne toujours l’adresse main : 0x5555555547a9 , nous en déduisons que l’adresse -pie est composée de:

 0x555555554000 + random offset + symbol offset (79a) 

TODO où est 0x555555554000 codé en dur dans le kernel Linux / chargeur glibc / où? Comment l’adresse de la section texte d’un exécutable PIE est-elle déterminée sous Linux?

Testé dans Ubuntu 18.04.

Question connexe: Comment puis-je savoir, avec quelque chose comme objdump, si un fichier object a été construit avec -fPIC?