【问题标题】:Linux process capabilities empty despite executable has them setLinux 进程功能为空,尽管可执行文件已设置
【发布时间】:2021-04-20 02:09:42
【问题描述】:

我有一个包装程序,它仅用于将CAP_NET_RAW 功能添加到 nodejs 脚本。该二进制文件已将功能设置为cap_net_raw+eip,但该进程没有获取它们并且设置它们会导致EPERM (Operation not permitted)。从 Debian 9 升级到 10 后,包装器停止工作。向 nodejs 二进制文件添加功能可以工作,并且 nodejs 脚本运行良好,但不希望允许对任何 nodejs 脚本的网络适配器进行原始访问。

这是包装源代码:

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

void main() {
        cap_t caps = cap_get_proc();
        cap_value_t newcaps[1] = { CAP_NET_RAW, };
        cap_set_flag(caps, CAP_INHERITABLE, 1, newcaps, CAP_SET);
        cap_set_proc(caps);
        cap_free(caps);
        execl("/usr/bin/node", "node", "/opt/sitemp/sitemp.js", NULL);
}

在 strace 下运行结果如下:

capget({version=_LINUX_CAPABILITY_VERSION_3, pid=0}, NULL) = 0
capget({version=_LINUX_CAPABILITY_VERSION_3, pid=0}, {effective=0, permitted=0, inheritable=0}) = 0
capset({version=_LINUX_CAPABILITY_VERSION_3, pid=0}, {effective=0, permitted=0, inheritable=1<<CAP_NET_RAW}) = -1 EPERM (Operation not permitted)

【问题讨论】:

  • 我已经通过在 systemd.service 中分配功能而不是自定义包装器/二进制文件来解决我的问题。 Systemd 服务具有属性 AmbientCapabilities 用于精确此
  • Linux 内核不信任具有文件权限的脚本,只信任已编译的二进制文件。如果您尝试制作sitemp.js setuid-root,也会出现同样的问题。
  • 权限设置在二进制文件上,而不是脚本上。此设置在 Debian 9 中有效,但在 10 中无效。
  • 与其试图在这里解释,我会发布一个更完整的答案......

标签: c linux linux-capabilities


【解决方案1】:

评论太长,这里有更完整的解释。

首先,文件功能仅适用于二进制文件。

让我们称您的包装程序为wrapper.c(编译为wrapper)。它被编码做的是提高一个可继承的能力。可继承功能可以使随后执行的程序具有特权的方式是它们与可执行文件上的“文件可继承”功能AND

也就是说,你可以这样做:

$ sudo setcap cap_net_raw=p ./wrapper
$ sudo setcap cap_net_raw=ie /usr/bin/node

现在,当您执行 ./wrapper 时,它将引发可继承的能力,当它 execl()s /usr/bin/node 时,组合将继承并提高正在运行的/usr/bin/node 的允许和有效标志中的cap_net_raw 能力程序。

如果您不使用./wrapper,您将没有进程可继承的能力,/usr/bin/node 将不会继承任何特权。

或者,您可以清除这些功能并将您的 wrapper.c 修改为如下所示:

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

void main() {
    cap_iab_t iab = cap_iab_from_text("^cap_net_raw");
    if (iab == NULL) {
        perror("iab not parsed");
        exit(1);
    }
    if (cap_iab_set_proc(iab)) {
        perror("unable to set iab");
        exit(1);
    }
    cap_free(iab);
    execl("/usr/bin/node", "node", "/opt/sitemp/sitemp.js", NULL);
    perror("execl failed");
}

您需要编译并设置此版本的wrapper 如下:

$ sudo setcap -r /usr/bin/node
$ cc -o wrapper wrapper.c -lcap
$ sudo setcap cap_net_raw,cap_setpcap=p ./wrapper

现在,当您运行 ./wrapper 时,它将同时提升 Ambient 和 Inheritable 功能,并且组合将导致 /usr/bin/node 直接从 ./wrapper 继承一些特权。

【讨论】:

  • 你的have privilege is they AND with可能有错字
  • 您能解释一下它与我的旧解决方案有何不同以及为什么它在 debian 9 上有效而在 debian 10 上无效?我的二进制文件确实设置了功能,但 cap_set_proc 返回错误。
  • 没有错字。这是一个逻辑 AND。至于您在早期版本的 Debian 中的尝试是如何工作的,我无法猜测。如果节点二进制文件没有 Inheritable 能力,进程可继承能力不能提高任何特权。自从添加了文件功能以来,在内核中就是如此。
  • 为什么具有cap_net_raw=eip 的包装器在调用cap_set_proc 时会得到EPERM?甚至 cap_get_proc 也没有返回任何功能
  • 如果你在strace下运行它,它的权限就会被抑制。内核这样做是为了防止权限提升,因为运行 strace 所需的内核 API 实际上可以修改被跟踪的 ./wrapper 二进制文件的行为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-11
  • 1970-01-01
  • 2017-07-14
  • 1970-01-01
  • 1970-01-01
  • 2011-12-20
相关资源
最近更新 更多