在 /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
是什么。您可能需要对绝对路径进行硬编码。
您可以使用相同的技巧来运行多个命令,但是您必须进入fork
和wait
。 (不要使用 system
,因为这会调用 shell 并破坏禁止 setuid 脚本的目的!)
您可以使用 the libcap
functions 代替调用 setcap 二进制文件,但这会有点复杂。
您可以使用glob
来扩展/dev/cpu/*/msr
,如果您想执行第一部分,则像shell 一样,然后使用stat
和chown
来避免必须使用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"
二进制文件的路径,因为根据您的环境,您可能会担心有人会滥用mkcap
将cap_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 权限并构建二进制文件的主要内容,如果未能解决你的问题,请参考以下文章
Linux 20180412 隐藏权限lsattr_chattr等