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