【问题标题】:stdbuf with setuid/capabilities带有 setuid/功能的 stdbuf
【发布时间】:2012-11-18 14:28:50
【问题描述】:

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

【问题讨论】:

  • getline() 中使用了什么函数?
  • 该示例使用 GNU getline(可与 -std=gnu99 一起使用),但行为与 fread 相同。
  • 你用strace看过了吗?

标签: c linux buffering setuid linux-capabilities


【解决方案1】:

stdbuf source code 看来,它似乎可以通过设置 LD_PRELOAD 来工作。将 LD_PRELOAD 与 setuid 可执行文件或 sudo 一起使用当然存在安全问题。

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

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

【讨论】:

  • 遗憾的是我无法控制作者的来源,所以我无法修改它。但是感谢有关 stdbuf 的解释,禁止 LD_PRELOAD 用于 setuid 是有意义的。
  • 还有一个用于stdbuf 的FreeBSD 端口的手册页显示了LD_PRELOAD 的使用:libstdbuf
【解决方案2】:

没有LD_PRELOAD的解决方案

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

在您的情况下的用法:

unbuffer ./writer | ./reader

如果stdbufunbuffer 程序一起工作,那么很有可能也会工作。因为LD_PRELOAD 有一些限制unbufferstdbuf 有优势。与stdbuf 不同,它适用于这些可执行文件:

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

【讨论】:

  • 您提到使用 pty 使缓冲区成为行缓冲区。这到底是什么意思?如果我有一条没有\n 的无限线,什么都不会出现?还是有一些限制?如果完全关闭缓冲,缓冲区中最多存在 1 个字节呢?
  • @CMCDragonkai 包括 GNU/Linux 在内的许多系统都试图与 ISO C 兼容。共有三种模式:无缓冲(所有内容都尽快发送)、完全缓冲(由其大小定义的缓冲区)、行缓冲(缓冲单行文本)。对于缓冲行,缓冲区仍然具有固定大小,因此当它被填充时,它会被刷新。没有缓冲“无限”的极长行。请参阅open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 部分 7.21.3 文件
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-16
  • 2012-03-03
  • 2013-11-03
  • 2016-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多