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