使用fork和execve继承非特权父进程的能力

10

在Linux系统中,一个非特权用户启动了一个程序。创建的进程具有 CAP_NET_RAW,CAP_NET_ADMIN 的能力,并且这些能力的模式是 effective,permitted,inheritable

该进程通过调用forkexecv来创建一个子进程以调用另一个程序udhcpc,但是子进程并没有如预期继承父进程的 CAP_NET_RAW,CAP_NET_ADMIN 能力。即使在设置能力之前,我已经调用了prctl(PR_SET_KEEPCAPS, 1)

有什么建议可以让子进程在fork后跟随execve继承非特权父进程的能力吗?


目前似乎无法在execve之后保留能力,而不设置文件能力。请参见[RFC] Capabilities still can't be inherited by normal programs(http://www.gossamer-threads.com/lists/linux/kernel/1641892)。 - Lekensteyn
Fork 可以传递它们,exec 不能(除非使用 ambient)。Exec 可以传递继承的,但被 exec 的文件也需要设置这个继承。 - ctrl-alt-delor
4个回答

14

execve() 中,被执行的文件(这里是 udhcpc)的能力集会被检查并与线程的能力集合并。特别地,文件的 Inheritable 集将与线程的 Inheritable 集进行 AND 操作以确定新的 Permitted 集,且必须设置文件的 Effective 位,以便从 Permitted 集中复制新的 Effective 集。

这意味着在您的情况下,您必须使用 setcap cap_net_raw,cap_net_admin=ei /path/to/udhcpc 来获得您想要的效果(除了在父进程中设置权限外- 不需要使用 prctl() )。


嗨,感谢您宝贵的答案。我正在使用内核2.6.18-7.1。我找不到setcap命令以为可执行文件提供能力。我认为这在最新的内核中是可用的。在内核2.6.18-7.1中是否有任何替代方法可以实现它。谢谢,Eswar - Eswar
@user736403:抱歉,我不确定在那些旧内核中的情况是什么。 - caf

2

从手册中提取,有一些变化。根据它的说法,fork不会改变能力。现在有一个环境设置,看起来这就是你要做的事情。

   Ambient (since Linux 4.3):
          This is a set of capabilities that are preserved across an execve(2) of a program that is not privileged.  The ambient capability set obeys the invariant that no capability can ever
          be ambient if it is not both permitted and inheritable.

          The ambient capability set can be directly modified using
          prctl(2).  Ambient capabilities are automatically lowered if
          either of the corresponding permitted or inheritable
          capabilities is lowered.

          Executing a program that changes UID or GID due to the set-
          user-ID or set-group-ID bits or executing a program that has
          any file capabilities set will clear the ambient set.  Ambient
          capabilities are added to the permitted set and assigned to
          the effective set when execve(2) is called.

   A child created via fork(2) inherits copies of its parent's
   capability sets.  See below for a discussion of the treatment of
   capabilities during execve(2).

       P'(ambient) = (file is privileged) ? 0 : P(ambient)

       P'(permitted) = (P(inheritable) & F(inheritable)) |
                       (F(permitted) & cap_bset) | P'(ambient)

       P'(effective) = F(effective) ? P'(permitted) : P'(ambient)

       P'(inheritable) = P(inheritable)    [i.e., unchanged]

   where:

       P         denotes the value of a thread capability set before the
                 execve(2)

       P'        denotes the value of a thread capability set after the
                 execve(2)

       F         denotes a file capability set

       cap_bset  is the value of the capability bounding set (described
                 below).

2

0

拥有一个包装程序,可以执行具有特定功能的任何程序,而无需在目标程序上设置功能,这非常有用。这样的包装程序特别适用于从构建目录运行软件(其中使用setcap将很麻烦)或运行解释器如Python(这是不合适的)。

如其他答案所述,环境能力可以解决此问题,但仅适用于内核4.3以后。可以通过让包装程序直接加载目标程序而不是使用exec来解决此问题。我的意思是打开可执行文件,映射相关部分,设置堆栈等,并跳转到其代码。这是一项相当复杂的任务,但幸运的是,Wine项目的wine-preloader程序正是这样做的(还有其他与此目的无关的事情)。

以root身份运行以下命令来设置包装程序:

cp /usr/bin/wine-preloader /path/to/wrapper
setcap cap_net_raw+ep /path/to/wrapper # set whatever capabilities you need

现在我们有一个能够运行任何具备这些功能的程序的wine-preloader副本:

/path/to/wrapper /path/to/executable arguments...

这个方法是可行的,但有一些缺陷:

  • 目标程序必须是可执行文件的路径,它不能在PATH中查找程序。
  • 如果目标程序是带解释器的脚本(#!),则无法正常工作。
  • wine-preloader会打印一个关于找不到某些东西的消息(但它仍然可以正常运行程序)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接