具有setuid /功能的stdbuf

问题描述 投票:2回答:2

我正在读取另一个生成输出(慢速和无限)的过程的输出。因为我想实时读取这些数据,所以我使用“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在幕后所做的事情。

c linux buffering setuid linux-capabilities
2个回答
2
投票

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

我找到的一个建议是disable the noatsecure selinux attribute你的可执行文件。

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


1
投票

没有LD_PRELOAD的解决方案

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

用法:

unbuffer ./writer | ./reader

如果stdbuf与该计划合作,那么unbuffer也很有可能。因为LD_PRELOAD有一些限制,unbufferstdbuf有优势。与stdbuf相反,它将适用于这些类型的可执行文件:

  • setuid的
  • 具有文件功能
  • 静态联系
  • 不使用标准的libc
© www.soinside.com 2019 - 2024. All rights reserved.