目前我正在尝试通过阅读来了解 Linux 的功能http://man7.org/linux/man-pages/man7/capability.7.html
我创建了一个具有以下功能的小型 C++ 应用程序CAP_DAC_READ_SEARCH+eip
该功能对于应用程序来说效果很好。但我system()
里面有电话
system("cat /dev/mtdX > targetFile");
我如何继承此调用的功能?
编辑:
我知道这system()
是由fork()
+驱动的execl()
。在文档中提到,fork()
子进程获得与父进程相同的功能。但为什么读能力没有被继承呢?
答案1
首先,你应该让system(3)
开;与您所建议的不同,system(3)
不仅是fork+exec
,而且是相当复杂的事情,涉及改变信号配置,等待子进程并用作/bin/sh
包装器(这可能会根据维护者的突发奇想和假设而删除或添加功能,弄乱环境变量,源初始化脚本,以及其他有趣的事情)。使用 justexecv*(2)
代替system(3)
会消除所有这些虚假的并发症。
其次,你应该深入了解一下“期间能力的转变execve()
”部分。capabilities(7)
联机帮助页。我不打算在这里复制粘贴它,但它基本上可以归结为:功能不会通过 execve() 继承,除非它们被添加到周围的放线程(进程)的,并且不能将它们添加到那里,除非它们已经在线程(进程)的可继承集中线。 (文件元数据中的“可继承”功能只是一个面具,限制线程的那些)。
因此,为了拥有继承的能力,execve()
你应该A)将它们从允许的到可继承的设置(你可以用capset(2)
系统调用 [1]) 和b)将它们添加到周围的设置(你可以用prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE)
)。
把它们放在一起:
$ cat capexec.c
#include <sys/prctl.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/capability.h>
#include <err.h>
int main(int ac, char **av){
static char *dav[] = { "/bin/bash", 0 };
struct __user_cap_header_struct hs;
struct __user_cap_data_struct ds[2];
hs.version = 0x20080522; /*_LINUX_CAPABILITY_VERSION_3;*/
hs.pid = getpid();
if(syscall(SYS_capget, &hs, ds)) err(1, "capget");
ds[0].inheritable = ds[0].permitted;
if(syscall(SYS_capset, &hs, ds)) err(1, "capset");
if(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_DAC_READ_SEARCH, 0, 0)) err(1, "prctl(pr_cap_ambient_raise)");
av = ac < 2 ? dav : av + 1;
execvp(*av, av);
err(1, "execvp %s", *av);
}
$ cc -Wall capexec.c -o capexec
# as root
# setcap cap_dac_read_search+ip /tmp/capexec
$ ./capexec dd if=/dev/sda of=/dev/null count=1
1+0 records in
1+0 records out
512 bytes copied, 0.000299173 s, 1.7 MB/s
[1] 文档建议使用 libcap 库;这个例子的部分内容是从我为旧版本的 android 编写的 hack 中删除的,其中没有 libcap,并且缺少许多标头定义。将其转换为使用 libcap 包装器作为练习留给读者。
答案2
谢谢@mosvy,我用 libcap 实现了他的解决方案,它似乎按预期工作。
void inheritCapabilities()
{
cap_t caps;
caps = cap_get_proc();
if (caps == NULL)
throw "Failed to load capabilities";
printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
cap_value_t cap_list[1];
cap_list[0] = CAP_DAC_READ_SEARCH;
if (cap_set_flag(caps, CAP_INHERITABLE, 1, cap_list, CAP_SET) == -1)
throw "Failed to set inheritable";
printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
if (cap_set_proc(caps) == -1)
throw "Failed to set proc";
printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
caps = cap_get_proc();
if (caps == NULL)
throw "Failed to load capabilities";
printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_DAC_READ_SEARCH, 0, 0) == -1)
throw "Failed to pr_cap_ambient_raise! Error: " + errno;
}
main() {
inheritCapabilities();
char *catargv[5];
catargv[0] = (char *)"cmd";
catargv[1] = (char *)"arg1";
catargv[2] = (char *)"arg2";
catargv[3] = (char *)"arg3";
catargv[4] = NULL;
if (execvp(catargv[0], catargv) == -1)
throw "Failed! command";
}