Existe-t-il un moyen d'exécuter un binaire natif à partir d'un canal?

13
echo 'main(){}' | gcc -xc - -o /dev/stdout | ???

Existe-t-il un moyen d'exécuter le binaire de sortie sur un système de type Unix?

EDIT: J'en avais besoin pour exécuter la sortie de g ++ dans un environnement en bac à sable où je ne peux écrire aucun fichier (rien de malveillant, je le promets).

Alex B
la source
Je pense que les mécanismes de sécurité de base doivent empêcher cela. Mais si votre intention est d'exécuter du code C à la volée, utilisez simplement csh.
rozcietrzewiacz

Réponses:

10

Je ne pense pas que ce soit possible. L' appel système exec (2) nécessite toujours un nom de fichier ou un chemin absolu (le nom de fichier est toujours a char*). posix_spawna également des exigences similaires pour un nom de fichier.

Le mieux que vous puissiez faire est de diriger la sortie vers un canal nommé et d'essayer de l'exécuter à partir du canal. Cela peut fonctionner, bien que le shell puisse refuser d'exécuter tout fichier dont les --x--x--xbits ne sont pas définis. Créez le tuyau avec mkfifo(1)et voyez si vous pouvez le faire fonctionner.

Une autre approche consisterait à écrire quelque chose qui lit l'entrée standard, écrit un fichier dans une zone temporelle, y définit les bits --x, les fourches et les exécutables, puis supprime le fichier. L'inode et le contenu resteront jusqu'à la fin de l'exécution du programme, mais ils ne seront pas accessibles via le système de fichiers. À la fin du processus, l'inode sera libéré et le stockage sera retourné à la liste gratuite.

EDIT: Comme le souligne Mat, la première approche ne fonctionnera pas car le chargeur tentera d'exiger une page dans l'exécutable, ce qui générera un trafic de recherche aléatoire sur le fichier, et ce n'est pas possible sur un canal. Cela laisse une sorte d'approche comme la seconde.

ConcernedOfTunbridgeWells
la source
2
Je serais vraiment surpris si l'astuce de pipe fonctionnait - vous ne pouvez pas faire de recherches aléatoires sur une pipe, et ne pouvez pas les mapper - je suis presque sûr que cela ennuiera le chargeur / éditeur de liens :) Votre deuxième suggestion semble bonne cependant, ne peut rien trouver sans un fichier temporaire.
Mat
@Mat - Je pense que vous avez raison. La pagination de la demande dans l'exécutable entraînerait un trafic d'accès aléatoire qui ne fonctionnera pas sur le canal. Ironiquement, cela aurait pu fonctionner sur SVR2.0 (la dernière version qui n'utilisait pas la pagination à la demande) - Juste pour montrer mon âge, j'avais en fait utilisé un AT&T 3B2 / 400 une fois avec SVR2.0 comme O / S.
ConcernedOfTunbridgeWells
En y réfléchissant un peu plus, je suis presque sûr que les emballeurs exe comme UPX peuvent faire la décompression et l' exécution sur des supports en lecture seule. Modifiez le stub sur lequel ils collent aux exécutables compressés pour lire dans un tube plutôt que de décompresser, et ... cela pourrait fonctionner.
Mat
Les packers @Mat ont déjà une image chargée, ils ne démarrent pas un nouveau processus. Pour faire la même chose, j'ai besoin d'un des processus pour effectuer un saut arbitraire dans les données d'entrée (ce qui serait considéré comme une vulnérabilité de sécurité).
Alex B
@Alex B: Vous demandez spécifiquement comment effectuer un saut arbitraire dans les données d'entrée. Pourquoi vous plaindriez-vous quand on vous suggère de faire exactement cela? Le but du bac à sable est-il précisément d'empêcher ce que vous essayez de faire?
David Schwartz
7

Une solution utilisant memfd syscall: https://github.com/abbat/elfexec

Il crée un descripteur de fichier nommé en mémoire qui pourrait être utilisé dans exec. Un pseudo-code:

#include <linux/memfd.h>
...
int memfd = syscall(SYS_memfd_create, "someName", 0);
...
write(memfd,... elf-content...);
...
fexecve(memfd, argv, environ);
kan
la source
1
Vous n'avez pas besoin de l'en- memfd.htête à moins que vous ne vouliez l'utiliser MFD_CLOEXEC(ce qui cassera les #! /bin/shscripts à cause des bogues dans linux ' fexecve()). Ce n'est pas trop compliqué, vous pouvez inclure un échantillon de travail de 20 lignes dans votre réponse (par exemple, ce git gist - bien que ce ne soit pas un remplacement pour votre elfexec, car cela vous permettra également de spécifier argv[0]et d'exécuter un binaire uniquement à partir d'un tuyau (mandaté par UUoC ;-))
mosvy
Je ne comprends donc pas du tout comment cela devrait fonctionner. gcc écrira les .ofichiers dans / tmp et mourra s'il ne le peut pas.
Joshua
4

Vous pouvez essayer tcc , qui compilera et exécutera un programme en une seule étape, sans écrire de fichiers intermédiaires. Ce n'est pas gcc, ce qui peut être un problème pour vous, mais il est spectaculairement rapide, il peut donc même mieux miser que gcc pour vos besoins.

TheQUUX
la source
2

Cela exécutera automatiquement la compilation de votre code, mais créera un fichier (temporairement) sur le système de fichiers afin de le faire.

echo 'main(){}' | gcc -xc -o /tmp/a.out && chmod u+x /tmp/a.out && /tmp/a.out && rm -f /tmp/a.out

(Je suis en train de tester cela maintenant, mais je suis presque sûr que cela, ou quelque chose de proche fonctionnera pour vous)

EDIT: Si le but de votre tuyauterie est de couper les disques physiques de l'équation de la vitesse, envisagez de créer un disque RAM pour contenir le fichier intermédiaire.

dtyler
la source
Cela fonctionnera bien sûr, mais il manque le point principal de la question - exécuter un code binaire qui n'est jamais écrit sur le disque.
rozcietrzewiacz
@rozcietrzewiacz J'espérais que ce serait utile si le but était d'exécuter facilement un extrait de code à la volée sans traiter le fichier physique requis.
dtyler
Oui je comprends. Mais pour cela, on pourrait simplement utiliser csh.
rozcietrzewiacz