• # Un peu tout ça...

    Posté par . En réponse au journal question : est-ce que la zone de code est modifiable. Évalué à 4.

    Si le CPU ne dispose pas de MMU alors tout est permis (cf reponse qui cause de DSP). Si le CPU dispose d'une MMU alors il y a fort a parier qu'elle supporte la notion de droit hard (lecture/ecriture voire execution sur certaines archi) et/ou la notion de privilege (user/superviseur, voire plus de 2 niveaux). Par exemple sur IA32, la MMU est capable de gerer les droits lecture/ecriture et les niveaux de privilege (4 pour la segmentation, 2 pour la pagination). Les extensions plus recentes distinguent en plus un droit a l'execution (extension "NX" chez Intel, j'ai oublie le nom chez AMD).

    Ce n'est pas le CPU qui etablit tout seul a quel endroit qui a le droit d'ecrire/lire/executer. C'est l'OS. Donc a son tour l'OS peut decider d'exploiter ces notions ou pas. Par exemple DOS ne gere rien de tout ça ; le DOS de base ne sait meme pas qu'il y a une MMU. Mais Windows et les Unix exploitent ces notions.

    C'est donc une combinaison hard/soft qui decide quoi faire au niveau des privileges et des droits d'acces autorises. C'est "politique" tout ça, l'OS peut faire ce qu'il veut.

    En general (cas Linux/Windows), l'OS considere que les applis utilisateur sont executees avec le plus bas privilege. Ca interdit a ces applications l'utilisation de certaines instructions dont celles qui pourraient modifier leur config de la MMU ou leur niveau de privilege (mise a part les syscalls). Au niveau des privileges, donc, l'appli ne peut rien changer. Sauf si l'OS lui autorise a le faire (jamais le cas sous Linux).

    Ensuite, les droits d'acces (r/w voire x) en VM sont definis aussi par l'OS. Mais pas n'importe comment. Dans le cas courant (Unix/Windows) ces droits sont definis dans le format de l'executable qui est charge (man objdump + comparer avec /proc/pid/maps). C'est le compilo qui genere ces fichiers, c'est lui qui dit quelle zone est r/w/x. Par defaut, les sections de code sont en rx, les sections data (et bss) en rw et les sections "rodata" (chaines de caracteres ecrites en dur dans le source) en read-only. Tout acces non autorise generera un SEGV.

    Cependant, sous Unix (et j'imagine aussi sous windows), l'appli a toute lattitude pour modifier ces droits. Ca peut se faire en amont lors de la compilation (p.ex : demander a gcc de mettre les chaines en data plutot que rodata) et/ou de l'edition de liens (modif des scripts ld). Ca peut se faire aussi a l'execution (mprotect) car l'OS propose des syscalls pour que l'appli puisse modifier ses droits d'acces (syscalls nécessaires pour ld.so). Par exemple, le programme suivant passera une partie du code en r/w et ecrasera le debut du code de la fonction f (SEGV assure):

    -----------------------------------------------------
    #include <stdio.h>
    #include <sys/mman.h>
    #include <string.h>

    void f()
    {
    printf("Hugh\n");
    }


    int main ()
    {
    int * ptr_f = (int*)f;
    printf("Salut\n");
    mprotect(((void*) (((long)ptr_f) & ~4095)), 4096,
    PROT_READ | PROT_WRITE | PROT_EXEC);
    *ptr_f = 0xdeadbeef;
    f();
    return 0;
    }
    -----------------------------------------------------

    Evidemment, si on vire le mprotect on aura aussi un SEGV mais pas pour les memes raisons. Dans le premier cas (avec mprotect) c'est le code de f qui a ete ecrase et donc qui fait n'imorte quoi (=> SEGV), dans le 2eme cas (sans mprotect) c'est que main tente d'ecrire sur une zone en lecture seule.

    Sinon, l'injection de code ne correspond pas obligatoirement a la creation d'un thread parasite. Il sagit tout betement d'ecrire du code la ou on peut sans grand effort (p.ex sur la pile par debordement de tableau local), puis a ruser la pile pour dire au CPU de sauter a l'endroit ou le code a ete injecte. Apres le code injecte peut faire ce qu'il veut : pourquoi pas creer un thread si ca lui chante.