パイプからネイティブバイナリを実行する方法はありますか?


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

UNIXライクなシステムで出力バイナリを実行する方法はありますか?

編集:私は書くことができないサンドボックス環境でG ++の出力を実行するために、それを必要な任意の(私は約束する悪質な何も、)ファイルを。


基本的なセキュリティメカニズムはこれを防ぐ必要があると思います。ただし、その場でCコードを実行する場合は、を使用しますcsh
rozcietrzewiacz

回答:


9

これが可能だとは思わない。EXEC(2)システムコールは、常にファイル名または絶対パス(ファイル名は常に必要char*)。 posix_spawnファイル名についても同様の要件があります。

最も近い方法は、出力を名前付きパイプにパイプし、パイプから実行してみることです。シェルは、--x--x--xビットが設定されていないファイルの実行を拒否する可能性がありますが、これは動作する可能性があります。でパイプを作成し、mkfifo(1)それを動作させることができるかどうかを確認します。

別のアプローチは、標準入力を読み取り、temporay領域にファイルを書き込み、そのファイルに--xビットを設定し、forkおよびexecsしてファイルを削除するものを書くことです。iノードとコンテンツは、プログラムの実行が完了するまで残りますが、ファイルシステムからはアクセスできません。プロセスが終了すると、iノードが解放され、ストレージが空きリストに戻されます。

編集: Matが指摘しているように、ローダーは実行可能ファイルのデマンドページングを試みるため、ファイルでランダムシークトラフィックを生成するため、最初のアプローチは機能しません。これはパイプでは不可能です これにより、2番目のような何らかのアプローチが残ります。


2
パイプのトリックがうまくいった場合、私は本当に驚きます-あなたはパイプでランダムシークを行うことはできず、それらをmmapすることはできません-それはランタイムローダー/リンカーを悩ますでしょう:)あなたの2番目の提案は良いようですただし、一時ファイルがないと何も思いつきません。
マット

@Mat-あなたは正しいと思います。実行可能ファイルのデマンドページングにより、ランダムアクセストラフィックが発生し、パイプでは機能しません。皮肉なことに、実際にSVR2.0(デマンドページングを使用しなかった最後のバージョン)で動作していた可能性があります。
ConcernedOfTunbridgeWells

さらに考えてみると、UPXのようなexeパッカーは、読み取り専用メディアで解凍実行を行うことができると確信しています。圧縮された実行可能ファイルに追加するスタブを変更して、圧縮解除するのではなくパイプから読み取るようにします。
マット

@Matパッカーには、新しいプロセスを開始しないイメージが既にロードされています。同様のことを行うには、入力データに任意のジャンプを行うプロセスの1つが必要です(これはセキュリティの脆弱性と見なされます)。
アレックスB

@Alex B:入力データに任意のジャンプを行う方法を具体的に求めています。正確にそうするように提案されたのに、なぜ文句を言うのでしょうか?サンドボックスの目的は、特にあなたがやろうとしていることを防ぐことですか?
デビッドシュワルツ

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/shLinuxのバグが原因でスクリプトが破損しますfexecve())。それはそれほど複雑ではありません、あなたはあなたの答えに20行の作業サンプルを含めることができます(例えば、このgit gist-elfexecそれはあなたのドロップイン置換ではありませんが、それはまた指定することを可能にしargv[0]、バイナリを実行しますパイプからのみ(UUoC必須
;

したがって、これがどのように機能するかはまったくわかりません。gccは.oファイルを/ tmpに書き込み、できない場合は終了します。
ジョシュア

4

tccを試すことができます。これは、中間ファイルを作成せずに、1ステップでプログラムをコンパイルおよび実行します。これは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

(私は現在これを現在テストしていますが、これ、またはそれに近いものがあなたのためにうまくいくと確信しています)

編集:パイプの目標が物理ディスクを速度の方程式から切り出すことである場合、中間ファイルを保持するためにRAMディスクを作成することを検討してください。


これはもちろん機能しますが、質問の要点を見逃します。ディスクに決して書き込まれないバイナリコードを実行することです。
-rozcietrzewiacz

@rozcietrzewiacz目標は、必要な物理ファイルを処理せずに、コードのスニペットをその場で簡単に実行することができれば便利だと思いました。
dtyler

はい、わかりました。しかし、そのためには、単に使用できますcsh
rozcietrzewiacz

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.