具有setuid /功能的stdbuf

时间:2012-11-30 11:07:15

标签: c linux buffering setuid linux-capabilities

我正在读取另一个生成输出(慢速和无限)的过程的输出。因为我想实时读取这些数据,所以我使用“stdbuf -oL”(行缓冲,数据是文本)。我无法控制生成过程,因此我无法修改源以强制刷新。

到目前为止,stdbuf工作正常,但是该过程使用SOCK_RAW并且需要以root身份运行,具有setuid(0)或cap_net_raw功能。当使用setuid或功能作为非root运行时,stdbuf似乎被忽略了。让我来说明问题:

这是一个简单的作家:

#include <stdio.h>
#include <unistd.h>

int main(){
        int i;
        for ( i = 0;; i++){
                fprintf(stdout, "%d\n", i);
                sleep(1);
        }
}

一位简单的读者:

#include <stdio.h>

int main(){
        char* line = NULL;
        size_t n = 0;
        while (getline(&line, &n, stdin) != -1 ) {
                fputs(line, stdout);
        }
}

正如预期的那样,通过执行./writer | ./reader,在填充缓冲区之前不会显示任何内容。预先stdbuf -oL启用行缓冲,我将这些行放入读者:

% stdbuf -oL ./writer | ./reader
0
1
2
...

但如果我添加cap_net_raw+ep,它就会停止工作:

% sudo setcap cap_net_raw+ep ./writer
% stdbuf -oL ./writer | ./reader
(no output)

使用setuid时会出现相同的行为:

% sudo chown root:root ./writer
% sudo chmod +s ./writer
% stdbuf -oL ./writer | ./reader
(no output)

我很想知道为什么会这样,以及如何在不以root身份运行的情况下继续使用stdbuf。我承认我并不完全理解setuid在幕后所做的事情。

2 个答案:

答案 0 :(得分:2)

通过设置LD_PRELOAD查看stdbuf source code它看起来是有效的。使用LD_PRELOAD和setuid可执行文件或sudo当然存在安全问题。

我发现有一个建议是disable the noatsecure selinux attribute为您的可执行文件。

另一个更简单的选择是避免使用stdbuf并直接从源代码中调用fflush(stdout)

答案 1 :(得分:1)

没有LD_PRELOAD

的解决方案

您可以使用属于unbufferexpect-devel)软件包的expect实用程序。 unbuffer是一个非常短的期望脚本。它不需要LD_PRELOAD,因为它使用了另一种技巧。 expect创建一个伪终端(如xtermssh),因此使用unbuffer执行的进程被欺骗,认为它正在写入交互设备,因此默认情况下它使用行缓冲stdout

在您的情况下使用:

unbuffer ./writer | ./reader

如果stdbuf适用于程序unbuffer,那么它也很有可能。由于LD_PRELOAD带来了一些限制unbuffer优于stdbuf。与stdbuf相反,它将适用于这些类型的可执行文件:

  • 的setuid
  • 具有文件功能
  • 静态链接
  • 未使用标准libc