带有setuid /function的stdbuf

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

到目前为止,stdbuf工作得很好,但是该进程使用SOCK_RAW,并且需要以root身份运行,具有setuid(0)或cap_net_rawfunction。 以非root用户身份运行setuid或functionstdbuf似乎被忽略。 让我来certificate这个问题:

这是一个简单的作家:

 #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 ./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) 

我有兴趣了解为什么发生这种情况,以及如何继续使用stdbuf而不以root身份运行。 我承认我并不完全理解幕后的setuid在做什么。

从stdbuf源代码看,它看起来像通过设置LD_PRELOAD工作。 使用LD_PRELOAD和setuid可执行文件或sudo当然有安全问题。

我发现的一个建议是禁用可执行文件的noatsecure selinux属性 。

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

没有LD_PRELOAD解决方案

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

在你的情况下的用法:

 unbuffer ./writer | ./reader 

如果stdbuf与程序一起工作, unbuffer也会以很高的概率工作。 由于LD_PRELOAD带来一些限制, unbufferstdbuf有优势。 与stdbuf相反,它将与这些类型的可执行文件一起工作:

  • setuid的
  • 与文件功能
  • 静态链接
  • 不使用标准的libc