C'è un modo per eseguire un binario nativo da una pipe?


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

C'è un modo per eseguire l'output binario su un sistema simile a unix?

EDIT: ne avevo bisogno per eseguire l'output di g ++ in un ambiente sandbox in cui non riesco a scrivere alcun file (niente di male, lo prometto).


Credo che i meccanismi di sicurezza di base debbano impedirlo. Ma se la tua intenzione è quella di eseguire il codice C al volo, basta usare csh.
rozcietrzewiacz,

Risposte:


10

Non credo sia possibile. La chiamata di sistema exec (2) richiede sempre un nome file o un percorso assoluto (il nome file è sempre a char*). posix_spawnha anche requisiti simili per un nome file.

Il più vicino che puoi fare è reindirizzare l'output in una pipe denominata e provare a eseguirlo dalla pipe. Potrebbe funzionare, sebbene la shell possa rifiutare di eseguire qualsiasi file che non abbia i --x--x--xbit impostati. Crea la pipa con mkfifo(1)e vedi se riesci a farlo funzionare.

Un altro approccio sarebbe quello di scrivere qualcosa che legga l'input standard, scriva un file in un'area temporanea, imposta i bit --x su di esso, forchette ed esecuzioni quindi elimina il file. L'inode e il contenuto rimarranno fino al termine dell'esecuzione del programma ma non saranno accessibili tramite il file system. Al termine del processo, l'inode verrà rilasciato e la memoria verrà restituita all'elenco gratuito.

EDIT: Come sottolinea Mat, il primo approccio non funzionerà poiché il caricatore tenterà di richiedere la pagina nell'eseguibile, il che genererà traffico di ricerca casuale sul file e questo non è possibile su una pipe. Questo lascia una sorta di approccio come il secondo.


2
Sarei davvero sorpreso se il trucco della pipa funzionasse - non puoi fare ricerche casuali su una pipe e non puoi bloccarle - Sono abbastanza sicuro che infastidirà il caricatore / linker di runtime :) Il tuo secondo suggerimento sembra buono tuttavia, non è possibile trovare nulla senza un file temporaneo.
Mat

@Mat - Penso che tu abbia ragione. Il paging della domanda nell'eseguibile causerebbe un traffico ad accesso casuale che non funzionerà sulla pipe. Ironia della sorte, avrebbe potuto effettivamente funzionare su SVR2.0 (l'ultima versione che non utilizzava il paging della domanda) - Solo per mostrare la mia età in realtà avevo un AT&T 3B2 / 400 una volta con SVR2.0 come O / S.
Preoccupato di

Pensandoci ancora un po ', sono abbastanza sicuro che i packer exe come UPX possano eseguire la decompressione e l' esecuzione su supporti di sola lettura. Modifica qualsiasi troncone su cui si attacchiano eseguibili compressi per leggere da una pipe piuttosto che decomprimere, e ... potrebbe funzionare.
Mat

I packer @Mat hanno già un'immagine caricata e non avviano un nuovo processo. Per fare lo stesso ho bisogno di avere uno dei processi per fare un salto arbitrario nei dati di input (che sarebbe considerato una vulnerabilità di sicurezza).
Alex B,

@Alex B: stai chiedendo in particolare come eseguire un salto arbitrario nei dati di input. Perché ti lamenti quando ti viene suggerito di fare esattamente questo? Lo scopo della sandbox è specificamente quello di impedire ciò che stai cercando di fare?
David Schwartz,

7

Una soluzione che utilizza memfd syscall: https://github.com/abbat/elfexec

Crea un descrittore di file con nome in memoria che può essere utilizzato in exec. Uno pseudo-codice:

#include <linux/memfd.h>
...
int memfd = syscall(SYS_memfd_create, "someName", 0);
...
write(memfd,... elf-content...);
...
fexecve(memfd, argv, environ);

1
Non hai bisogno memfd.hdell'intestazione a meno che tu non voglia usare MFD_CLOEXEC(che romperà gli #! /bin/shscript a causa di bug in Linux ' fexecve()). Non è troppo complicato, puoi includere un campione di lavoro a 20 righe nella tua risposta (ad es. Questo git gist - anche se non è un rimpiazzo sostitutivo per il tuo elfexec, dal momento che ciò ti permetterà anche di specificare argv[0]ed eseguirà un binario solo da una pipa (UUoC obbligatorio ;-))
mosvy

Quindi non capisco come questo dovrebbe funzionare. gcc scriverà i .ofile su / tmp e morirà se non ci riesce.
Joshua,

4

Puoi provare tcc , che compilerà ed eseguirà un programma in un solo passaggio, senza scrivere alcun file intermedio. Non è gcc, il che potrebbe essere un problema per te, ma è incredibilmente veloce, quindi potrebbe anche scommettere meglio di gcc per i tuoi scopi.


2

Questo eseguirà automaticamente la compilazione del tuo codice, ma crea un file (temporaneo) sul filesystem per farlo.

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

(Attualmente sto testando questo ora, ma sono abbastanza sicuro, o qualcosa di simile funzionerà per te)

EDIT: se l'obiettivo delle tubazioni è tagliare i dischi fisici fuori dall'equazione per la velocità, prendere in considerazione la creazione di un disco ram per contenere il file intermedio.


Questo funzionerà ovviamente, ma manca il punto principale della domanda: eseguire un codice binario che non è mai scritto su disco.
rozcietrzewiacz,

@rozcietrzewiacz La mia speranza era che sarebbe utile se l'obiettivo fosse quello di eseguire facilmente uno snippit di codice al volo senza occuparsi del file fisico richiesto.
dtyler,

Si, capisco. Ma per quello, si potrebbe semplicemente usare csh.
rozcietrzewiacz,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.