![通过 exec 传递能力](https://linux22.com/image/36334/%E9%80%9A%E8%BF%87%20exec%20%E4%BC%A0%E9%80%92%E8%83%BD%E5%8A%9B.png)
我试图了解 Linux 功能如何传递给已exec()
被另一个进程处理的进程。根据我的阅读,为了在 exec 之后保留某个功能,它必须位于可继承集中。但我不确定该集合是如何填充的。
我的目标是能够以普通用户身份运行通常需要 root 权限的程序。它需要的功能是cap_dac_override
可以读取私有文件。我不想赋予它任何其他功能。
这是我的包装:
#include <unistd.h>
int main(int argc, char *argv[]) {
return execl("/usr/bin/net", "net", "ads", "dns", "register", "-P", NULL);
}
当我对生成的可执行文件设置 setuid 权限时,这会起作用:
~ $ sudo chown root: ./registerdns
~ $ sudo chmod u+s ./registerdns
~ $ ./registerdns
Successfully registered hostname with DNS
不过,我想使用功能而不是 setuid。我尝试cap_dac_override
在包装器上设置功能:
~ $ sudo setcap cap_dac_override=eip ./registerdns
~ $ ./registerdns
Failed to open /var/lib/samba/private/secrets.tdb
ERROR: Unable to open secrets database
cap_dac_override
我还尝试在可执行文件本身的功能上设置可继承标志net
:
~ $ sudo setcap cap_dac_override=eip ./registerdns
~ $ sudo setcap cap_dac_override=i /usr/bin/net
~ $ ./registerdns
Failed to open /var/lib/samba/private/secrets.tdb
ERROR: Unable to open secrets database
我需要使用包装器来确保该功能仅在使用确切的参数集时才可用;该net
程序还执行其他一些操作,如果向用户授予过于广泛的权限,这些操作可能会很危险。
我显然误解了继承的运作方式。我似乎无法弄清楚如何设置包装器以将其功能传递给替换过程,以便它可以使用它们。我已经阅读了手册页以及无数其他有关如何使用它的文档应该工作,我以为我正在做它所描述的事情。
答案1
事实证明,在包装器上设置 +i 确实可以不是将能力添加到CAP_INHERITABLE
包装进程的集合中,因此它不会被传递exec
。因此,我必须在调用之前手动CAP_DAC_OVERRIDE
添加:CAP_INHERITABLE
execl
#include <sys/capability.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv[]) {
cap_t caps = cap_get_proc();
printf("Capabilities: %s\n", cap_to_text(caps, NULL));
cap_value_t newcaps[1] = { CAP_DAC_OVERRIDE, };
cap_set_flag(caps, CAP_INHERITABLE, 1, newcaps, CAP_SET);
cap_set_proc(caps);
printf("Capabilities: %s\n", cap_to_text(caps, NULL));
cap_free(caps);
return execl("/usr/bin/net", "net", "ads", "dns", "register", "-P", NULL);
}
此外,我还必须添加cap_dac_override
允许的文件功能设置/usr/bin/net
并设置有效位:
~ $ sudo setcap cap_dac_override=p ./registerdns
~ $ sudo setcap cap_dac_override=ei /usr/bin/net
~ $ ./registerdns
Capabilities = cap_dac_override+p
Capabilities = cap_dac_override+ip
Successfully registered hostname with DNS
我想我现在完全明白发生了什么:
- 包装器需要
CAP_DAC_OVERRIDE
在其允许集中,以便可以将其添加到其可继承集中。 - 包装器的进程可继承集与其文件可继承集不同,因此在文件上设置 +i 是没有用的;包装器必须显式添加
CAP_DAC_OVERRIDE
到CAP_INHERITABLE
usingcap_set_flag
/cap_set_proc
。 - 该
net
文件需要包含CAP_DAC_OVERRIDE
在其可继承集中,以便它实际上可以将功能从包装器继承到其CAP_PERMITTED
集中。它还需要设置有效位,以便自动提升为CAP_EFFECTIVE
。
答案2
我认为你需要两者:
setcap cap_dac_override+pe ./registerdns
setcap cap_dac_override+i /usr/bin/net
pe
上的标志表示registerdns
运行该程序获得了该功能。i
on 标志表示net
允许从调用程序继承功能。