著者: Yves Martin 日付: To: guilde 題目: Re: A propos du No eXecute d'AMD64
Selon serge rouveyrol <Serge.Rouveyrol@???>:
> > C'est effectivement un problème. Mais un code assembleur inline permet
> > de changer les valeurs des segments et cela devrait suffire au niveau du
> > kernel (un segment CS pour le code, un pour les données DS (et copie dans
> > ES, FS, GS), un pour la pile SS pour chaque application)
> > Une fois que le kernel les définit pour l'application, l'application n'a
> pas
> > besoin d'y toucher (d'ailleurs elle aurait du mal si elle ne connaît pas
> leur
> > valeur exacte).
>
> pour une application il reste le probmeme du code genere par C pour un
> pointeur sur une variable dans la zone data et un pointeur
> sur une variable locale
Et oui - c'est pour cela que Linux ne définit qu'un seul segment de données
pour la pile et les données. Donc cela ne pose pas de problème au C.
Mais alors pourquoi un code déposé en pile est exécutable ?
J'ai compris: parce que les deux segments USER_CS et USER_DS sont identiques:
base à 0 et limite à 2 Gb (pour le kernel c'est 0 -> 4 Gb)
Lors de l'écriture du buffer dans la pile, c'est un registre DS:ECX qui est
utilisé (par exemple) pour écrire en STACK - 0x0200,
et au moment du 'RET', la valeur STACK - 0x0200 est chargée dans EIP,
et pointe sur une adresse dans la pile (exemple STACK - 0x0220),
ce qui permet d'exécuter le contenu du 'buffer' (lu par le réseau par exemple)
Donc le problème n'est pas que le segment de données est exécutable
(comme je le pensais naïvement), le problème est que les deux segments
code et données rendent visible l'ensemble de la mémoire de l'application
(code, données et pile)
Si le segment de code (CS) était limité à [ 0 -> 1 Gb ] (uniquement le code)
et le segment de données à [ 1 Gb -> 2 Gb ] (data + pile),
les attaques sur la pile ne serait pas possibles.
Mais voilà - le C et le loader (ld) charge le code de l'exécutable, les
données initialisées et non initialisées de façon contigües. C'est là qu'il
faudrait faire un petit changement, sans avoir à toucher à gcc, à condition
que les exécutables ELF soient toujours générés relogeables
en mémoire pour déplacer les zones de données.