开发者

fork and execve to inherit unprivileged parent process' capabilities

In Linux system, an unprivileged user launches a program. The process created has the capabilities CAP_NET_RAW,CAP_NET_ADMIN with mode as effective,permitted,inheritable. This process then creates a child process by calling fork and execv to invoke another program udhcpc, but the child process does not inherit the capabilities CAP_NET_RAW,CAP_NET_ADMIN as expected. Even though before setting the capabilities I have called prctl(PR_SET_KEEPCAPS, 1).

Any suggestion on开发者_运维知识库 what to do to inherit unprivileged parent process' capabilities upon fork followed by execve?


On execve(), the file capability sets of the file being executed (in this case, udhcpc) are inspected and combined with the thread's capability sets. In particular, the file's Inheritable set is AND-ed with the thread's Inheritable set to determine the new Permitted set, and the file's Effective bit must be set in order for the new Effective set to be copied from the Permitted set.

This implies that in your case you must use setcap cap_net_raw,cap_net_admin=ei /path/to/udhcpc to obtain the effect you want (in addition to setting the capabilities in the parent process - the prctl() is not necessary).


According to "The Linux Programming Interface" by Michael Kerrisk (No Starch Press, 2010):

Since kernel 2.6.24, it is possible to attach capabilities to a file. Various other features were added in kernels 2.6.25 and 2.6.26 in order to complete the capabilities implementation.

The tools sucap and execcap are what you should look up. However they are, if I recall limited to restricting, not granting capabilities. Look at :

http://www.linuxjournal.com/article/5737

and

http://lkml.indiana.edu/hypermail/linux/kernel/0503.1/2540.html


Extracted from the manual, There have been some changes. According to it fork does not change capabilities. And now there is an ambient set, it seems that this is for what you are trying to do.

   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).


It is useful to have a wrapper program that can execute any program with specific capabilities, without having to set capabilities on target programs. Such a wrapper is particularly useful to run software from a build directory (where setcap would be cumbersome) or to run interpreters like Python (where it would be inappropriate).

As explained in other answers, ambient capabilities solve this, but they are only available since kernel 4.3. It is possible to work around this problem by having the wrapper load the target program directly instead of using exec. By that, I mean open the executable, map relevant sections, set up the stack, etc., and jump to its code. This is a pretty complicated task, but luckily the wine-preloader program from the Wine project does exactly that (and some other things that are irrelevant for this purpose).

Run something like this as root to set up the wrapper:

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

Now we have a copy of wine-preloader that is able to run any program with those capabilities:

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

This works but there are some pitfalls:

  • The target program must be a path to an executable, it cannot find programs in PATH.
  • It does not work if the target program is a script with an interpreter (#!).
  • The wine-preloader prints a message about not being able to find something (but it still runs the program fine).
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜