2

ユーザー入力をサーバー側コマンドにリダイレクトする Node.JS アプリケーションを構築しています。もちろん、それはセキュリティに壊滅的な影響を与える可能性があるため、子コマンドをSELinux サンドボックス内で実行したいと考えています。(アプリケーション全体をサンドボックス内で実行したくありません。これは、エンド ユーザーがそれぞれサーバー上に独自のワークスペースを持つことを望んでいるためです。)

たとえば、コマンドを考えてみましょうcowsay。サンドボックス化されたカウセイを実行するには、単にsandbox cowsay. 舞台裏のセキュリティの違いを除けば、 のインターフェースsandbox cowsayは plain のインターフェースと同じでなければなりませんcowsay

ただし、Node.JS はこれら 2 つのアプローチに対して異なる対応をします。次のコードを検討してください。

var spawn = require('child_process').spawn;                      
var cmd = spawn("cowsay", ["hello"]); // line A (no sandbox) 
var cmd = spawn("sandbox", ["cowsay", "hello"]); // line B (with sandbox)
cmd.stdout.on("data", function(data){
    console.log("stdout: "+data);
});
cmd.stderr.on("data", function(data){
    console.log("stderr: "+data);
});
cmd.on("exit", function(err){
    console.log("exit: "+err);
});

行 A を含むバージョンの出力を次に示します。

$ node run.js
stdout:  _______ 
< hello >
 ------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

exit: 0

しかし、代わりにB行を含むバージョンの出力は次のとおりです。

$ node run.js
exit: 0

つまり、Node.JS はサンドボックスの子プロセスからストリームを読み取っていないようです。

このテストは、任意のコマンドを使用して実行できます。たとえば、python コマンド インタープリターを使用したとします。ここで何が起こるかというと、サンドボックスpython化されていないものは Node.JS から stdin に何かが供給されるのを待ちますが、サンドボックス化されたものはpython待機せずに単にコード 0 で存在します。

この動作は、SELinux が「enforcing」モードの場合にのみ発生します。サンドボックス バージョンは、SELinux が「許可」(非強制) モードの場合に正常に動作します。

Node.JS がサンドボックス化されたコマンドをサンドボックス化されていないコマンドと同じように扱うには、何が必要ですか?

4

1 に答える 1

4

これをさらに数週間試した後、サンドボックスを期待どおりに機能させる方法を見つけました。

この問題は、SELinux が libuv (Node の基盤) を停止して UNIX ストリーム ソケットの読み取りと書き込みを停止しているように思われます。これはもちろん、Node の非ブロック I/O に必要です。これを見つけるのに非常に時間がかかった理由の 1 つは、このエラーが dontaudit ルールによって SELinux の監査から隠されていたことです。

私たちは次のことから始めました。

# semodule -DB  ## turns off dontaudit rules
# tail -f /var/log/audit/audit.log

次に、別のターミナルでアプリケーションを実行します。一連の SELinux 監査が表示されますが、最も重要なのは次のようなものです。

type=AVC msg=audit(1370065734.791:5038): avc:  denied  { read write } for  pid=8887 comm="my_command" path="socket:[1258916]" dev=sockfs ino=1258916 scontext=unconfined_u:unconfined_r:sandbox_t:s0:c98,c807 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket

これをポリシーにするために、次のことを行いました。

# grep "type=AVC msg=audit(1370065734.791:5038)" /var/log/audit/audit.log  | audit2allow -M unixsocketsandbox
# semodule -i unixsocketsandbox.pp

ポリシーのunixsocketsandbox一意の名前です。ポリシー (経由cat unixsocketsandbox.te) は次のようになります。

allow sandbox_t unconfined_t:unix_stream_socket { read write };

この後、アプリケーションはサンドボックスの制限内で期待どおりに動作します。

于 2013-06-01T07:29:55.590 に答える