La Pie et les Pingouins
Merci à Alice, Arthur et Yurug pour le titre.Ne vous méprenez pas, il n'est pas question que je me prenne pour "un éditeur affable comme il y en a depuis Esope" (Bobby Lapointe, évidemment).
Tout espoir de trouver là des histoires de volatiles, s'est envolé.
Ma plume, j'en ai peur, n'est point duveteuse.
Programme inutile
J'adore les programmes inutiles.fa$ cat unepie.c #include |
Prenons, 2 distributions Linux
Ubuntu 16.4 | Debian 9.1 |
---|---|
fa$ lsb_release -a Distributor ID:Ubuntu Description: Ubuntu 16.04.2 LTS Release: 16.04 Codename: xenial fa$ |
fa$ lsb_release -a Distributor ID: Debian Description: Debian GNU/Linux 9.1 (stretch) Release: 9.1 Codename: stretch fa$ |
Compilons, exécutons notre programme.
Ubuntu 16.4 | Debian 9.1 |
---|---|
fa$ gcc unepie.c -o unepie fa$ ./unepie Y'a une pie dans le poirier, J'entends la pie qui chante... fa$ | fa$ gcc unepie.c -o unepie fa$ ./unepie Y'a une pie dans le poirier, J'entends la pie qui chante... fa$ |
Pas de quoi s'émouvoir, je suis bien d'accord. Cependant..
Des formats différents!
Ubuntu 16.4 |
---|
fa$ file -b ./unepie ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=f528ec2c46a51d998c04d42b86d6d1a50331d378, not stripped fa$ |
Debian 9.1 |
fa$ file -b ./unepie ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=587bb830a101539c950ea7999b43442ebf7bd037, not stripped fa$ |
Rire sardonique emprunté à DjiBee.
Sous Ubuntu 16.04, le binaire exécutable est conformément à nos attentes un binaire exécutable. Mais sous Debian 9.1 (et je crois Ubuntu 17), le binaire exécutable n'est pas, n'est plus un binaire exécutable. Et pourtant il s'exécute!
readelf à la rescousse ?
Ubuntu 16.4 |
---|
fa$ readelf -l unepie Elf file type is EXEC (Executable file) Entry point 0x400430 There are 9 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040 0x00000000000001f8 0x00000000000001f8 R E 8 INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238 0x000000000000001c 0x000000000000001c R 1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x0000000000000744 0x0000000000000744 R E 200000 LOAD 0x0000000000000e10 0x0000000000600e10 0x0000000000600e10 0x0000000000000228 0x0000000000000230 RW 200000 fa$ |
Debian 9.1 |
fa$ readelf -l unepie Elf file type is DYN (Shared object file) Entry point 0x580 There are 9 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040 0x00000000000001f8 0x00000000000001f8 R E 0x8 INTERP 0x0000000000000238 0x0000000000000238 0x0000000000000238 0x000000000000001c 0x000000000000001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x00000000000008f4 0x00000000000008f4 R E 0x200000 LOAD 0x0000000000000dd8 0x0000000000200dd8 0x0000000000200dd8 0x0000000000000258 0x0000000000000260 RW 0x200000 fa$ |
Sous Ubuntu, le binaire exécutable a les caractéristiques habituelles. Sous Debian 9.1, le fichier ELF généré est différent: son type est DYN au lieu de EXEC mais il a un point d'entrée, et l'adresse virtuelle du texte est à 0 en lieu et place des 0x...0400000 proposés par Ubuntu.
Pourrait-on trouver d'autres exemples de fichiers de type "Shared object file" ?
Les librairies
Si on regarde la librairie C sous Debian 9.1:
Debian 9.1 | |
---|---|
fa$ readelf -l /lib/x86_64-linux-gnu/libc-2.24.so Elf file type is DYN (Shared object file) Entry point 0x203d0 There are 10 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040 0x0000000000000230 0x0000000000000230 R E 0x8 INTERP 0x000000000016aee0 0x000000000016aee0 0x000000000016aee0 0x000000000000001c 0x000000000000001c R 0x10 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x00000000001948e8 0x00000000001948e8 R E 0x200000 LOAD 0x00000000001957c8 0x00000000003957c8 0x00000000003957c8 0x0000000000004f38 0x00000000000091d8 RW 0x200000 fa$ |
C'est très similaire à notre binaire "unepie" sur Debian 9.1.
Notre binaire serait-il une librairie ?
Pas tout à fait.
On nous cache tout, on nous dit rien...
(Jacques Dutronc)En fait, Debian 9.1 génère automatiquement les binaires exécutables sous forme
"PIE". Ça consiste à générer le texte et les données du binaire comme on le fait pour des librairies dynamiques partagées. Pour les librairies, on utilise l'option -fPIC. Ici, on utilise l'option -fPIE (pour le compilateur) et -pie (pour l'éditeur de liens).
Oui, mais ! Je n'ai rien demandé à gcc.
En fait, gcc ne demande rien, mais est pré-configuré pour compiler avec un certain nombres d'options. Ce que l'on peut observer avec l'option -v de gcc, comme ci-dessous:
Debian 9.1 | |
---|---|
fa$ gcc -v unepie.c -o unepie Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/6/lto-wrapper Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Debian 6.3.0-18' ... --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ ... --enable-default-pie .... --target=x86_64-linux-gnu Thread model: posix gcc version 6.3.0 20170516 (Debian 6.3.0-18) COLLECT_GCC_OPTIONS='-v' '-o' 'unepie' '-mtune=generic' '-march=x86-64' /usr/lib/gcc/x86_64-linux-gnu/6/cc1 -quiet -v -imultiarch x86_64-linux-gnu unepie.c -quiet -dumpbase unepie.c -mtune=generic -march=x86-64 -auxbase unepie -version -o /tmp/ccQvdgZ6.s fa$ |
Le résultat ci-dessus a été considérablement expurgé.
Si on effectue la même commande dans le monde Ubuntu 16.4, on s'aperçoit que l'option PIE n'est pas configurée par défaut.
Si on veut se débarrasser de la chose, il faut le dire au compilateur :
Debian 9.1 | |
---|---|
fa$ gcc unepie.c -o unepie -fno-PIE -no-pie fa$ file -b unepie ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=4b5d9a8c53c61f07d857612460a2cd2d7742a82d, not stripped fa$ |
Pourquoi ?
La raison principale pour générer des binaires en mode PIE, est de pouvoir étendre la protection fournie par le mécanisme d'ASLR aux régions de code et de données. Sans le mode PIE, la protection est limitée aux régions de pile, de librairies partagées et aux régions créées par mmap.Une curiosité pour finir
Debian 9.1 ou Ubuntu 16.4 | |
---|---|
fa$ /lib/x86_64-linux-gnu/libc.so.6 GNU C Library (Ubuntu GLIBC 2.23-0ubuntu10) stable release version 2.23, by Roland McGrath et al. Copyright (C) 2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compiled by GNU CC version 5.4.0 20160609. Available extensions: crypt add-on version 2.1 by Michael Glad and others GNU Libidn by Simon Josefsson Native POSIX Threads Library by Ulrich Drepper et al BIND-8.2.3-T5B libc ABIs: UNIQUE IFUNC For bug reporting instructions, please see: |
La librairie C est exécutable! (Merci à Xavier R.)
Elle donne la version!
Ce n'est pas vrai de toutes les bibliothèques partagées. Seules quelques unes ont des droits rwx permettant une exécution.