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

3

6

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.

Jellaba answered 31/1, 2013 at 22:31 Comment(3)
Can you please clarify a point, in your title you wrote "in spite of missing file capabilities", in your question you say you want to use this feature and set the whole file's capabilities bits to ei. Is the feature present or not in your system?Hamm
Means filesystem capabilities does not allow +i for, for example, files user have just compiled, but we still want that user to be able to use this capability. Getting capabilities using +i works only as intersection between process (user's) +i and filesystem's +i. Without contest of the filesystem (no +p and no +i), I can't run other executable preserving effective capability I already have. This created discrepancy (i.e. can load a dynamic library that will use my capability, but this library can't spawn processes without losing caps).Jellaba
So it is working, but not as you expected.Dexter
D
3

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.
Dexter answered 4/6, 2016 at 8:29 Comment(3)
Implementing setting ambient capabilities in my tool dived.Jellaba
@vi can you say that again using a full sentence?Dexter
I looked here and there to find a tool with allows experimenting with ambient cabapilities, but did find none (especially on Debian Stable). So I have added yet another option for this into my own tool "dive". In order to help other users who want to play with ambient capabilities without waiting for proper tools and libraries to catch up, I've decided to post a link somewhere related. And this answer which enlightened me about the feature seems like this related place.Jellaba
F
3

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.

Federalist answered 7/5, 2013 at 22:5 Comment(13)
Imagine I somehow running a program (shell) which have a effective permission. I can make it dynamically load libraries and execute any code. But it whould be convenient to also enable to load things apart from dynamic libraries (just usual programs). With PR_SET_NO_NEW_PRIVS you can't gain new privs. But I want a tool to prevent "losing" already existing privs.Jellaba
Setting the whole file system effective bit -> Or setting it for /lib/ld-linux*. strongly reduce the security on the system -> Should not, if you supervise processes getting +i. It shifts "granting privileges to programs" to "granting privileges to users" (i.e. user can compile and start any program exercizing this privilege).Jellaba
You can not give capabilities to a user directly, can you describe more in detail what you are trying to achieve? Why don't you want to set file capabilities from your shell, and then allow only users you trust to run this shell? Are you trying to write a program? To hack the kernel?Hamm
"set file capabilities from your shell" -> Needs CAP_SETFCAP.Jellaba
Example: allow user only CAP_NET_BIND_SERVICE for any programs (including ones he have just compiled). CAP_NET_BIND_SERVICE+i for this user can be set using PAM. The hacky workaround involves setting +i for /lib/ld-linux.so.2.Jellaba
Example 2: Semi-privileged (for example, with CAP_NET_RAW) process with plugins (in form of dynamic libraries), and it can auto-update its plugins. Suddenly one of plugins refactored and now spawns separate executable to do something (also CAP_NET_RAW-requiring). But the app can't set CAP_NET_RAW+i for that new executable and also can't call it preserving effective and inherited CAP_NET_RAW...Jellaba
I expanded my answer, as I misunderstood your question when I first answered. I thought you meant "missing filesystem-capabilities" as in file systems like NFS which don't support extended attributes, and don't have any filesystem-capabilities.Hamm
dropping file capabilities in inheritance rules across exec would introduce some security problems -> Of course, if executing program does not expect it (i.e. exec'ing untrusted things). Such exec-preserving-all-access should be explicitly requested by the callee of exec and be treated like "load library and execute a function from it" securitywise.Jellaba
But that's what you want to do, isn't it?Hamm
Yes. I don't want execve to change it's default behaviour, but to provide something like trusted_execve (for example, prctl, then execve) that never drops any privileges/capabilities. That way I will be sure that I can factor out things not just into a library, but into separate executable (without messing with additional things such as requiring somebody to set up +i on that new executable).Jellaba
That's not possible at the moment, read the kernel mailing list discussion I linked, they call trusted_execve SECURE_CAP_INHERITANCE.Hamm
This paragraph “If the file you want to execute doesn't have its fE bit set, or its fI bits aren't set, your process will have no permitted and therefore no effective capabilities.” is incorrect.Dexter
Thanks, I modified the sentence and replaced fE with fP. The intent was just to rephrase the first of the 3 equations.Hamm
D
3

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.
Dexter answered 4/6, 2016 at 8:29 Comment(3)
Implementing setting ambient capabilities in my tool dived.Jellaba
@vi can you say that again using a full sentence?Dexter
I looked here and there to find a tool with allows experimenting with ambient cabapilities, but did find none (especially on Debian Stable). So I have added yet another option for this into my own tool "dive". In order to help other users who want to play with ambient capabilities without waiting for proper tools and libraries to catch up, I've decided to post a link somewhere related. And this answer which enlightened me about the feature seems like this related place.Jellaba
D
0

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.
Dexter answered 1/9, 2016 at 19:37 Comment(4)
s/leek/leak/?Jellaba
Ambient capabilities can be used, for example, to just cancel the "ports less than 1024 only for root" rule. Or to factor network setup code into a shell script without settings any bits on /bin/sh. Or when file system is dumb and doesn't have extended attributes.Jellaba
@Vi I did what you sed. And by the way s/[?]/g/.Dexter
@Vi you have a good point, that I did not see: ambient for starting shell scripts. As for your first point, if you need to listen on ports < 1024, then set appropriate inherited bit on executable file. The sudo/setpriv or when ever it is called, could by default loot at what inherited bits are set, and set them as well, to activate them (of for a script use ambient).Dexter

© 2022 - 2024 — McMap. All rights reserved.