Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to execve a process, retaining capabilities in spite of missing filesystem-based capabilities?

I want to make system usable without setuid, file "+p" capabilities, and in general without things which are disabled when I set PR_SET_NO_NEW_PRIVS.

With this approach (init sets PR_SET_NO_NEW_PRIVS and filesystem-based capability elevation no longer possible) you cannot "refill" your capabilities and only need to be careful not to "splatter" them.

How to execve some other process without "splattering" any granted capabilities (such as if the new program's file is setcap =ei)? Just "I trust this new process as I trust myself". For example, a capability is given to a user (and the user wants to exercise it in any program he starts)...

Can I make the entire filesystem permanently =ei? I want to keep the filesystem just not interfering with the scheme, not capable of granting or revoking capabilities; controlling everything through parent->child things.

like image 430
Vi. Avatar asked Jan 31 '13 22:01

Vi.


2 Answers

I am not saying that I recommend this for what you are doing, but here it is.

Extracted from the manual, There have been some changes. According to it: fork does not change capabilities. And now there is an ambient set added in Linux kernel 4.3, 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).

Transformation of capabilities during execve()
   During an execve(2), the kernel calculates the new capabilities of
   the process using the following algorithm:

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

   A privileged file is one that has capabilities or has the set-user-ID
   or set-group-ID bit set.
like image 91
ctrl-alt-delor Avatar answered Oct 05 '22 06:10

ctrl-alt-delor


There is currently no simple way to do that, if you refer to the capabilities' man page:

During an execve(2), the kernel calculates the new capabilities of the process
using the following algorithm:

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

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

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 capability set after the execve(2)
F        denotes a file capability set
cap_bset is the value of the capability bounding set 

If the file you want to execute doesn't have its fP bit set, or if its fI bits aren't set, your process will have no permitted and therefore no effective capabilities.

Setting the whole file system permitted and inheritance bits would be technically possible but that would not make much sense since it would strongly reduce the security on the system, (edit: and as you mentioned that won't work for new executables).

You can indeed give some capabilities to a user with pam_cap, but you can't let them execute any file they just compiled using that. Capabilities are by design made to give power to programs and not to users, you can read in Hallyn's paper:

A key insight is the observation that programs, not people, exercise privilege. That is, everything done in a computer is via agents—programs—and only if these programs know what to do with privilege can they be trusted to wield it.

See also the POSIX draft 1003.1e, which defines POSIX capabilities, page 310:

It is also not appropriate to establish for a process chain (a sequence of programs within a single process) a set of capabilities that remains fixed and active throughout the life of that chain. [...] This is an application of the principle of least privilege, and it applies equally to users and to processes.

Someone asked to introduce what you want to do as a feature in this Linux kernel mailing list recently (dec. 2012), and there are some very interesting answers given. Some people argue that dropping file capabilities in inheritance rules across exec would introduce some security problems and that capabilities are not designed for such a feature, even though no explanation is given wrt which security issue it would introduce:/

The only way to do that currently is to modify the way capabilities are inherited in the Linux kernel (2 files to modify, I tested it successfully on a 3.7 kernel), but it's not clear whether that is secured or not as mentioned above.

On old kernels (before 2.6.33) there was an option to compile without file's capabilities (CONFIG_SECURITY_FILE_CAPABILITIES), but I doubt working with such an old kernel is an option for you.

like image 38
Étienne Avatar answered Oct 05 '22 05:10

Étienne