LCOV - code coverage report
Current view: top level - basic - capability-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 32 284 11.3 %
Date: 2019-08-22 15:41:25 Functions: 4 12 33.3 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <grp.h>
       5             : #include <stdio.h>
       6             : #include <stdlib.h>
       7             : #include <sys/capability.h>
       8             : #include <sys/prctl.h>
       9             : #include <unistd.h>
      10             : 
      11             : #include "alloc-util.h"
      12             : #include "capability-util.h"
      13             : #include "cap-list.h"
      14             : #include "fileio.h"
      15             : #include "log.h"
      16             : #include "macro.h"
      17             : #include "missing_prctl.h"
      18             : #include "parse-util.h"
      19             : #include "user-util.h"
      20             : #include "util.h"
      21             : 
      22           1 : int have_effective_cap(int value) {
      23           1 :         _cleanup_cap_free_ cap_t cap;
      24             :         cap_flag_value_t fv;
      25             : 
      26           1 :         cap = cap_get_proc();
      27           1 :         if (!cap)
      28           0 :                 return -errno;
      29             : 
      30           1 :         if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0)
      31           0 :                 return -errno;
      32             : 
      33           1 :         return fv == CAP_SET;
      34             : }
      35             : 
      36         557 : unsigned long cap_last_cap(void) {
      37             :         static thread_local unsigned long saved;
      38             :         static thread_local bool valid = false;
      39         557 :         _cleanup_free_ char *content = NULL;
      40         557 :         unsigned long p = 0;
      41             :         int r;
      42             : 
      43         557 :         if (valid)
      44         553 :                 return saved;
      45             : 
      46             :         /* available since linux-3.2 */
      47           4 :         r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content);
      48           4 :         if (r >= 0) {
      49           4 :                 r = safe_atolu(content, &p);
      50           4 :                 if (r >= 0) {
      51             : 
      52           4 :                         if (p > 63) /* Safety for the future: if one day the kernel learns more than 64 caps,
      53             :                                      * then we are in trouble (since we, as much userspace and kernel space
      54             :                                      * store capability masks in uint64_t types). Let's hence protect
      55             :                                      * ourselves against that and always cap at 63 for now. */
      56           0 :                                 p = 63;
      57             : 
      58           4 :                         saved = p;
      59           4 :                         valid = true;
      60           4 :                         return p;
      61             :                 }
      62             :         }
      63             : 
      64             :         /* fall back to syscall-probing for pre linux-3.2 */
      65           0 :         p = MIN((unsigned long) CAP_LAST_CAP, 63U);
      66             : 
      67           0 :         if (prctl(PR_CAPBSET_READ, p) < 0) {
      68             : 
      69             :                 /* Hmm, look downwards, until we find one that works */
      70           0 :                 for (p--; p > 0; p --)
      71           0 :                         if (prctl(PR_CAPBSET_READ, p) >= 0)
      72           0 :                                 break;
      73             : 
      74             :         } else {
      75             : 
      76             :                 /* Hmm, look upwards, until we find one that doesn't work */
      77           0 :                 for (; p < 63; p++)
      78           0 :                         if (prctl(PR_CAPBSET_READ, p+1) < 0)
      79           0 :                                 break;
      80             :         }
      81             : 
      82           0 :         saved = p;
      83           0 :         valid = true;
      84             : 
      85           0 :         return p;
      86             : }
      87             : 
      88           0 : int capability_update_inherited_set(cap_t caps, uint64_t set) {
      89             :         unsigned long i;
      90             : 
      91             :         /* Add capabilities in the set to the inherited caps. Do not apply
      92             :          * them yet. */
      93             : 
      94           0 :         for (i = 0; i <= cap_last_cap(); i++) {
      95             : 
      96           0 :                 if (set & (UINT64_C(1) << i)) {
      97             :                         cap_value_t v;
      98             : 
      99           0 :                         v = (cap_value_t) i;
     100             : 
     101             :                         /* Make the capability inheritable. */
     102           0 :                         if (cap_set_flag(caps, CAP_INHERITABLE, 1, &v, CAP_SET) < 0)
     103           0 :                                 return -errno;
     104             :                 }
     105             :         }
     106             : 
     107           0 :         return 0;
     108             : }
     109             : 
     110           0 : int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
     111           0 :         _cleanup_cap_free_ cap_t caps = NULL;
     112             :         unsigned long i;
     113             :         int r;
     114             : 
     115             :         /* Add the capabilities to the ambient set. */
     116             : 
     117           0 :         if (also_inherit) {
     118           0 :                 caps = cap_get_proc();
     119           0 :                 if (!caps)
     120           0 :                         return -errno;
     121             : 
     122           0 :                 r = capability_update_inherited_set(caps, set);
     123           0 :                 if (r < 0)
     124           0 :                         return -errno;
     125             : 
     126           0 :                 if (cap_set_proc(caps) < 0)
     127           0 :                         return -errno;
     128             :         }
     129             : 
     130           0 :         for (i = 0; i <= cap_last_cap(); i++) {
     131             : 
     132           0 :                 if (set & (UINT64_C(1) << i)) {
     133             : 
     134             :                         /* Add the capability to the ambient set. */
     135           0 :                         if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0)
     136           0 :                                 return -errno;
     137             :                 }
     138             :         }
     139             : 
     140           0 :         return 0;
     141             : }
     142             : 
     143           0 : int capability_bounding_set_drop(uint64_t keep, bool right_now) {
     144           0 :         _cleanup_cap_free_ cap_t before_cap = NULL, after_cap = NULL;
     145             :         cap_flag_value_t fv;
     146             :         unsigned long i;
     147             :         int r;
     148             : 
     149             :         /* If we are run as PID 1 we will lack CAP_SETPCAP by default
     150             :          * in the effective set (yes, the kernel drops that when
     151             :          * executing init!), so get it back temporarily so that we can
     152             :          * call PR_CAPBSET_DROP. */
     153             : 
     154           0 :         before_cap = cap_get_proc();
     155           0 :         if (!before_cap)
     156           0 :                 return -errno;
     157             : 
     158           0 :         if (cap_get_flag(before_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
     159           0 :                 return -errno;
     160             : 
     161           0 :         if (fv != CAP_SET) {
     162           0 :                 _cleanup_cap_free_ cap_t temp_cap = NULL;
     163             :                 static const cap_value_t v = CAP_SETPCAP;
     164             : 
     165           0 :                 temp_cap = cap_dup(before_cap);
     166           0 :                 if (!temp_cap)
     167           0 :                         return -errno;
     168             : 
     169           0 :                 if (cap_set_flag(temp_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0)
     170           0 :                         return -errno;
     171             : 
     172           0 :                 if (cap_set_proc(temp_cap) < 0)
     173           0 :                         log_debug_errno(errno, "Can't acquire effective CAP_SETPCAP bit, ignoring: %m");
     174             : 
     175             :                 /* If we didn't manage to acquire the CAP_SETPCAP bit, we continue anyway, after all this just means
     176             :                  * we'll fail later, when we actually intend to drop some capabilities. */
     177             :         }
     178             : 
     179           0 :         after_cap = cap_dup(before_cap);
     180           0 :         if (!after_cap)
     181           0 :                 return -errno;
     182             : 
     183           0 :         for (i = 0; i <= cap_last_cap(); i++) {
     184             :                 cap_value_t v;
     185             : 
     186           0 :                 if ((keep & (UINT64_C(1) << i)))
     187           0 :                         continue;
     188             : 
     189             :                 /* Drop it from the bounding set */
     190           0 :                 if (prctl(PR_CAPBSET_DROP, i) < 0) {
     191           0 :                         r = -errno;
     192             : 
     193             :                         /* If dropping the capability failed, let's see if we didn't have it in the first place. If so,
     194             :                          * continue anyway, as dropping a capability we didn't have in the first place doesn't really
     195             :                          * matter anyway. */
     196           0 :                         if (prctl(PR_CAPBSET_READ, i) != 0)
     197           0 :                                 goto finish;
     198             :                 }
     199           0 :                 v = (cap_value_t) i;
     200             : 
     201             :                 /* Also drop it from the inheritable set, so
     202             :                  * that anything we exec() loses the
     203             :                  * capability for good. */
     204           0 :                 if (cap_set_flag(after_cap, CAP_INHERITABLE, 1, &v, CAP_CLEAR) < 0) {
     205           0 :                         r = -errno;
     206           0 :                         goto finish;
     207             :                 }
     208             : 
     209             :                 /* If we shall apply this right now drop it
     210             :                  * also from our own capability sets. */
     211           0 :                 if (right_now) {
     212           0 :                         if (cap_set_flag(after_cap, CAP_PERMITTED, 1, &v, CAP_CLEAR) < 0 ||
     213           0 :                             cap_set_flag(after_cap, CAP_EFFECTIVE, 1, &v, CAP_CLEAR) < 0) {
     214           0 :                                 r = -errno;
     215           0 :                                 goto finish;
     216             :                         }
     217             :                 }
     218             :         }
     219             : 
     220           0 :         r = 0;
     221             : 
     222           0 : finish:
     223           0 :         if (cap_set_proc(after_cap) < 0) {
     224             :                 /* If there are no actual changes anyway then let's ignore this error. */
     225           0 :                 if (cap_compare(before_cap, after_cap) != 0)
     226           0 :                         r = -errno;
     227             :         }
     228             : 
     229           0 :         return r;
     230             : }
     231             : 
     232           0 : static int drop_from_file(const char *fn, uint64_t keep) {
     233           0 :         _cleanup_free_ char *p = NULL;
     234             :         uint64_t current, after;
     235             :         uint32_t hi, lo;
     236             :         int r, k;
     237             : 
     238           0 :         r = read_one_line_file(fn, &p);
     239           0 :         if (r < 0)
     240           0 :                 return r;
     241             : 
     242           0 :         k = sscanf(p, "%" PRIu32 " %" PRIu32, &lo, &hi);
     243           0 :         if (k != 2)
     244           0 :                 return -EIO;
     245             : 
     246           0 :         current = (uint64_t) lo | ((uint64_t) hi << 32);
     247           0 :         after = current & keep;
     248             : 
     249           0 :         if (current == after)
     250           0 :                 return 0;
     251             : 
     252           0 :         lo = after & UINT32_C(0xFFFFFFFF);
     253           0 :         hi = (after >> 32) & UINT32_C(0xFFFFFFFF);
     254             : 
     255           0 :         return write_string_filef(fn, 0, "%" PRIu32 " %" PRIu32, lo, hi);
     256             : }
     257             : 
     258           0 : int capability_bounding_set_drop_usermode(uint64_t keep) {
     259             :         int r;
     260             : 
     261           0 :         r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", keep);
     262           0 :         if (r < 0)
     263           0 :                 return r;
     264             : 
     265           0 :         r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", keep);
     266           0 :         if (r < 0)
     267           0 :                 return r;
     268             : 
     269           0 :         return r;
     270             : }
     271             : 
     272           0 : int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
     273             :         int r;
     274             : 
     275             :         /* Unfortunately we cannot leave privilege dropping to PID 1 here, since we want to run as user but
     276             :          * want to keep some capabilities. Since file capabilities have been introduced this cannot be done
     277             :          * across exec() anymore, unless our binary has the capability configured in the file system, which
     278             :          * we want to avoid. */
     279             : 
     280           0 :         if (setresgid(gid, gid, gid) < 0)
     281           0 :                 return log_error_errno(errno, "Failed to change group ID: %m");
     282             : 
     283           0 :         r = maybe_setgroups(0, NULL);
     284           0 :         if (r < 0)
     285           0 :                 return log_error_errno(r, "Failed to drop auxiliary groups list: %m");
     286             : 
     287             :         /* Ensure we keep the permitted caps across the setresuid(). Note that we do this even if we actually
     288             :          * don't want to keep any capabilities, since we want to be able to drop them from the bounding set
     289             :          * too, and we can only do that if we have capabilities. */
     290           0 :         if (prctl(PR_SET_KEEPCAPS, 1) < 0)
     291           0 :                 return log_error_errno(errno, "Failed to enable keep capabilities flag: %m");
     292             : 
     293           0 :         if (setresuid(uid, uid, uid) < 0)
     294           0 :                 return log_error_errno(errno, "Failed to change user ID: %m");
     295             : 
     296           0 :         if (prctl(PR_SET_KEEPCAPS, 0) < 0)
     297           0 :                 return log_error_errno(errno, "Failed to disable keep capabilities flag: %m");
     298             : 
     299             :         /* Drop all caps from the bounding set (as well as the inheritable/permitted/effective sets), except
     300             :          * the ones we want to keep */
     301           0 :         r = capability_bounding_set_drop(keep_capabilities, true);
     302           0 :         if (r < 0)
     303           0 :                 return log_error_errno(r, "Failed to drop capabilities: %m");
     304             : 
     305             :         /* Now upgrade the permitted caps we still kept to effective caps */
     306           0 :         if (keep_capabilities != 0) {
     307           0 :                 cap_value_t bits[u64log2(keep_capabilities) + 1];
     308           0 :                 _cleanup_cap_free_ cap_t d = NULL;
     309           0 :                 unsigned i, j = 0;
     310             : 
     311           0 :                 d = cap_init();
     312           0 :                 if (!d)
     313           0 :                         return log_oom();
     314             : 
     315           0 :                 for (i = 0; i < ELEMENTSOF(bits); i++)
     316           0 :                         if (keep_capabilities & (1ULL << i))
     317           0 :                                 bits[j++] = i;
     318             : 
     319             :                 /* use enough bits */
     320           0 :                 assert(i == 64 || (keep_capabilities >> i) == 0);
     321             :                 /* don't use too many bits */
     322           0 :                 assert(keep_capabilities & (UINT64_C(1) << (i - 1)));
     323             : 
     324           0 :                 if (cap_set_flag(d, CAP_EFFECTIVE, j, bits, CAP_SET) < 0 ||
     325           0 :                     cap_set_flag(d, CAP_PERMITTED, j, bits, CAP_SET) < 0)
     326           0 :                         return log_error_errno(errno, "Failed to enable capabilities bits: %m");
     327             : 
     328           0 :                 if (cap_set_proc(d) < 0)
     329           0 :                         return log_error_errno(errno, "Failed to increase capabilities: %m");
     330             :         }
     331             : 
     332           0 :         return 0;
     333             : }
     334             : 
     335           1 : int drop_capability(cap_value_t cv) {
     336           1 :         _cleanup_cap_free_ cap_t tmp_cap = NULL;
     337             : 
     338           1 :         tmp_cap = cap_get_proc();
     339           1 :         if (!tmp_cap)
     340           0 :                 return -errno;
     341             : 
     342           2 :         if ((cap_set_flag(tmp_cap, CAP_INHERITABLE, 1, &cv, CAP_CLEAR) < 0) ||
     343           2 :             (cap_set_flag(tmp_cap, CAP_PERMITTED, 1, &cv, CAP_CLEAR) < 0) ||
     344           1 :             (cap_set_flag(tmp_cap, CAP_EFFECTIVE, 1, &cv, CAP_CLEAR) < 0))
     345           0 :                 return -errno;
     346             : 
     347           1 :         if (cap_set_proc(tmp_cap) < 0)
     348           0 :                 return -errno;
     349             : 
     350           1 :         return 0;
     351             : }
     352             : 
     353           1 : bool ambient_capabilities_supported(void) {
     354             :         static int cache = -1;
     355             : 
     356           1 :         if (cache >= 0)
     357           0 :                 return cache;
     358             : 
     359             :         /* If PR_CAP_AMBIENT returns something valid, or an unexpected error code we assume that ambient caps are
     360             :          * available. */
     361             : 
     362           1 :         cache = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_KILL, 0, 0) >= 0 ||
     363           0 :                 !IN_SET(errno, EINVAL, EOPNOTSUPP, ENOSYS);
     364             : 
     365           1 :         return cache;
     366             : }
     367             : 
     368           0 : bool capability_quintet_mangle(CapabilityQuintet *q) {
     369             :         unsigned long i;
     370           0 :         uint64_t combined, drop = 0;
     371             :         bool ambient_supported;
     372             : 
     373           0 :         assert(q);
     374             : 
     375           0 :         combined = q->effective | q->bounding | q->inheritable | q->permitted;
     376             : 
     377           0 :         ambient_supported = q->ambient != (uint64_t) -1;
     378           0 :         if (ambient_supported)
     379           0 :                 combined |= q->ambient;
     380             : 
     381           0 :         for (i = 0; i <= cap_last_cap(); i++) {
     382           0 :                 unsigned long bit = UINT64_C(1) << i;
     383           0 :                 if (!FLAGS_SET(combined, bit))
     384           0 :                         continue;
     385             : 
     386           0 :                 if (prctl(PR_CAPBSET_READ, i) > 0)
     387           0 :                         continue;
     388             : 
     389           0 :                 drop |= bit;
     390             : 
     391           0 :                 log_debug("Not in the current bounding set: %s", capability_to_name(i));
     392             :         }
     393             : 
     394           0 :         q->effective &= ~drop;
     395           0 :         q->bounding &= ~drop;
     396           0 :         q->inheritable &= ~drop;
     397           0 :         q->permitted &= ~drop;
     398             : 
     399           0 :         if (ambient_supported)
     400           0 :                 q->ambient &= ~drop;
     401             : 
     402           0 :         return drop != 0; /* Let the caller know we changed something */
     403             : }
     404             : 
     405           0 : int capability_quintet_enforce(const CapabilityQuintet *q) {
     406           0 :         _cleanup_cap_free_ cap_t c = NULL, modified = NULL;
     407             :         int r;
     408             : 
     409           0 :         if (q->ambient != (uint64_t) -1) {
     410             :                 unsigned long i;
     411           0 :                 bool changed = false;
     412             : 
     413           0 :                 c = cap_get_proc();
     414           0 :                 if (!c)
     415           0 :                         return -errno;
     416             : 
     417             :                 /* In order to raise the ambient caps set we first need to raise the matching inheritable + permitted
     418             :                  * cap */
     419           0 :                 for (i = 0; i <= cap_last_cap(); i++) {
     420           0 :                         uint64_t m = UINT64_C(1) << i;
     421           0 :                         cap_value_t cv = (cap_value_t) i;
     422             :                         cap_flag_value_t old_value_inheritable, old_value_permitted;
     423             : 
     424           0 :                         if ((q->ambient & m) == 0)
     425           0 :                                 continue;
     426             : 
     427           0 :                         if (cap_get_flag(c, cv, CAP_INHERITABLE, &old_value_inheritable) < 0)
     428           0 :                                 return -errno;
     429           0 :                         if (cap_get_flag(c, cv, CAP_PERMITTED, &old_value_permitted) < 0)
     430           0 :                                 return -errno;
     431             : 
     432           0 :                         if (old_value_inheritable == CAP_SET && old_value_permitted == CAP_SET)
     433           0 :                                 continue;
     434             : 
     435           0 :                         if (cap_set_flag(c, CAP_INHERITABLE, 1, &cv, CAP_SET) < 0)
     436           0 :                                 return -errno;
     437           0 :                         if (cap_set_flag(c, CAP_PERMITTED, 1, &cv, CAP_SET) < 0)
     438           0 :                                 return -errno;
     439             : 
     440           0 :                         changed = true;
     441             :                 }
     442             : 
     443           0 :                 if (changed)
     444           0 :                         if (cap_set_proc(c) < 0)
     445           0 :                                 return -errno;
     446             : 
     447           0 :                 r = capability_ambient_set_apply(q->ambient, false);
     448           0 :                 if (r < 0)
     449           0 :                         return r;
     450             :         }
     451             : 
     452           0 :         if (q->inheritable != (uint64_t) -1 || q->permitted != (uint64_t) -1 || q->effective != (uint64_t) -1) {
     453           0 :                 bool changed = false;
     454             :                 unsigned long i;
     455             : 
     456           0 :                 if (!c) {
     457           0 :                         c = cap_get_proc();
     458           0 :                         if (!c)
     459           0 :                                 return -errno;
     460             :                 }
     461             : 
     462           0 :                 for (i = 0; i <= cap_last_cap(); i++) {
     463           0 :                         uint64_t m = UINT64_C(1) << i;
     464           0 :                         cap_value_t cv = (cap_value_t) i;
     465             : 
     466           0 :                         if (q->inheritable != (uint64_t) -1) {
     467             :                                 cap_flag_value_t old_value, new_value;
     468             : 
     469           0 :                                 if (cap_get_flag(c, cv, CAP_INHERITABLE, &old_value) < 0) {
     470           0 :                                         if (errno == EINVAL) /* If the kernel knows more caps than this
     471             :                                                               * version of libcap, then this will return
     472             :                                                               * EINVAL. In that case, simply ignore it,
     473             :                                                               * pretend it doesn't exist. */
     474           0 :                                                 continue;
     475             : 
     476           0 :                                         return -errno;
     477             :                                 }
     478             : 
     479           0 :                                 new_value = (q->inheritable & m) ? CAP_SET : CAP_CLEAR;
     480             : 
     481           0 :                                 if (old_value != new_value) {
     482           0 :                                         changed = true;
     483             : 
     484           0 :                                         if (cap_set_flag(c, CAP_INHERITABLE, 1, &cv, new_value) < 0)
     485           0 :                                                 return -errno;
     486             :                                 }
     487             :                         }
     488             : 
     489           0 :                         if (q->permitted != (uint64_t) -1) {
     490             :                                 cap_flag_value_t old_value, new_value;
     491             : 
     492           0 :                                 if (cap_get_flag(c, cv, CAP_PERMITTED, &old_value) < 0) {
     493           0 :                                         if (errno == EINVAL)
     494           0 :                                                 continue;
     495             : 
     496           0 :                                         return -errno;
     497             :                                 }
     498             : 
     499           0 :                                 new_value = (q->permitted & m) ? CAP_SET : CAP_CLEAR;
     500             : 
     501           0 :                                 if (old_value != new_value) {
     502           0 :                                         changed = true;
     503             : 
     504           0 :                                         if (cap_set_flag(c, CAP_PERMITTED, 1, &cv, new_value) < 0)
     505           0 :                                                 return -errno;
     506             :                                 }
     507             :                         }
     508             : 
     509           0 :                         if (q->effective != (uint64_t) -1) {
     510             :                                 cap_flag_value_t old_value, new_value;
     511             : 
     512           0 :                                 if (cap_get_flag(c, cv, CAP_EFFECTIVE, &old_value) < 0) {
     513           0 :                                         if (errno == EINVAL)
     514           0 :                                                 continue;
     515             : 
     516           0 :                                         return -errno;
     517             :                                 }
     518             : 
     519           0 :                                 new_value = (q->effective & m) ? CAP_SET : CAP_CLEAR;
     520             : 
     521           0 :                                 if (old_value != new_value) {
     522           0 :                                         changed = true;
     523             : 
     524           0 :                                         if (cap_set_flag(c, CAP_EFFECTIVE, 1, &cv, new_value) < 0)
     525           0 :                                                 return -errno;
     526             :                                 }
     527             :                         }
     528             :                 }
     529             : 
     530           0 :                 if (changed) {
     531             :                         /* In order to change the bounding caps, we need to keep CAP_SETPCAP for a bit
     532             :                          * longer. Let's add it to our list hence for now. */
     533           0 :                         if (q->bounding != (uint64_t) -1) {
     534           0 :                                 cap_value_t cv = CAP_SETPCAP;
     535             : 
     536           0 :                                 modified = cap_dup(c);
     537           0 :                                 if (!modified)
     538           0 :                                         return -ENOMEM;
     539             : 
     540           0 :                                 if (cap_set_flag(modified, CAP_PERMITTED, 1, &cv, CAP_SET) < 0)
     541           0 :                                         return -errno;
     542           0 :                                 if (cap_set_flag(modified, CAP_EFFECTIVE, 1, &cv, CAP_SET) < 0)
     543           0 :                                         return -errno;
     544             : 
     545           0 :                                 if (cap_compare(modified, c) == 0) {
     546             :                                         /* No change? then drop this nonsense again */
     547           0 :                                         cap_free(modified);
     548           0 :                                         modified = NULL;
     549             :                                 }
     550             :                         }
     551             : 
     552             :                         /* Now, let's enforce the caps for the first time. Note that this is where we acquire
     553             :                          * caps in any of the sets we currently don't have. We have to do this before
     554             :                          * dropping the bounding caps below, since at that point we can never acquire new
     555             :                          * caps in inherited/permitted/effective anymore, but only lose them. */
     556           0 :                         if (cap_set_proc(modified ?: c) < 0)
     557           0 :                                 return -errno;
     558             :                 }
     559             :         }
     560             : 
     561           0 :         if (q->bounding != (uint64_t) -1) {
     562           0 :                 r = capability_bounding_set_drop(q->bounding, false);
     563           0 :                 if (r < 0)
     564           0 :                         return r;
     565             :         }
     566             : 
     567             :         /* If needed, let's now set the caps again, this time in the final version, which differs from what
     568             :          * we have already set only in the CAP_SETPCAP bit, which we needed for dropping the bounding
     569             :          * bits. This call only undoes bits and doesn't acquire any which means the bounding caps don't
     570             :          * matter. */
     571           0 :         if (modified)
     572           0 :                 if (cap_set_proc(c) < 0)
     573           0 :                         return -errno;
     574             : 
     575           0 :         return 0;
     576             : }

Generated by: LCOV version 1.14