Apakah ada cara untuk mengeksekusi biner asli dari pipa?

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

Apakah ada cara untuk menjalankan biner keluaran pada sistem seperti unix?

EDIT: Saya membutuhkannya untuk menjalankan output dari g ++ di lingkungan sandboxed di mana saya tidak bisa menulis setiap berkas (tidak berbahaya, aku janji).

Alex B
sumber
Saya percaya bahwa mekanisme keamanan dasar harus mencegah ini. Tetapi jika kehebatan Anda adalah menjalankan kode C on-the-fly, gunakan saja csh.
rozcietrzewiacz

Jawaban:

9

Saya tidak percaya ini mungkin. The exec (2) system call selalu membutuhkan nama file atau path absolut (nama file selalu char*). posix_spawnjuga memiliki persyaratan serupa untuk nama file.

Yang paling dekat Anda bisa lakukan adalah pipa output ke pipa bernama dan coba jalankan dari pipa. Itu mungkin berhasil, meskipun shell mungkin menolak untuk mengeksekusi file apa pun yang tidak memiliki --x--x--xbit yang ditetapkan. Buat pipa dengan mkfifo(1)dan lihat apakah Anda bisa membuatnya bekerja.

Pendekatan lain adalah menulis sesuatu yang membaca input standar, menulis file ke area temporay, menetapkan --x bit di atasnya, garpu dan eksekutif kemudian menghapus file. Inode dan konten akan tetap sampai program selesai dieksekusi tetapi tidak dapat diakses melalui sistem file. Ketika proses berakhir inode akan dirilis dan penyimpanan akan dikembalikan ke daftar gratis.

EDIT: Seperti yang ditunjukkan oleh Mat, pendekatan pertama tidak akan berhasil karena loader akan berusaha untuk meminta halaman pada file yang dapat dieksekusi, yang akan menghasilkan lalu lintas pencarian acak pada file, dan ini tidak mungkin dilakukan pada sebuah pipa. Ini meninggalkan semacam pendekatan seperti yang kedua.

ConcernedOfTunbridgeWells
sumber
2
Saya akan sangat terkejut jika trik pipa bekerja - Anda tidak dapat melakukan pencarian acak pada pipa, dan tidak bisa mmap mereka - Saya cukup yakin itu akan mengganggu runtime loader / linker :) Saran kedua Anda sepertinya bagus meskipun, tidak dapat menghasilkan apa pun tanpa file sementara.
Mat
@Mat - Saya pikir Anda benar. Permintaan paging di executable akan menyebabkan lalu lintas akses acak yang tidak akan berfungsi pada pipa. Ironisnya itu mungkin benar-benar bekerja pada SVR2.0 (versi terakhir yang tidak menggunakan permintaan paging) - Hanya untuk menunjukkan usia saya, saya benar-benar dulu memiliki AT&T 3B2 / 400 sekali dengan SVR2.0 sebagai O / S.
ConcernedOfTunbridgeWells
Berpikir tentang itu lagi, saya cukup yakin exe packers seperti UPX dapat melakukan dekompresi dan eksekusi pada media read-only. Ubah rintisan apa pun yang mereka tempel ke executable yang dikemas untuk membaca dari sebuah pipa daripada dekompresi, dan ... mungkin berhasil.
Mat
@Mat packers sudah memuat gambar, mereka tidak memulai proses baru. Untuk melakukan hal yang sama, saya perlu memiliki satu proses untuk melakukan lompatan sewenang-wenang ke data input (yang akan dianggap sebagai kerentanan keamanan).
Alex B
@Alex B: Anda secara khusus bertanya bagaimana melakukan lompatan sewenang-wenang ke data input. Mengapa Anda mengeluh ketika disarankan agar Anda melakukan hal itu? Apakah tujuan dari kotak pasir khusus untuk mencegah apa yang Anda coba lakukan?
David Schwartz
7

Solusi menggunakan memfd syscall: https://github.com/abbat/elfexec

Itu menciptakan deskriptor file bernama dalam memori yang dapat digunakan di exec. Kode semu:

#include <linux/memfd.h>
...
int memfd = syscall(SYS_memfd_create, "someName", 0);
...
write(memfd,... elf-content...);
...
fexecve(memfd, argv, environ);
kan
sumber
1
Anda tidak perlu memfd.htajuk kecuali Anda ingin menggunakan MFD_CLOEXEC(yang akan merusak #! /bin/shskrip karena bug di linux ' fexecve()). Itu tidak terlalu rumit, Anda dapat memasukkan sampel 20-baris yang berfungsi dalam jawaban Anda (mis. Inti git ini - meskipun itu bukan pengganti drop-in untuk Anda elfexec, karena itu juga akan memungkinkan Anda untuk menentukan argv[0], dan akan menjalankan biner hanya dari pipa (amanat UUoC ;-))
mosvy
Jadi saya tidak mengerti bagaimana ini diharapkan bekerja sama sekali. gcc akan menulis .ofile ke / tmp dan mati jika tidak bisa.
Joshua
4

Anda dapat mencoba tcc , yang akan mengkompilasi dan menjalankan program dalam satu langkah, tanpa menulis file perantara. Ini bukan gcc, yang mungkin menjadi masalah bagi Anda, tetapi sangat cepat, sehingga bahkan mungkin bertaruh lebih baik daripada gcc untuk tujuan Anda.

TheQUUX
sumber
2

Ini secara otomatis akan menjalankan kompilasi kode Anda, tetapi membuat file (sementara) pada sistem file untuk melakukannya.

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

(Saya sedang menguji ini sekarang, tapi saya cukup yakin ini, atau sesuatu yang dekat dengan itu akan bekerja untuk Anda)

EDIT: Jika tujuan perpipaan Anda adalah untuk memotong disk fisik dari persamaan untuk kecepatan, pertimbangkan untuk membuat ram ram untuk menyimpan file perantara.

dtyler
sumber
Hal ini tentu saja akan berhasil, tetapi melewatkan poin utama dari pertanyaan - untuk mengeksekusi kode biner yang tidak pernah ditulis ke disk.
rozcietrzewiacz
@rozcietrzewiacz Harapan saya adalah itu akan berguna jika tujuannya adalah untuk dengan mudah menjalankan potongan kode dengan cepat tanpa berurusan dengan file fisik yang diperlukan.
dtyler
Ya saya mengerti. Tapi untuk itu, orang bisa menggunakannya csh.
rozcietrzewiacz