Есть ли способ выполнить родной двоичный файл из трубы?


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

Есть ли способ запустить выходной двоичный файл в Unix-подобной системе?

EDIT: мне нужно было его запустить вывод г ++ в изолированном окружении , где я не могу писать какой - либо файл (ничего злонамеренного, я обещаю).


Я считаю, что основные механизмы безопасности должны этому помешать. Но если вы хотите запускать C-код на лету, просто используйте csh.
rozcietrzewiacz

Ответы:


10

Я не верю, что это возможно. Exec (2) системный вызов всегда требует имя файла или абсолютный путь (имя файла всегда char*). posix_spawnтакже имеет аналогичные требования для имени файла.

Самое близкое, что вы можете сделать, это направить вывод в именованный канал и попытаться выполнить его из канала. Это может сработать, хотя оболочка может отказаться выполнять любой файл, для которого не установлены --x--x--xбиты. Создайте трубу с помощью mkfifo(1)и посмотрите, сможете ли вы заставить ее работать.

Другой подход состоит в том, чтобы написать что-то, что читает стандартный ввод, записывает файл во временную область, устанавливает для него биты --x, разветвляется и исполняет, а затем удаляет файл. Индекс и содержимое останутся до тех пор, пока не завершится выполнение программы, но не будут доступны через файловую систему. Когда процесс завершится, индекс будет освобожден, и хранилище будет возвращено в свободный список.

РЕДАКТИРОВАТЬ: Как указывает Mat, первый подход не будет работать, так как загрузчик будет пытаться запросить страницу в исполняемом файле, который будет генерировать трафик случайного поиска по файлу, а это невозможно на конвейере. Это оставляет какой-то подход, как второй.


2
Я был бы очень удивлен, если бы трубочный трюк сработал - вы не можете выполнять произвольный поиск по каналу и не можете их отобразить - я уверен, что это будет раздражать загрузчик / компоновщик времени выполнения :) Ваше второе предложение кажется хорошим хотя, ничего не могу придумать без временного файла.
Мат

@ Мат - я думаю, что ты прав. Пейджинг по требованию в исполняемом файле вызовет трафик произвольного доступа, который не будет работать на канале. По иронии судьбы он мог работать на SVR2.0 (последняя версия, которая не использовала пейджинг по требованию) - просто чтобы показать свой возраст, я действительно имел обыкновение иметь AT & T 3B2 / 400 с SVR2.0 в качестве O / S.
ConcernedOfTunbridgeWells

Подумав об этом еще немного, я уверен, что упаковщики exe, такие как UPX, могут выполнять распаковку и выполнение на носителях только для чтения. Измените любую заглушку, которую они прикрепляют к упакованным исполняемым файлам, чтобы читать из канала, а не распаковывать, и ... может работать.
Мат

У упаковщиков @Mat уже загружено изображение, и они не запускают новый процесс. Чтобы сделать подобное, мне нужен один из процессов для произвольного перехода к входным данным (что будет считаться уязвимостью безопасности).
Алекс Б

@ Алекс Б: Вы конкретно спрашиваете, как сделать произвольный переход во входные данные. Почему вы жалуетесь, когда вам предлагают именно это? Предназначена ли песочница специально для предотвращения того, что вы пытаетесь сделать?
Дэвид Шварц

7

Решение с использованием системного вызова memfd: https://github.com/abbat/elfexec

Он создает именованный дескриптор файла в памяти, который может быть использован в exec. Псевдокод:

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

1
Вам не нужен memfd.hзаголовок, если вы не хотите его использовать MFD_CLOEXEC(что приведет к поломке #! /bin/shскриптов из-за ошибок в linux ' fexecve()). Это не так уж сложно, вы можете включить в ваш ответ 20-строчный рабочий пример (например, этот git gist - хотя это не является заменой для вас elfexec, так как это также позволит вам указать argv[0]и запустит двоичный файл). только из трубы (UUoC поручено ;-))
mosvy

Так что я не понимаю, как это вообще сработает. gcc запишет .oфайлы в / tmp и умрет, если не сможет.
Джошуа

4

Вы можете попробовать tcc , который скомпилирует и выполнит программу за один шаг, без записи каких-либо промежуточных файлов. Это не GCC, что может быть проблемой для вас, но это невероятно быстро, поэтому он может даже поставить лучше, чем GCC для ваших целей.


2

Это автоматически запустит компиляцию вашего кода, но создаст файл (временно) в файловой системе, чтобы сделать это.

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

(Я сейчас проверяю это сейчас, но я почти уверен, что или что-то близкое к этому подойдет вам)

РЕДАКТИРОВАТЬ: Если цель вашего трубопровода состоит в том, чтобы вырезать физические диски из уравнения для скорости, подумайте о создании оперативного диска для хранения промежуточного файла.


Это, конечно, сработает, но при этом упускает суть вопроса - выполнить двоичный код, который никогда не записывается на диск.
rozcietrzewiacz

@rozcietrzewiacz Я надеюсь, что было бы полезно, если бы цель состояла в том, чтобы легко запустить фрагмент кода на лету, не имея дело с требуемым физическим файлом.
dtyler

Да, я понимаю. Но для этого можно было бы просто использовать csh.
rozcietrzewiacz

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.