在 /dev 文件上设置 root-only 权限并构建二进制文件

Posted

技术标签:

【中文标题】在 /dev 文件上设置 root-only 权限并构建二进制文件【英文标题】:Setting root-only permissions on /dev files and build binary 【发布时间】:2020-04-30 15:31:09 【问题描述】:

作为构建过程的一部分,我想运行以下两个命令:

sudo chmod a+r /dev/cpu/*/msr
sudo setcap cap_sys_rawio=ep ./bench

这会将msr 内核模块公开的/dev/cpu/*/msr 文件设置为全球可读,并设置实际读取这些文件所需的./bench 二进制文件(作为构建的一部分生成)的额外权限。

问题是这需要root权限,因此sudo

我想要一个类似 setuid 根脚本的东西来完成这两个特定的事情,但 setuid root scripts 在现代 Linux 上不被推荐和禁用。

对于一个简单的解决方案,我有哪些选择?

只适用于第二行的解决方案(setcap)也很有趣,因为我需要这个来运行每个构建,而chmod 只需要运行一次开机。

【问题讨论】:

【参考方案1】:

您可以构建一个简单的 C 程序来代替 shell 脚本:

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

int main(void) 
    char *const envp[] = NULL;
    execle("/sbin/setcap", "setcap", "cap_sys_rawio=ep", "./bench", NULL, envp);
    perror("execle");
    return 1;

注意事项:

这是安全的,因为它忽略了它的环境(包括 PATH)并且不调用 shell,但它仍然可以从任何地方运行,所以不能保证 ./bench 是什么。您可能需要对绝对路径进行硬编码。 您可以使用相同的技巧来运行多个命令,但是您必须进入forkwait。 (不要使用 system,因为这会调用 shell 并破坏禁止 setuid 脚本的目的!) 您可以使用 the libcap functions 代替调用 setcap 二进制文件,但这会有点复杂。 您可以使用glob 来扩展/dev/cpu/*/msr,如果您想执行第一部分,则像shell 一样,然后使用statchown 来避免必须使用exec

【讨论】:

谢谢,我缺少的技巧是从 C 运行 shell 命令的简单方法。我知道你可以编写 C 程序,但我不想费力地将 shell 脚本转换为系统调用(这有时会非常复杂,因为底层过程做了很多工作)。【参考方案2】:

通过libcap 实现同样的事情实际上并没有那么多代码:

#include <stdio.h>
#include <sys/capability.h>

int main(int arc, char *argv[]) 
    cap_t c = cap_from_text("cap_sys_rawio=ep");
    int status = cap_set_file("./bench", c);
    cap_free(c);
    if (status)
        perror("attempt failed");
    return status != 0;

要编译它(在 debian 上,您需要 sudo apt-get install libcap-dev;在 fedora 上,sudo dnf install libcap-devel):

$ gcc -o mkcap mkcap.c -lcap

如果你只是按原样运行它,它将失败,因为程序需要有足够的权限才能将功能实际添加到./bench

$ ./mkcap
attempt failed: Operation not permitted

所以,你需要让它本身有足够的能力:

$ sudo /sbin/setcap cap_setfcap=ep ./mkcap
$ ./mkcap
$ echo $?
0
您可能需要考虑更明确地使用"./bench" 二进制文件的路径,因为根据您的环境,您可能会担心有人会滥用mkcapcap_sys_rawio 提供给其他程序。使用完整的路径名会更明确。 您也可以chmod go-x ./mkcap 限制谁可以运行它。 您还可以考虑对所有这些使用可继承的功能:
basic $ sudo setcap cap_setfcap=ei ./mkcap
basic $ ./mkcap
attempt failed: Operation not permitted
basic $ sudo capsh --inh=cap_setfcap --user=$(whoami) --
enhanced $ ./mkcap
enhanced $ echo $?
0

enhanced(capsh shell)层中,您可以在设置了文件可继承位的二进制文件上提高该功能。这样一来,默认的basic 层shell 就无法从mkcap 中获得任何特权。在所有其他方面,enhanced shell 层与basic 层相同。例如,您可以执行构建并且几乎可以正常做事。 (使用exit 离开enhanced shell。)

有一个pam_cap 模块还可以在登录等时向特定用户的所有shell 添加一个可继承位。

【讨论】:

cap_free可以设置errno;也许更好地检查status 并在cap_set_file 之后运行perror 在这种特殊情况下,我认为不这样做实际上是安全的。如果cap_free() 正在对有效指针进行操作,那么它不会设置errno。如果它正在操作其他东西,因为cap_from_text() 函数失败,那么打印的'perror()' 将提供更多信息。【参考方案3】:

正如已经建议的那样,使用 libcap 是一个很好的选择来设置功能。要访问没有 sudo 权限的 MSR,我建议使用 msr-safe。它已经为 Intel 实现了,但是我也成功地为 AMD 测试了它。加载 msr_safe 内核模块后,会有一些新文件。您将使用/dev/cpu/*/msr_safe,而不是通过/dev/cpu/*/msr 访问msrs。它将公开/dev/cpu/msr_allowlist(以前的msr_whitelist)中列出的寄存器。您还可以通过文件中的掩码来控制这些寄存器的哪些位是可写的。

此外,可以准备一个批处理 (/dev/cpu/msr_batch) - 您将重复访问的寄存器列表,因此可以减少开销。此功能在libmsr 中实现。

【讨论】:

以上是关于在 /dev 文件上设置 root-only 权限并构建二进制文件的主要内容,如果未能解决你的问题,请参考以下文章

php-fpm sock文件权限设置

Ubuntu - usb转串口设备的访问权限设置

Linux 20180412 隐藏权限lsattr_chattr等

我的linux下非root用户为何出现permission denied?

如何在特定文件夹上设置 777 权限? [关闭]

ACL权限与一些简单的查找命令