通过 exec 传递功能

Adm*_*emo 9 linux setcap capabilities

我试图了解 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);
}
Run Code Online (Sandbox Code Playgroud)

当我在生成的可执行文件上设置 setuid 权限时,这会起作用:

~ $ sudo chown root: ./registerdns
~ $ sudo chmod u+s ./registerdns
~ $ ./registerdns 
Successfully registered hostname with DNS
Run Code Online (Sandbox Code Playgroud)

不过,我想使用功能而不是 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
Run Code Online (Sandbox Code Playgroud)

我还尝试cap_dac_overridenet可执行文件本身的功能上设置可继承标志:

~ $ 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
Run Code Online (Sandbox Code Playgroud)

我需要使用包装器来确保该功能仅在使用该确切参数集时才可用;该net程序还会执行其他一些操作,如果授予用户过于广泛的权限,这些操作可能会很危险。

我显然误解了继承的工作方式。我似乎无法弄清楚如何设置包装器以将其功能传递给替换过程,以便它可以使用它们。我已经阅读了手册页和无数其他关于它应该如何工作的文档,我以为我正在做它描述的事情。

Adm*_*emo 8

事实证明,包装器上的设置 +i不会将功能添加到CAP_INHERITABLE包装器进程的集合中,因此它不会通过exec。因此,我不得不手动添加CAP_DAC_OVERRIDECAP_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);
}
Run Code Online (Sandbox Code Playgroud)

此外,我必须添加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
Run Code Online (Sandbox Code Playgroud)

我想我现在完全明白发生了什么:

  1. 包装器需要CAP_DAC_OVERRIDE在其允许的集合中,以便可以将其添加到其可继承的集合中。
  2. 包装器的进程可继承集与它的文件可继承集不同,所以在文件上设置+i是没有用的;包装器必须显式添加CAP_DAC_OVERRIDECAP_INHERITABLEusing cap_set_flag/ cap_set_proc
  3. net文件需要CAP_DAC_OVERRIDE在其可继承集合中具有,以便它实际上可以将包装器的功能继承到其CAP_PERMITTED集合中。它还需要设置有效位,以便将其自动提升为CAP_EFFECTIVE

  • 您以一种危险的方式混合了可继承和允许的方式:通过授予文件允许的权限,您向所有调用它的人授予此权限。还要考虑较新的环境集。 (2认同)