¿Hay alguna manera de ejecutar un binario nativo desde una tubería?

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

¿Hay alguna manera de ejecutar el binario de salida en un sistema tipo Unix?

EDITAR: lo necesitaba para ejecutar la salida de g ++ en un entorno de espacio aislado donde no puedo escribir ningún archivo (nada malicioso, lo prometo).

Alex B
fuente
Creo que los mecanismos básicos de seguridad deben evitar esto. Pero si su intención es ejecutar código C sobre la marcha, simplemente use csh.
rozcietrzewiacz

Respuestas:

10

No creo que esto sea posible. La llamada al sistema exec (2) siempre requiere un nombre de archivo o ruta absoluta (el nombre de archivo siempre es a char*). posix_spawntambién tiene requisitos similares para un nombre de archivo.

Lo más cercano que puede hacer es canalizar la salida en una tubería con nombre e intentar ejecutar desde la tubería. Eso puede funcionar, aunque el shell puede negarse a ejecutar cualquier archivo que no tenga los --x--x--xbits establecidos. Cree la tubería con mkfifo(1)y vea si puede hacer que funcione.

Otro enfoque sería escribir algo que lea la entrada estándar, escriba un archivo en un área de temporay, establezca los bits --x, bifurcaciones y ejecutivos y luego elimine el archivo. El inodo y el contenido permanecerán hasta que el programa termine de ejecutarse, pero no será accesible a través del sistema de archivos. Cuando finalice el proceso, se liberará el inodo y el almacenamiento se devolverá a la lista libre.

EDITAR: como señala Mat, el primer enfoque no funcionará ya que el cargador intentará exigir la página en el ejecutable, lo que generará tráfico de búsqueda aleatorio en el archivo, y esto no es posible en una tubería. Esto deja algún tipo de enfoque como el segundo.

Preocupado por TunbridgeWells
fuente
2
Me sorprendería mucho si el truco de la tubería funcionara: no puede hacer búsquedas aleatorias en una tubería y no puede mapearlas. Estoy bastante seguro de que molestará al cargador / enlazador de tiempo de ejecución :) Su segunda sugerencia parece buena sin embargo, no se puede llegar a nada sin un archivo temporal.
Mat
@ Mat: creo que tienes razón. La paginación de demanda en el ejecutable provocaría tráfico de acceso aleatorio que no funcionará en la tubería. Irónicamente, podría haber funcionado en SVR2.0 (la última versión que no usaba paginación por demanda). Solo para mostrar mi edad, en realidad solía tener un AT&T 3B2 / 400 una vez con SVR2.0 como O / S.
Preocupado por TunbridgeWells
Pensando un poco más, estoy bastante seguro de que los empacadores exe como UPX pueden hacer la descompresión y la ejecución en medios de solo lectura. Modifique cualquier trozo que agreguen en ejecutables empaquetados para leer desde una tubería en lugar de descomprimir, y ... podría funcionar.
Mat
Los empacadores @Mat ya tienen una imagen cargada, no inician un nuevo proceso. Para hacer lo mismo, necesito tener uno de los procesos para hacer un salto arbitrario a los datos de entrada (lo que se consideraría una vulnerabilidad de seguridad).
Alex B
@ Alex B: Usted pregunta específicamente cómo hacer un salto arbitrario a los datos de entrada. ¿Por qué te quejarías cuando te sugieran que hagas exactamente eso? ¿El propósito de la caja de arena es específicamente evitar lo que estás tratando de hacer?
David Schwartz
7

Una solución usando memfd syscall: https://github.com/abbat/elfexec

Crea un descriptor de archivo con nombre en la memoria que podría usarse en exec. Un pseudocódigo:

#include <linux/memfd.h>
...
int memfd = syscall(SYS_memfd_create, "someName", 0);
...
write(memfd,... elf-content...);
...
fexecve(memfd, argv, environ);
kan
fuente
1
No necesita el memfd.hencabezado a menos que quiera usarlo MFD_CLOEXEC(lo que romperá los #! /bin/shscripts debido a errores en linux ' fexecve()). Eso no es demasiado complicado, puede incluir una muestra de trabajo de 20 líneas en su respuesta (por ejemplo, este git gist , aunque eso no es un reemplazo directo para su elfexec, ya que eso también le permitirá especificar argv[0]y ejecutará un binario solo desde una tubería (UUoC obligatorio ;-))
mosvy
Así que no entiendo cómo se esperaba que esto funcione en absoluto. gcc escribirá .oarchivos en / tmp y morirá si no puede.
Joshua
4

Puede probar tcc , que compilará y ejecutará un programa en un solo paso, sin escribir ningún archivo intermedio. No es gcc, lo que puede ser un problema para usted, pero es espectacularmente rápido, por lo que incluso puede apostar mejor que gcc para sus propósitos.

TheQUUX
fuente
2

Esto ejecutará automáticamente la compilación de su código, pero crea un archivo (temparaily) en el sistema de archivos para poder hacerlo.

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

(Actualmente estoy probando esto ahora, pero estoy bastante seguro de que esto, o algo similar funcionará para usted)

EDITAR: Si el objetivo de su tubería es cortar discos físicos fuera de la ecuación para la velocidad, considere crear un disco RAM para contener el archivo intermedio.

dtyler
fuente
Esto funcionará, por supuesto, pero pierde el punto principal de la pregunta: ejecutar un código binario que nunca se escribe en el disco.
rozcietrzewiacz
@rozcietrzewiacz Espero que sea útil si el objetivo fuera ejecutar fácilmente un fragmento de código sobre la marcha sin tener que lidiar con el archivo físico requerido.
dtyler
Si entiendo. Pero para eso, uno simplemente podría usar csh.
rozcietrzewiacz