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

StackOverflow https://stackoverflow.com/questions/14636359

Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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.

I think (my understanding), that the best way to use capabilities is:

  • For programs that need capabilities and are trusted including trusted not to leak capabilities: e.g. the packet sniffing part of wire-shark, a web server that needs to listen on port 80.
    • new programs, capabilities aware: set permitted.
    • legacy programs, not capabilities aware: set permitted and effective
  • For programs that will leak capabilities, and have code that could (sometimes) use a capability: set inherited
    • e.g. for chmod set inherit CAP_FOWNER, if user needs super powers (those normally held by root), then they need to use setpriv (or equivalent, this could be rolled into sudo), else it works in unprivileged mode.
  • When a process needs to fork and share some capabilities, then and only then use ambient. Probably same executable; if it was a different one, then this new one would have permitted or inherited set on the file. [Edit: I have just realised that you do not need ambient if you do not exec. If I think of a use-case for ambient, in a well set up system, then I will add it here. Ambient can be used as a transitional mechanism, when inherited is not set on files that could use it.]

Uses of ambient:

  • On a system where files do not have the correct capabilities. ( a transitional technique).
  • For shell scripts, that can not have capabilities (as they can not have setuid), except on systems that have fixed and then allow setuid on scripts.
  • Add more here.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top