Gibt es eine Möglichkeit, eine native Binärdatei aus einer Pipe auszuführen?

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

Gibt es eine Möglichkeit, die Ausgabebinärdatei auf einem Unix-ähnlichen System auszuführen?

BEARBEITEN: Ich brauchte es, um die Ausgabe von g ++ in einer Sandbox-Umgebung auszuführen, in der ich keine Datei schreiben kann (nichts Bösartiges, wie ich verspreche).

Alex B
quelle
Ich glaube, dass grundlegende Sicherheitsmechanismen dies verhindern müssen. Wenn Sie jedoch C-Code direkt ausführen möchten, verwenden Sie einfach csh.
rozcietrzewiacz

Antworten:

9

Ich glaube nicht, dass das möglich ist. Der Systemaufruf exec (2) erfordert immer einen Dateinamen oder einen absoluten Pfad (der Dateiname ist immer a char*). posix_spawnhat auch ähnliche Anforderungen für einen Dateinamen.

Das Nächste, was Sie tun können, ist, die Ausgabe in eine Named Pipe umzuleiten und die Ausführung über die Pipe zu versuchen. Das kann funktionieren, obwohl die Shell möglicherweise die Ausführung von Dateien ablehnt, für die die --x--x--xBits nicht gesetzt sind. Erstellen Sie die Pipe mit mkfifo(1)und versuchen Sie, sie zum Laufen zu bringen.

Ein anderer Ansatz wäre, etwas zu schreiben, das die Standardeingabe liest, eine Datei in einen temporären Bereich ausschreibt, die --x-Bits darauf setzt, die Datei gabelt und ausführt und dann löscht. Der Inode und der Inhalt bleiben so lange erhalten, bis die Ausführung des Programms abgeschlossen ist. Über das Dateisystem kann jedoch nicht darauf zugegriffen werden. Wenn der Prozess beendet ist, wird der Inode freigegeben und der Speicher auf die freie Liste zurückgesetzt.

BEARBEITEN: Wie Mat betont, funktioniert der erste Ansatz nicht, da der Loader versucht, eine Seite in der ausführbaren Datei anzufordern, wodurch zufälliger Suchverkehr für die Datei generiert wird. Dies ist in einer Pipe nicht möglich. Dies lässt eine Art Ansatz wie der zweite.

Betroffen vonTunbridgeWells
quelle
2
Ich wäre wirklich überrascht, wenn der Pipe-Trick funktioniert hätte - Sie können keine zufälligen Suchvorgänge für eine Pipe ausführen und sie auch nicht mappen - ich bin mir ziemlich sicher, dass dies den Runtime-Loader / Linker ärgern wird :) Ihr zweiter Vorschlag scheint gut zu sein Ich kann mir jedoch nichts ohne eine temporäre Datei ausdenken.
Mat
@ Mat - ich denke du hast recht. Ein Anforderungs-Paging in der ausführbaren Datei würde einen Datenverkehr mit wahlfreiem Zugriff verursachen, der auf der Pipe nicht funktioniert. Ironischerweise hat es tatsächlich mit SVR2.0 geklappt (die letzte Version, die kein Demand-Paging verwendet hat) - Nur um mein Alter zu zeigen, hatte ich tatsächlich einmal einen AT & T 3B2 / 400 mit SVR2.0 als Betriebssystem.
ConcernedOfTunbridgeWells
Ich bin mir ziemlich sicher, dass Exe-Packer wie UPX die Dekomprimierung und Ausführung auf schreibgeschützten Medien durchführen können. Ändern Sie die Stubs, an denen sie anheften, in gepackte ausführbare Dateien, um sie aus einer Pipe zu lesen, anstatt sie zu dekomprimieren, und ... funktionieren möglicherweise.
Mat
@Mat-Packer haben bereits ein Image geladen und starten keinen neuen Prozess. Um das Gleiche zu tun, brauche ich einen der Prozesse, um willkürlich in Eingabedaten zu springen (was als Sicherheitslücke angesehen werden würde).
Alex B
@Alex B: Sie fragen speziell, wie Sie einen willkürlichen Sprung in Eingabedaten machen können. Warum sollten Sie sich beschweren, wenn genau das vorgeschlagen wird? Ist der Zweck der Sandbox speziell, um zu verhindern, was Sie versuchen, zu tun?
David Schwartz
7

Eine Lösung mit memfd syscall: https://github.com/abbat/elfexec

Es wird ein benannter Dateideskriptor im Speicher erstellt, der verwendet werden kann exec. Ein Pseudocode:

#include <linux/memfd.h>
...
int memfd = syscall(SYS_memfd_create, "someName", 0);
...
write(memfd,... elf-content...);
...
fexecve(memfd, argv, environ);
kan
quelle
1
Sie brauchen den memfd.hHeader nicht, es sei denn, Sie möchten ihn verwenden MFD_CLOEXEC(wodurch #! /bin/shSkripte aufgrund von Fehlern in Linux beschädigt werden fexecve()). Das ist nicht allzu kompliziert. Sie können ein 20- zeiliges Arbeitsprobe in Ihre Antwort aufnehmen (z. B. dieses Git-Gist - obwohl dies kein Ersatz für Ihr ist elfexec, da Sie damit auch argv[0]eine Binärdatei angeben und ausführen können nur von einer Pipe (UUoC mandated ;-))
mosvy
Ich verstehe also nicht, wie das überhaupt funktionieren soll. gcc schreibt .oDateien nach / tmp und stirbt, wenn dies nicht möglich ist.
Joshua
4

Sie können tcc ausprobieren , das ein Programm in einem Schritt kompiliert und ausführt, ohne Zwischendateien zu schreiben. Es ist nicht gcc, was für Sie ein Problem sein kann, aber es ist spektakulär schnell, so dass es für Ihre Zwecke sogar besser als gcc sein kann.

TheQUUX
quelle
2

Dadurch wird die Kompilierung Ihres Codes automatisch ausgeführt, es wird jedoch (vorübergehend) eine Datei auf dem Dateisystem erstellt, um dies zu tun.

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

(Ich teste dies gerade, aber ich bin mir ziemlich sicher, dass dies oder etwas in der Nähe für Sie funktionieren wird.)

BEARBEITEN: Wenn das Ziel Ihrer Rohrleitungen darin besteht, physische Datenträger aus Gründen der Geschwindigkeit aus der Gleichung herauszuschneiden, sollten Sie eine RAM-Platte für die Zwischendatei erstellen.

dtyler
quelle
Dies wird natürlich funktionieren, aber es verfehlt den Hauptpunkt der Frage - einen Binärcode auszuführen, der niemals auf die Festplatte geschrieben wird.
Rozcietrzewiacz
@rozcietrzewiacz Meine Hoffnung war, dass es nützlich sein würde, wenn das Ziel darin bestand, schnell und einfach einen Codeausschnitt auszuführen, ohne die erforderliche physische Datei zu bearbeiten.
dtyler
Ja ich verstehe. Aber dafür könnte man einfach verwenden csh.
rozcietrzewiacz