]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/capability-util.c
Merge pull request #8575 from keszybz/non-absolute-paths
[thirdparty/systemd.git] / src / basic / capability-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
d7832d2c
KS
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
d7832d2c
KS
6***/
7
d7832d2c 8#include <errno.h>
3ffd4af2 9#include <grp.h>
d7832d2c 10#include <stdio.h>
11c3a366 11#include <stdlib.h>
d7832d2c
KS
12#include <sys/capability.h>
13#include <sys/prctl.h>
3ffd4af2 14#include <unistd.h>
d7832d2c 15
b5efdb8a 16#include "alloc-util.h"
430f0182 17#include "capability-util.h"
3ffd4af2
LP
18#include "fileio.h"
19#include "log.h"
d7832d2c 20#include "macro.h"
6bedfcbb 21#include "parse-util.h"
36d85478 22#include "user-util.h"
d7832d2c 23#include "util.h"
d7832d2c
KS
24
25int have_effective_cap(int value) {
5ce70e5b 26 _cleanup_cap_free_ cap_t cap;
d7832d2c 27 cap_flag_value_t fv;
d7832d2c 28
ec8927ca
LP
29 cap = cap_get_proc();
30 if (!cap)
d7832d2c
KS
31 return -errno;
32
33 if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0)
5ce70e5b 34 return -errno;
d7832d2c 35 else
5ce70e5b 36 return fv == CAP_SET;
d7832d2c
KS
37}
38
39unsigned long cap_last_cap(void) {
ec202eae
SL
40 static thread_local unsigned long saved;
41 static thread_local bool valid = false;
80b43783 42 _cleanup_free_ char *content = NULL;
a7f7d1bd 43 unsigned long p = 0;
80b43783 44 int r;
d7832d2c
KS
45
46 if (valid)
47 return saved;
48
80b43783
DH
49 /* available since linux-3.2 */
50 r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content);
51 if (r >= 0) {
52 r = safe_atolu(content, &p);
53 if (r >= 0) {
54 saved = p;
55 valid = true;
56 return p;
57 }
58 }
59
60 /* fall back to syscall-probing for pre linux-3.2 */
d7832d2c
KS
61 p = (unsigned long) CAP_LAST_CAP;
62
63 if (prctl(PR_CAPBSET_READ, p) < 0) {
64
65 /* Hmm, look downwards, until we find one that
66 * works */
67 for (p--; p > 0; p --)
68 if (prctl(PR_CAPBSET_READ, p) >= 0)
69 break;
70
71 } else {
72
73 /* Hmm, look upwards, until we find one that doesn't
74 * work */
75 for (;; p++)
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
86int 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
92 for (i = 0; i < cap_last_cap(); i++) {
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
108int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
109 unsigned long i;
110 _cleanup_cap_free_ cap_t caps = NULL;
111
112 /* Add the capabilities to the ambient set. */
113
114 if (also_inherit) {
115 int r;
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
128 for (i = 0; i < cap_last_cap(); i++) {
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 141int 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
220finish:
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 230static int drop_from_file(const char *fn, uint64_t keep) {
939b8f14
LP
231 int r, k;
232 uint32_t hi, lo;
233 uint64_t current, after;
234 char *p;
235
236 r = read_one_line_file(fn, &p);
237 if (r < 0)
238 return r;
239
240 assert_cc(sizeof(hi) == sizeof(unsigned));
241 assert_cc(sizeof(lo) == sizeof(unsigned));
242
243 k = sscanf(p, "%u %u", &lo, &hi);
244 free(p);
245
246 if (k != 2)
247 return -EIO;
248
249 current = (uint64_t) lo | ((uint64_t) hi << 32ULL);
a103496c 250 after = current & keep;
939b8f14
LP
251
252 if (current == after)
253 return 0;
254
255 lo = (unsigned) (after & 0xFFFFFFFFULL);
256 hi = (unsigned) ((after >> 32ULL) & 0xFFFFFFFFULL);
257
258 if (asprintf(&p, "%u %u", lo, hi) < 0)
259 return -ENOMEM;
260
4c1fc3e4 261 r = write_string_file(fn, p, WRITE_STRING_FILE_CREATE);
939b8f14
LP
262 free(p);
263
264 return r;
265}
266
a103496c 267int capability_bounding_set_drop_usermode(uint64_t keep) {
939b8f14
LP
268 int r;
269
a103496c 270 r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", keep);
939b8f14
LP
271 if (r < 0)
272 return r;
273
a103496c 274 r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", keep);
939b8f14
LP
275 if (r < 0)
276 return r;
277
278 return r;
279}
966bff26 280
ed617ec2 281int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
966bff26 282 _cleanup_cap_free_ cap_t d = NULL;
f11943c5 283 unsigned i, j = 0;
966bff26
LP
284 int r;
285
286 /* Unfortunately we cannot leave privilege dropping to PID 1
287 * here, since we want to run as user but want to keep some
288 * capabilities. Since file capabilities have been introduced
289 * this cannot be done across exec() anymore, unless our
290 * binary has the capability configured in the file system,
291 * which we want to avoid. */
292
4a62c710
MS
293 if (setresgid(gid, gid, gid) < 0)
294 return log_error_errno(errno, "Failed to change group ID: %m");
966bff26 295
97f0e76f
LP
296 r = maybe_setgroups(0, NULL);
297 if (r < 0)
298 return log_error_errno(r, "Failed to drop auxiliary groups list: %m");
966bff26 299
51ddf615
ZJS
300 /* Ensure we keep the permitted caps across the setresuid() */
301 if (prctl(PR_SET_KEEPCAPS, 1) < 0)
4a62c710 302 return log_error_errno(errno, "Failed to enable keep capabilities flag: %m");
966bff26
LP
303
304 r = setresuid(uid, uid, uid);
4a62c710
MS
305 if (r < 0)
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
f11943c5 311 /* Drop all caps from the bounding set, except the ones we want */
a103496c 312 r = capability_bounding_set_drop(keep_capabilities, true);
f647962d
MS
313 if (r < 0)
314 return log_error_errno(r, "Failed to drop capabilities: %m");
966bff26 315
f11943c5 316 /* Now upgrade the permitted caps we still kept to effective caps */
966bff26
LP
317 d = cap_init();
318 if (!d)
319 return log_oom();
320
51ddf615 321 if (keep_capabilities) {
057255fb 322 cap_value_t bits[u64log2(keep_capabilities) + 1];
6a010ac9 323
7d328b54 324 for (i = 0; i < ELEMENTSOF(bits); i++)
51ddf615
ZJS
325 if (keep_capabilities & (1ULL << i))
326 bits[j++] = i;
057255fb 327
2c9fc266
ZJS
328 /* use enough bits */
329 assert(i == 64 || (keep_capabilities >> i) == 0);
330 /* don't use too many bits */
331 assert(keep_capabilities & (1ULL << (i - 1)));
966bff26 332
51ddf615 333 if (cap_set_flag(d, CAP_EFFECTIVE, j, bits, CAP_SET) < 0 ||
e1427b13
MS
334 cap_set_flag(d, CAP_PERMITTED, j, bits, CAP_SET) < 0)
335 return log_error_errno(errno, "Failed to enable capabilities bits: %m");
51ddf615
ZJS
336
337 if (cap_set_proc(d) < 0)
338 return log_error_errno(errno, "Failed to increase capabilities: %m");
339 }
966bff26
LP
340
341 return 0;
342}
dd5ae4c3
PK
343
344int drop_capability(cap_value_t cv) {
345 _cleanup_cap_free_ cap_t tmp_cap = NULL;
346
347 tmp_cap = cap_get_proc();
348 if (!tmp_cap)
349 return -errno;
350
351 if ((cap_set_flag(tmp_cap, CAP_INHERITABLE, 1, &cv, CAP_CLEAR) < 0) ||
352 (cap_set_flag(tmp_cap, CAP_PERMITTED, 1, &cv, CAP_CLEAR) < 0) ||
353 (cap_set_flag(tmp_cap, CAP_EFFECTIVE, 1, &cv, CAP_CLEAR) < 0))
354 return -errno;
355
356 if (cap_set_proc(tmp_cap) < 0)
357 return -errno;
358
359 return 0;
360}
39f608e4
LP
361
362bool ambient_capabilities_supported(void) {
363 static int cache = -1;
364
365 if (cache >= 0)
366 return cache;
367
368 /* If PR_CAP_AMBIENT returns something valid, or an unexpected error code we assume that ambient caps are
369 * available. */
370
371 cache = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_KILL, 0, 0) >= 0 ||
372 !IN_SET(errno, EINVAL, EOPNOTSUPP, ENOSYS);
373
374 return cache;
375}