2

我正在构建一个涉及将用户输入重定向到服务器端命令的 Node.JS 应用程序。当然,这可能对安全性造成灾难性影响,因此我希望在SELinux 沙箱中运行子命令。(我不想在沙箱中运行整个应用程序,因为我希望最终用户在服务器上都有自己的工作区。)

例如,考虑命令cowsay。为了运行沙盒牛话,您只需要sandbox cowsay. 除了幕后的安全差异之外, 的接口sandbox cowsay应该与 plain 的接口相同cowsay

然而,Node.JS 对这两种方法的反应不同。考虑代码:

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 将某些内容输入其标准输入,但沙盒仅以python代码 0 存在,无需等待。

仅当 SELinux 处于“强制”模式时才会出现此行为。当 SELinux 处于“许可”(非强制)模式时,沙盒版本可以正常工作。

为了让 Node.JS 将沙盒命令与非沙盒命令相同,需要发生什么?

4

1 回答 1

4

在玩了几个星期之后,我们找到了一种让沙盒按预期工作的方法。

这个问题似乎涉及 SELinux 阻止 libuv(Node 的基础)读取和写入 UNIX 流套接字,这当然是 N​​ode 的非阻塞 I/O 所必需的。花了这么长时间才发现的一个原因是这个错误被 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是策略的唯一名称。该政策 (via cat unixsocketsandbox.te) 内容如下:

allow sandbox_t unconfined_t:unix_stream_socket { read write };

在此之后,应用程序在沙盒的限制内按预期工作。

于 2013-06-01T07:29:55.590 回答