{"id":133,"date":"2005-03-04T16:50:54","date_gmt":"2005-03-04T16:50:54","guid":{"rendered":"http:\/\/www.lucas-nussbaum.net\/blog\/?p=133"},"modified":"2005-03-04T16:50:54","modified_gmt":"2005-03-04T16:50:54","slug":"gcc-trampoline-et-code-auto-modifiable","status":"publish","type":"post","link":"https:\/\/www.lucas-nussbaum.net\/blog\/?p=133","title":{"rendered":"GCC, Trampoline, et code auto-modifiable"},"content":{"rendered":"<p>Aux temps h\u00e9ro\u00efques, le code auto-modifiable \u00e9tait fr\u00e9quent. \u00c7a consiste \u00e0 \u00e9crire du code qui se modifie lui-m\u00eame pendant l&#8217;ex\u00e9cution, pour faire des micro-optimisations qui tuent (en fait, surtout gagner une indirection par ci par l\u00e0, mais \u00e0 l&#8217;\u00e9poque c&#8217;\u00e9tait pas n\u00e9gligeable).<\/p>\n<p>Mais en fait, \u00e7a n&#8217;a pas compl\u00e8tement disparu : GCC, dans un cas pr\u00e9cis, en g\u00e9n\u00e8re d&#8217;ailleurs !<\/p>\n<h3>Fonctions imbriqu\u00e9es en C<\/h3>\n<p>Une fonction imbriqu\u00e9e en C est une fonction d\u00e9finie \u00e0 l&#8217;int\u00e9rieur d&#8217;une autre fonction. A quoi est-ce que \u00e7a sert ? Parfois, pour rendre votre code plus clair, vous d\u00e9finissez des fonctions qui ne sont utiles que dans une autre fonction. Il est donc d\u00e9bile de la rendre accessible depuis toutes les autres fonctions ! GNU CC vous autorise \u00e0 \u00e9crire le code suivant (c&#8217;est une extension de GCC, ce n&#8217;est pas dans la norme C99) :<\/p>\n<pre> int f1() { \tint f2() \t{ \t\t[...] \t} \t[...] \tf2(); \t[...] } <\/pre>\n<p>C&#8217;est bien joli, mais \u00e7a pose un probl\u00e8me. Regardez cet exemple (qui compile, n&#8217;h\u00e9sitez pas \u00e0 essayer) :<\/p>\n<pre> void f0(void (*f)()); long f1 (void) { \tlong i = 0; \tvoid f2(void) \t{ \t\ti++; \t} \tf0(f2); \treturn i; } void f0(void (*f)()) { \t(*f)(); } int main() { \treturn f1(); } <\/pre>\n<p>C&#8217;est tout \u00e0 fait l\u00e9gal : f1 passe un pointeur vers f2 \u00e0 f0, qui se charge d&#8217;appeler la fonction en param\u00e8tre. Le probl\u00e8me est que f2 modifie i. Or i est une variable locale de f1 (allou\u00e9e sur la pile par f1). La distance entre ESP dans f2 et les variables locales de f1 sur la pile n&#8217;est pas connue : ici, f0 appelle directement f2, mais il pourrait appeler blop(f2) qui lui m\u00eame appelerait f2. Il faut trouver un moyen de passer \u00e0 f2 l&#8217;adresse du contexte de sa fonction parente.<\/p>\n<h3>Trampolines<\/h3>\n<p>Un <a href=\"http:\/\/people.debian.org\/~aaronl\/Usenix88-lexic.pdf\">papier (PDF)<\/a> \u00e9voque ce probl\u00e8me pour le C++ (o\u00f9 les <i>closures<\/i> sont encore plus pratiques qu&#8217;en C, notamment lorsqu&#8217;on utilise des it\u00e9rateurs). Il propose une solution \u00e9l\u00e9gante utilisant un trampoline. Dans l&#8217;article, il d\u00e9montre la solution avec de l&#8217;assembleur 68000. Voici le code ci-dessus compil\u00e9 pour x86, sans optimisation histoire de garder le code le plus proche possible du C.<\/p>\n<pre> \t.file\t\"t5.c\" \t.text \t.type\tf2.0, @function f2.0: \tpushl\t%ebp \tmovl\t%esp, %ebp \tsubl\t$4, %esp \tmovl\t%ecx, -4(%ebp) \tmovl\t-4(%ebp), %ecx \tincl\t-4(%ecx) \tleave \tret \t.size\tf2.0, .-f2.0 .globl f1 \t.type\tf1, @function f1: \tpushl\t%ebp \tmovl\t%esp, %ebp \tsubl\t$40, %esp \tleal\t-24(%ebp), %eax \taddl\t$0, %eax \tandl\t$-1, %eax \tmovl\t$f2.0, %ecx \tleal\t10(%eax), %edx \tsubl\t%edx, %ecx \tmovl\t%ecx, %edx \tmovb\t$-71, (%eax) \tleal\t-8(%ebp), %ecx \tmovl\t%ecx, 1(%eax) \tmovb\t$-23, 5(%eax) \tmovl\t%edx, 6(%eax) \tmovl\t$0, -12(%ebp) \tleal\t-24(%ebp), %eax \taddl\t$0, %eax \tandl\t$-1, %eax \tmovl\t%eax, (%esp) \tcall\tf0 \tmovl\t-12(%ebp), %eax \tleave \tret \t.size\tf1, .-f1 .globl f0 \t.type\tf0, @function f0: \tpushl\t%ebp \tmovl\t%esp, %ebp \tsubl\t$8, %esp \tmovl\t8(%ebp), %eax \tcall\t*%eax \tleave \tret \t.size\tf0, .-f0 .globl main \t.type\tmain, @function main: \tpushl\t%ebp \tmovl\t%esp, %ebp \tsubl\t$8, %esp \tandl\t$-16, %esp \tmovl\t$0, %eax \tsubl\t%eax, %esp \tcall\tf1 \tleave \tret \t.size\tmain, .-main \t.section\t.note.GNU-stack,\"x\",@progbits \t.ident\t\"GCC: (GNU) 3.3.5 (Debian 1:3.3.5-8)\" <\/pre>\n<p>Un trampoline, c&#8217;est un petit bout de code qui va mettre dans registre (ici ECX, je ne sais pas quelle est la convention exactement) l&#8217;adresse de l&#8217;environnement de la fonction parente. Dans le code de f2, on voit qu&#8217;on incr\u00e9mente -4(%ecx) pour incr\u00e9menter i. Ce petit bout de code est g\u00e9n\u00e9r\u00e9 sur la pile par f1 avant d&#8217;appeler f0. Le code qui g\u00e9n\u00e8re le code est entre &#8220;subl\t$40, %esp&#8221; et &#8220;call f0&#8221;, en gros. Et mon d\u00e9bogueur me dit que le code g\u00e9n\u00e9r\u00e9 ressemble \u00e0 :<\/p>\n<pre> Dump of assembler code from 0xbffff930 to 0xbffffa30:     0xbffff930:     mov    $0xbffff940,%ecx     0xbffff935:     jmp    0x8048354  <\/pre>\n<p>Quand f0 fera son call, il appellera une adresse de la pile sans le savoir. Et quand f2 retournera, elle retournera directement dans f0.<\/p>\n<h3>C&#8217;est trop beau, il doit bien y avoir un probl\u00e8me qqpart &#8230;<\/h3>\n<p>H\u00e9 oui. La pile ex\u00e9cutable, c&#8217;est un probl\u00e8me : c&#8217;est la base de l&#8217;exploitation de beaucoup de trous de s\u00e9curit\u00e9. Du coup, des syst\u00e8mes essayent de rendre la pile non ex\u00e9cutable. C&#8217;est le cas de <a href=\"http:\/\/marc.theaimsgroup.com\/?l=openbsd-misc&amp;m=105056000801065&amp;w=2\">OpenBSD avec W^X<\/a>, ou de Linux avec <a href=\"http:\/\/www.redhat.com\/f\/pdf\/rhel\/WHP0006US_Execshield.pdf\">Exec-shield (PDF)<\/a>. Comment faire pour continuer \u00e0 autoriser les trampolines, alors ? Et bien c&#8217;est tout simple. Sous linux, l&#8217;en-t\u00eate ELF des binaires contient un flag indiquant si ce programme a besoin que la pile soit ex\u00e9cutable. Avec l&#8217;ex\u00e9cutable du code de tout \u00e0 l&#8217;heure :<\/p>\n<pre> ***lucas@blop:~% readelf -l t5 | grep STACK   STACK          0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4 <\/pre>\n<p> Tandis qu&#8217;avec un autre ex\u00e9cutable (notez le RW au lieu du RWE) : <\/p>\n<pre> ***lucas@blop:~% readelf -l t3 | grep STACK   STACK          0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4 <\/pre>\n<p>C&#8217;est un flag ajout\u00e9 par GCC.<\/p>\n<p>Bravo si vous avez lu jusque l\u00e0 ;)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Aux temps h\u00e9ro\u00efques, le code auto-modifiable \u00e9tait fr\u00e9quent. \u00c7a consiste \u00e0 \u00e9crire du code qui se modifie lui-m\u00eame pendant l&#8217;ex\u00e9cution, pour faire des micro-optimisations qui tuent (en fait, surtout gagner une indirection par ci par l\u00e0, mais \u00e0 l&#8217;\u00e9poque c&#8217;\u00e9tait pas n\u00e9gligeable). Mais en fait, \u00e7a n&#8217;a pas compl\u00e8tement disparu : GCC, dans un cas [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"0","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-133","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=\/wp\/v2\/posts\/133","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=133"}],"version-history":[{"count":0,"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=\/wp\/v2\/posts\/133\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=133"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=133"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=133"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}