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