Чи є спосіб виконати власний бінарний файл з труби?


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

Чи є спосіб запустити вихідний двійковий файл у системі, схожу на unix?

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


Я вважаю, що основні механізми безпеки повинні цьому перешкоджати. Але якщо ваша мета полягає в тому, щоб запустити код C на льоту, просто використовуйте csh.
rozcietrzewiacz

Відповіді:


10

Я не вірю, що це можливо. Exec (2) системний виклик завжди вимагає ім'я файлу або абсолютний шлях (ім'я файлу завжди char*). posix_spawnтакож має подібні вимоги до імені файлу.

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

Іншим підходом було б написати щось, що читає стандартне введення, записує файл у область темпорай, встановлює на нього --x біти, forks та execs, а потім видаляє файл. Вкладення та вміст залишатимуться до тих пір, поки програма не завершить виконання, але вона не буде доступною через файлову систему. Коли процес закінчиться, inode буде звільнений, а зберігання повернеться у вільний список.

EDIT: Як зазначає Мат, перший підхід не працюватиме, оскільки завантажувач намагатиметься виконати запит на сторінку у виконуваному файлі, що генеруватиме трафік випадкових запитів у файлі, а це неможливо в трубі. Це залишає такий собі підхід, як другий.


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

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

Думаючи про це ще декілька, я впевнений, що пакети EXE, такі як UPX, можуть робити декомпресію та виконання на носіях, які лише для читання. Змініть будь-яку заглушку, яку вони приставлять до упакованих виконуваних файлів, щоб прочитати з труби, а не розпакувати, і ... може спрацювати.
Мат

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

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

7

Рішення за допомогою memfd syscall: 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

(Я зараз тестую це зараз, але я майже впевнений, що це чи щось наближене до вас спрацює)

EDIT: Якщо метою ваших трубопроводів є скорочення фізичних дисків з рівняння для швидкості, подумайте про створення оперативного диска для зберігання проміжного файлу.


Це, звичайно, спрацює, але пропускає головний пункт питання - виконати двійковий код, який ніколи не записується на диск.
rozcietrzewiacz

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

Так я зрозумів. Але для цього можна було просто скористатися csh.
rozcietrzewiacz

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.