Je me tape la tête contre le mur avec ça.
Dans mon projet, lorsque j'alloue de la mémoire avec mmap
le mapping ( /proc/self/maps
), cela montre que c'est une région lisible et exécutable bien que je n'aie demandé que de la mémoire lisible.
Après avoir examiné strace (qui avait l'air bien) et d'autres débogages, j'ai pu identifier la seule chose qui semble éviter cet étrange problème: supprimer les fichiers d'assembly du projet et ne laisser que du C. pur (quoi?!)
Voici donc mon étrange exemple, je travaille sur Ubunbtu 19.04 et gcc par défaut.
Si vous compilez l'exécutable cible avec le fichier ASM (qui est vide), puis mmap
retourne une région lisible et exécutable, si vous construisez sans, il se comportera correctement. Voir la sortie /proc/self/maps
dont j'ai intégré dans mon exemple.
exemple.c
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
int main()
{
void* p;
p = mmap(NULL, 8192,PROT_READ,MAP_ANONYMOUS|MAP_PRIVATE,-1,0);
{
FILE *f;
char line[512], s_search[17];
snprintf(s_search,16,"%lx",(long)p);
f = fopen("/proc/self/maps","r");
while (fgets(line,512,f))
{
if (strstr(line,s_search)) fputs(line,stderr);
}
fclose(f);
}
return 0;
}
example.s : est un fichier vide!
Les sorties
Avec la version ASM incluse
VirtualBox:~/mechanics/build$ gcc example.c example.s -o example && ./example
7f78d6e08000-7f78d6e0a000 r-xp 00000000 00:00 0
Sans la version incluse ASM
VirtualBox:~/mechanics/build$ gcc example.c -o example && ./example
7f1569296000-7f1569298000 r--p 00000000 00:00 0
-Wa,--noexecstack
.Réponses:
Linux a un domaine d'exécution appelé
READ_IMPLIES_EXEC
, qui donne également toutes les pages allouéesPROT_READ
àPROT_EXEC
. Ce programme vous montrera si c'est activé pour lui-même:Si vous compilez cela avec un
.s
fichier vide , vous verrez qu'il est activé, mais sans celui-ci, il sera désactivé. La valeur initiale de ceci provient des méta-informations ELF dans votre binaire . Faitesreadelf -Wl example
. Vous verrez cette ligne lorsque vous aurez compilé sans le.s
fichier vide :Mais celui-ci lorsque vous avez compilé avec:
Notez
RWE
au lieu de justeRW
. La raison en est que l'éditeur de liens suppose que vos fichiers d'assembly nécessitent read-implique-exec à moins qu'il ne soit explicitement dit qu'ils ne le font pas, et si une partie de votre programme nécessite read-implique-exec, il est activé pour l'ensemble de votre programme . Les fichiers d'assembly que GCC compile lui indiquent qu'il n'en a pas besoin, avec cette ligne (vous verrez ceci si vous compilez avec-S
):Mettez cette ligne
example.s
, et cela servira à dire à l'éditeur de liens qu'il n'en a pas besoin non plus, et votre programme fonctionnera alors comme prévu.la source
.o
fichiers! Mais de toute façon, je suppose que c'est le mécanisme quigcc -zexecstack
utilise, et pourquoi il rend non seulement la pile mais tout exécutable.-Wa,--noexecstack
. Je pense que c'est un tranchant très méchant. La perte silencieuse de piles nx devrait être une vulnérabilité de sécurité. Les gens de Binutil devraient le réparer..note.GNU-stack,"",@progbits
était expliquée - en ce moment, elle est opaque, équivalente à "cette chaîne magique de caractères provoque cet effet", mais la chaîne semble clairement avoir une sorte de sémantique.Au lieu de modifier vos fichiers d'assemblage avec des variantes de directive de section spécifiques à GNU, vous pouvez ajouter
-Wa,--noexecstack
à votre ligne de commande pour créer des fichiers d'assemblage. Par exemple, voyez comment je le fais dans Musl'sconfigure
:https://git.musl-libc.org/cgit/musl/commit/configure?id=adefe830dd376be386df5650a09c313c483adf1a
Je crois qu'au moins certaines versions de clang avec l'assembleur intégré peuvent nécessiter qu'il soit passé sous
--noexecstack
(sans le-Wa
), donc votre script de configuration devrait probablement vérifier les deux et voir lequel est accepté.Vous pouvez également utiliser
-Wl,-z,noexecstack
au moment du lien (inLDFLAGS
) pour obtenir le même résultat. L'inconvénient de cela est que cela n'aide pas si votre projet produit des.a
fichiers de bibliothèque static ( ) à utiliser par d'autres logiciels, car vous ne contrôlez pas les options de temps de liaison quand il est utilisé par d'autres programmes.la source