• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 15057632786

15 May 2025 09:01PM UTC coverage: 72.267% (+0.02%) from 72.244%
15057632786

push

github

bluca
man: document how to hook stuff into system wakeup

Fixes: #6364

298523 of 413084 relevant lines covered (72.27%)

738132.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.55
/src/basic/capability-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <errno.h>
4
#include <linux/prctl.h>
5
#include <stdatomic.h>
6
#include <stdio.h>
7
#include <stdlib.h>
8
#include <sys/prctl.h>
9
#include <threads.h>
10
#include <unistd.h>
11

12
#include "alloc-util.h"
13
#include "bitfield.h"
14
#include "cap-list.h"
15
#include "capability-util.h"
16
#include "fd-util.h"
17
#include "fileio.h"
18
#include "log.h"
19
#include "logarithm.h"
20
#include "macro.h"
21
#include "parse-util.h"
22
#include "pidref.h"
23
#include "process-util.h"
24
#include "stat-util.h"
25
#include "user-util.h"
26

27
int have_effective_cap(int value) {
185,925✔
28
        _cleanup_cap_free_ cap_t cap = NULL;
185,925✔
29
        cap_flag_value_t fv = CAP_CLEAR; /* To avoid false-positive use-of-uninitialized-value error reported
185,925✔
30
                                          * by fuzzers. */
31

32
        cap = cap_get_proc();
185,925✔
33
        if (!cap)
185,925✔
34
                return -errno;
×
35

36
        if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0)
185,925✔
37
                return -errno;
×
38

39
        return fv == CAP_SET;
185,925✔
40
}
41

42
unsigned cap_last_cap(void) {
1,713,179✔
43
        static atomic_int saved = INT_MAX;
1,713,179✔
44
        int r, c;
1,713,179✔
45

46
        c = saved;
1,713,179✔
47
        if (c != INT_MAX)
1,713,179✔
48
                return c;
1,713,179✔
49

50
        /* Available since linux-3.2 */
51
        _cleanup_free_ char *content = NULL;
12,114✔
52
        r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content);
12,114✔
53
        if (r < 0)
12,114✔
54
                log_debug_errno(r, "Failed to read /proc/sys/kernel/cap_last_cap, ignoring: %m");
×
55
        else {
56
                r = safe_atoi(content, &c);
12,114✔
57
                if (r < 0)
12,114✔
58
                        log_debug_errno(r, "Failed to parse /proc/sys/kernel/cap_last_cap, ignoring: %m");
×
59
                else {
60
                        if (c > CAP_LIMIT) /* Safety for the future: if one day the kernel learns more than
12,114✔
61
                                            * 64 caps, then we are in trouble (since we, as much userspace
62
                                            * and kernel space store capability masks in uint64_t types). We
63
                                            * also want to use UINT64_MAX as marker for "unset". Hence let's
64
                                            * hence protect ourselves against that and always cap at 62 for
65
                                            * now. */
66
                                c = CAP_LIMIT;
×
67

68
                        saved = c;
12,114✔
69
                        return c;
12,114✔
70
                }
71
        }
72

73
        /* Fall back to syscall-probing for pre linux-3.2, or where /proc/ is not mounted */
74
        unsigned long p = (unsigned long) MIN(CAP_LAST_CAP, CAP_LIMIT);
×
75

76
        if (prctl(PR_CAPBSET_READ, p) < 0) {
×
77

78
                /* Hmm, look downwards, until we find one that works */
79
                for (p--; p > 0; p--)
×
80
                        if (prctl(PR_CAPBSET_READ, p) >= 0)
×
81
                                break;
82

83
        } else {
84

85
                /* Hmm, look upwards, until we find one that doesn't work */
86
                for (; p < CAP_LIMIT; p++)
×
87
                        if (prctl(PR_CAPBSET_READ, p+1) < 0)
×
88
                                break;
89
        }
90

91
        c = (int) p;
×
92
        saved = c;
×
93
        return c;
×
94
}
95

96
int capability_update_inherited_set(cap_t caps, uint64_t set) {
748✔
97
        /* Add capabilities in the set to the inherited caps, drops capabilities not in the set.
98
         * Do not apply them yet. */
99

100
        for (unsigned i = 0; i <= cap_last_cap(); i++) {
31,416✔
101
                cap_flag_value_t flag = set & (UINT64_C(1) << i) ? CAP_SET : CAP_CLEAR;
30,668✔
102
                cap_value_t v;
30,668✔
103

104
                v = (cap_value_t) i;
30,668✔
105

106
                if (cap_set_flag(caps, CAP_INHERITABLE, 1, &v, flag) < 0)
30,668✔
107
                        return -errno;
×
108
        }
109

110
        return 0;
111
}
112

113
int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
17,839✔
114
        _cleanup_cap_free_ cap_t caps = NULL;
17,839✔
115
        int r;
17,839✔
116

117
        /* Remove capabilities requested in ambient set, but not in the bounding set */
118
        for (unsigned i = 0; i <= cap_last_cap(); i++) {
749,238✔
119
                if (!BIT_SET(set, i))
731,399✔
120
                        continue;
724,771✔
121

122
                if (prctl(PR_CAPBSET_READ, (unsigned long) i) != 1) {
6,628✔
123
                        log_debug("Ambient capability %s requested but missing from bounding set, suppressing automatically.",
112✔
124
                                  capability_to_name(i));
125
                        CLEAR_BIT(set, i);
112✔
126
                }
127
        }
128

129
        /* Add the capabilities to the ambient set (an possibly also the inheritable set) */
130

131
        if (also_inherit) {
17,839✔
132
                caps = cap_get_proc();
747✔
133
                if (!caps)
747✔
134
                        return -errno;
×
135

136
                r = capability_update_inherited_set(caps, set);
747✔
137
                if (r < 0)
747✔
138
                        return -errno;
×
139

140
                if (cap_set_proc(caps) < 0)
747✔
141
                        return -errno;
×
142
        }
143

144
        for (unsigned i = 0; i <= cap_last_cap(); i++) {
749,238✔
145
                if (BIT_SET(set, i)) {
731,399✔
146
                        /* Add the capability to the ambient set. */
147
                        if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0)
6,516✔
148
                                return -errno;
×
149
                } else {
150
                        /* Drop the capability so we don't inherit capabilities we didn't ask for. */
151
                        r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, i, 0, 0);
724,883✔
152
                        if (r < 0)
724,883✔
153
                                return -errno;
×
154
                        if (r > 0)
724,883✔
155
                                if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, i, 0, 0) < 0)
488✔
156
                                        return -errno;
×
157
                }
158
        }
159

160
        return 0;
161
}
162

163
int capability_gain_cap_setpcap(cap_t *ret_before_caps) {
3,442✔
164
        _cleanup_cap_free_ cap_t caps = NULL;
3,442✔
165
        cap_flag_value_t fv;
3,442✔
166
        caps = cap_get_proc();
3,442✔
167
        if (!caps)
3,442✔
168
                return -errno;
×
169

170
        if (cap_get_flag(caps, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
3,442✔
171
                return -errno;
×
172

173
        if (fv != CAP_SET) {
3,442✔
174
                _cleanup_cap_free_ cap_t temp_cap = NULL;
800✔
175
                static const cap_value_t v = CAP_SETPCAP;
77✔
176

177
                temp_cap = cap_dup(caps);
77✔
178
                if (!temp_cap)
77✔
179
                        return -errno;
×
180

181
                if (cap_set_flag(temp_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0)
77✔
182
                        return -errno;
×
183

184
                if (cap_set_proc(temp_cap) < 0)
77✔
185
                        log_debug_errno(errno, "Can't acquire effective CAP_SETPCAP bit, ignoring: %m");
77✔
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 or try to set securebits. */
189
        }
190
        if (ret_before_caps)
3,442✔
191
                /* Return the capabilities as they have been before setting CAP_SETPCAP */
192
                *ret_before_caps = TAKE_PTR(caps);
2,642✔
193

194
        return 0;
2,642✔
195
}
196

197
int capability_bounding_set_drop(uint64_t keep, bool right_now) {
2,642✔
198
        _cleanup_cap_free_ cap_t before_cap = NULL, after_cap = NULL;
5,284✔
199
        int r;
2,642✔
200

201
        /* If we are run as PID 1 we will lack CAP_SETPCAP by default
202
         * in the effective set (yes, the kernel drops that when
203
         * executing init!), so get it back temporarily so that we can
204
         * call PR_CAPBSET_DROP. */
205

206
        r = capability_gain_cap_setpcap(&before_cap);
2,642✔
207
        if (r < 0)
2,642✔
208
                return r;
209

210
        after_cap = cap_dup(before_cap);
2,642✔
211
        if (!after_cap)
2,642✔
212
                return -errno;
×
213

214
        for (unsigned i = 0; i <= cap_last_cap(); i++) {
110,964✔
215
                cap_value_t v;
108,322✔
216

217
                if ((keep & (UINT64_C(1) << i)))
108,322✔
218
                        continue;
26,146✔
219

220
                /* Drop it from the bounding set */
221
                if (prctl(PR_CAPBSET_DROP, i) < 0) {
82,176✔
222
                        r = -errno;
×
223

224
                        /* If dropping the capability failed, let's see if we didn't have it in the first place. If so,
225
                         * continue anyway, as dropping a capability we didn't have in the first place doesn't really
226
                         * matter anyway. */
227
                        if (prctl(PR_CAPBSET_READ, i) != 0)
×
228
                                goto finish;
×
229
                }
230
                v = (cap_value_t) i;
82,176✔
231

232
                /* Also drop it from the inheritable set, so
233
                 * that anything we exec() loses the
234
                 * capability for good. */
235
                if (cap_set_flag(after_cap, CAP_INHERITABLE, 1, &v, CAP_CLEAR) < 0) {
82,176✔
236
                        r = -errno;
×
237
                        goto finish;
×
238
                }
239

240
                /* If we shall apply this right now drop it
241
                 * also from our own capability sets. */
242
                if (right_now) {
82,176✔
243
                        if (cap_set_flag(after_cap, CAP_PERMITTED, 1, &v, CAP_CLEAR) < 0 ||
16,626✔
244
                            cap_set_flag(after_cap, CAP_EFFECTIVE, 1, &v, CAP_CLEAR) < 0) {
8,313✔
245
                                r = -errno;
×
246
                                goto finish;
×
247
                        }
248
                }
249
        }
250

251
        r = 0;
252

253
finish:
2,642✔
254
        if (cap_set_proc(after_cap) < 0) {
2,642✔
255
                /* If there are no actual changes anyway then let's ignore this error. */
256
                if (cap_compare(before_cap, after_cap) != 0)
×
257
                        r = -errno;
×
258
        }
259

260
        return r;
261
}
262

263
static int drop_from_file(const char *fn, uint64_t keep) {
×
264
        _cleanup_free_ char *p = NULL;
×
265
        uint64_t current, after;
×
266
        uint32_t hi, lo;
×
267
        int r, k;
×
268

269
        r = read_one_line_file(fn, &p);
×
270
        if (r < 0)
×
271
                return r;
272

273
        k = sscanf(p, "%" PRIu32 " %" PRIu32, &lo, &hi);
×
274
        if (k != 2)
×
275
                return -EIO;
276

277
        current = (uint64_t) lo | ((uint64_t) hi << 32);
×
278
        after = current & keep;
×
279

280
        if (current == after)
×
281
                return 0;
282

283
        lo = after & UINT32_MAX;
×
284
        hi = (after >> 32) & UINT32_MAX;
×
285

286
        return write_string_filef(fn, 0, "%" PRIu32 " %" PRIu32, lo, hi);
×
287
}
288

289
int capability_bounding_set_drop_usermode(uint64_t keep) {
×
290
        int r;
×
291

292
        r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", keep);
×
293
        if (r < 0)
×
294
                return r;
295

296
        r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", keep);
×
297
        if (r < 0)
×
298
                return r;
×
299

300
        return r;
301
}
302

303
int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
26✔
304
        int r;
26✔
305

306
        /* Unfortunately we cannot leave privilege dropping to PID 1 here, since we want to run as user but
307
         * want to keep some capabilities. Since file capabilities have been introduced this cannot be done
308
         * across exec() anymore, unless our binary has the capability configured in the file system, which
309
         * we want to avoid. */
310

311
        if (setresgid(gid, gid, gid) < 0)
26✔
312
                return log_error_errno(errno, "Failed to change group ID: %m");
1✔
313

314
        r = maybe_setgroups(0, NULL);
25✔
315
        if (r < 0)
25✔
316
                return log_error_errno(r, "Failed to drop auxiliary groups list: %m");
1✔
317

318
        /* Ensure we keep the permitted caps across the setresuid(). Note that we do this even if we actually
319
         * don't want to keep any capabilities, since we want to be able to drop them from the bounding set
320
         * too, and we can only do that if we have capabilities. */
321
        if (prctl(PR_SET_KEEPCAPS, 1) < 0)
24✔
322
                return log_error_errno(errno, "Failed to enable keep capabilities flag: %m");
×
323

324
        if (setresuid(uid, uid, uid) < 0)
24✔
325
                return log_error_errno(errno, "Failed to change user ID: %m");
×
326

327
        if (prctl(PR_SET_KEEPCAPS, 0) < 0)
24✔
328
                return log_error_errno(errno, "Failed to disable keep capabilities flag: %m");
×
329

330
        /* Drop all caps from the bounding set (as well as the inheritable/permitted/effective sets), except
331
         * the ones we want to keep */
332
        r = capability_bounding_set_drop(keep_capabilities, true);
24✔
333
        if (r < 0)
24✔
334
                return log_error_errno(r, "Failed to drop capabilities: %m");
×
335

336
        /* Now upgrade the permitted caps we still kept to effective caps */
337
        if (keep_capabilities != 0) {
24✔
338
                cap_value_t bits[log2u64(keep_capabilities) + 1];
4✔
339
                _cleanup_cap_free_ cap_t d = NULL;
4✔
340
                unsigned i, j = 0;
4✔
341

342
                d = cap_init();
4✔
343
                if (!d)
4✔
344
                        return log_oom();
×
345

346
                for (i = 0; i < ELEMENTSOF(bits); i++)
28✔
347
                        if (keep_capabilities & (1ULL << i))
24✔
348
                                bits[j++] = i;
6✔
349

350
                /* use enough bits */
351
                assert(i == 64 || (keep_capabilities >> i) == 0);
4✔
352
                /* don't use too many bits */
353
                assert(keep_capabilities & (UINT64_C(1) << (i - 1)));
4✔
354

355
                if (cap_set_flag(d, CAP_EFFECTIVE, j, bits, CAP_SET) < 0 ||
8✔
356
                    cap_set_flag(d, CAP_PERMITTED, j, bits, CAP_SET) < 0)
4✔
357
                        return log_error_errno(errno, "Failed to enable capabilities bits: %m");
×
358

359
                if (cap_set_proc(d) < 0)
4✔
360
                        return log_error_errno(errno, "Failed to increase capabilities: %m");
×
361
        }
362

363
        return 0;
364
}
365

366
static int change_capability(cap_value_t cv, cap_flag_value_t flag) {
3,889✔
367
        _cleanup_cap_free_ cap_t tmp_cap = NULL;
3,889✔
368

369
        tmp_cap = cap_get_proc();
3,889✔
370
        if (!tmp_cap)
3,889✔
371
                return -errno;
×
372

373
        if ((cap_set_flag(tmp_cap, CAP_INHERITABLE, 1, &cv, flag) < 0) ||
7,778✔
374
            (cap_set_flag(tmp_cap, CAP_PERMITTED, 1, &cv, flag) < 0) ||
7,778✔
375
            (cap_set_flag(tmp_cap, CAP_EFFECTIVE, 1, &cv, flag) < 0))
3,889✔
376
                return -errno;
×
377

378
        if (cap_set_proc(tmp_cap) < 0)
3,889✔
379
                return -errno;
×
380

381
        return 0;
382
}
383

384
int drop_capability(cap_value_t cv) {
2,393✔
385
        return change_capability(cv, CAP_CLEAR);
2,393✔
386
}
387

388
int keep_capability(cap_value_t cv) {
1,496✔
389
        return change_capability(cv, CAP_SET);
1,496✔
390
}
391

392
bool capability_quintet_mangle(CapabilityQuintet *q) {
107✔
393
        uint64_t combined, drop = 0;
107✔
394

395
        assert(q);
107✔
396

397
        combined = q->effective | q->bounding | q->inheritable | q->permitted | q->ambient;
107✔
398

399
        for (unsigned i = 0; i <= cap_last_cap(); i++) {
4,494✔
400
                if (!BIT_SET(combined, i))
4,387✔
401
                        continue;
1,563✔
402

403
                if (prctl(PR_CAPBSET_READ, (unsigned long) i) > 0)
2,824✔
404
                        continue;
2,824✔
405

406
                SET_BIT(drop, i);
×
407

408
                log_debug("Dropping capability not in the current bounding set: %s", capability_to_name(i));
×
409
        }
410

411
        q->effective &= ~drop;
107✔
412
        q->bounding &= ~drop;
107✔
413
        q->inheritable &= ~drop;
107✔
414
        q->permitted &= ~drop;
107✔
415
        q->ambient &= ~drop;
107✔
416

417
        return drop != 0; /* Let the caller know we changed something */
107✔
418
}
419

420
int capability_quintet_enforce(const CapabilityQuintet *q) {
107✔
421
        _cleanup_cap_free_ cap_t c = NULL, modified = NULL;
214✔
422
        int r;
107✔
423

424
        if (q->ambient != CAP_MASK_UNSET) {
107✔
425
                bool changed = false;
107✔
426

427
                c = cap_get_proc();
107✔
428
                if (!c)
107✔
429
                        return -errno;
×
430

431
                /* In order to raise the ambient caps set we first need to raise the matching
432
                 * inheritable + permitted cap */
433
                for (unsigned i = 0; i <= cap_last_cap(); i++) {
4,494✔
434
                        uint64_t m = UINT64_C(1) << i;
4,387✔
435
                        cap_value_t cv = (cap_value_t) i;
4,387✔
436
                        cap_flag_value_t old_value_inheritable, old_value_permitted;
4,387✔
437

438
                        if ((q->ambient & m) == 0)
4,387✔
439
                                continue;
4,385✔
440

441
                        if (cap_get_flag(c, cv, CAP_INHERITABLE, &old_value_inheritable) < 0)
2✔
442
                                return -errno;
×
443
                        if (cap_get_flag(c, cv, CAP_PERMITTED, &old_value_permitted) < 0)
2✔
444
                                return -errno;
×
445

446
                        if (old_value_inheritable == CAP_SET && old_value_permitted == CAP_SET)
2✔
447
                                continue;
×
448

449
                        if (cap_set_flag(c, CAP_INHERITABLE, 1, &cv, CAP_SET) < 0)
2✔
450
                                return -errno;
×
451
                        if (cap_set_flag(c, CAP_PERMITTED, 1, &cv, CAP_SET) < 0)
2✔
452
                                return -errno;
×
453

454
                        changed = true;
2✔
455
                }
456

457
                if (changed)
107✔
458
                        if (cap_set_proc(c) < 0)
1✔
459
                                return -errno;
×
460

461
                r = capability_ambient_set_apply(q->ambient, false);
107✔
462
                if (r < 0)
107✔
463
                        return r;
464
        }
465

466
        if (q->inheritable != CAP_MASK_UNSET || q->permitted != CAP_MASK_UNSET || q->effective != CAP_MASK_UNSET) {
107✔
467
                bool changed = false;
106✔
468

469
                if (!c) {
106✔
470
                        c = cap_get_proc();
×
471
                        if (!c)
×
472
                                return -errno;
×
473
                }
474

475
                for (unsigned i = 0; i <= cap_last_cap(); i++) {
4,452✔
476
                        uint64_t m = UINT64_C(1) << i;
4,346✔
477
                        cap_value_t cv = (cap_value_t) i;
4,346✔
478

479
                        if (q->inheritable != CAP_MASK_UNSET) {
4,346✔
480
                                cap_flag_value_t old_value, new_value;
4,346✔
481

482
                                if (cap_get_flag(c, cv, CAP_INHERITABLE, &old_value) < 0) {
4,346✔
483
                                        if (errno == EINVAL) /* If the kernel knows more caps than this
×
484
                                                              * version of libcap, then this will return
485
                                                              * EINVAL. In that case, simply ignore it,
486
                                                              * pretend it doesn't exist. */
487
                                                continue;
×
488

489
                                        return -errno;
×
490
                                }
491

492
                                new_value = (q->inheritable & m) ? CAP_SET : CAP_CLEAR;
4,346✔
493

494
                                if (old_value != new_value) {
4,346✔
495
                                        changed = true;
2,704✔
496

497
                                        if (cap_set_flag(c, CAP_INHERITABLE, 1, &cv, new_value) < 0)
2,704✔
498
                                                return -errno;
×
499
                                }
500
                        }
501

502
                        if (q->permitted != CAP_MASK_UNSET) {
4,346✔
503
                                cap_flag_value_t old_value, new_value;
4,346✔
504

505
                                if (cap_get_flag(c, cv, CAP_PERMITTED, &old_value) < 0) {
4,346✔
506
                                        if (errno == EINVAL)
×
507
                                                continue;
×
508

509
                                        return -errno;
×
510
                                }
511

512
                                new_value = (q->permitted & m) ? CAP_SET : CAP_CLEAR;
4,346✔
513

514
                                if (old_value != new_value) {
4,346✔
515
                                        changed = true;
1,640✔
516

517
                                        if (cap_set_flag(c, CAP_PERMITTED, 1, &cv, new_value) < 0)
1,640✔
518
                                                return -errno;
×
519
                                }
520
                        }
521

522
                        if (q->effective != CAP_MASK_UNSET) {
4,346✔
523
                                cap_flag_value_t old_value, new_value;
4,346✔
524

525
                                if (cap_get_flag(c, cv, CAP_EFFECTIVE, &old_value) < 0) {
4,346✔
526
                                        if (errno == EINVAL)
×
527
                                                continue;
×
528

529
                                        return -errno;
×
530
                                }
531

532
                                new_value = (q->effective & m) ? CAP_SET : CAP_CLEAR;
4,346✔
533

534
                                if (old_value != new_value) {
4,346✔
535
                                        changed = true;
1,517✔
536

537
                                        if (cap_set_flag(c, CAP_EFFECTIVE, 1, &cv, new_value) < 0)
1,517✔
538
                                                return -errno;
×
539
                                }
540
                        }
541
                }
542

543
                if (changed) {
106✔
544
                        /* In order to change the bounding caps, we need to keep CAP_SETPCAP for a bit
545
                         * longer. Let's add it to our list hence for now. */
546
                        if (q->bounding != CAP_MASK_UNSET) {
106✔
547
                                cap_value_t cv = CAP_SETPCAP;
106✔
548

549
                                modified = cap_dup(c);
106✔
550
                                if (!modified)
106✔
551
                                        return -ENOMEM;
×
552

553
                                if (cap_set_flag(modified, CAP_PERMITTED, 1, &cv, CAP_SET) < 0)
106✔
554
                                        return -errno;
×
555
                                if (cap_set_flag(modified, CAP_EFFECTIVE, 1, &cv, CAP_SET) < 0)
106✔
556
                                        return -errno;
×
557

558
                                if (cap_compare(modified, c) == 0) {
106✔
559
                                        /* No change? then drop this nonsense again */
560
                                        cap_free(modified);
103✔
561
                                        modified = NULL;
562
                                }
563
                        }
564

565
                        /* Now, let's enforce the caps for the first time. Note that this is where we acquire
566
                         * caps in any of the sets we currently don't have. We have to do this before
567
                         * dropping the bounding caps below, since at that point we can never acquire new
568
                         * caps in inherited/permitted/effective anymore, but only lose them. */
569
                        if (cap_set_proc(modified ?: c) < 0)
106✔
570
                                return -errno;
×
571
                }
572
        }
573

574
        if (q->bounding != CAP_MASK_UNSET) {
107✔
575
                r = capability_bounding_set_drop(q->bounding, false);
106✔
576
                if (r < 0)
106✔
577
                        return r;
578
        }
579

580
        /* If needed, let's now set the caps again, this time in the final version, which differs from what
581
         * we have already set only in the CAP_SETPCAP bit, which we needed for dropping the bounding
582
         * bits. This call only undoes bits and doesn't acquire any which means the bounding caps don't
583
         * matter. */
584
        if (modified)
107✔
585
                if (cap_set_proc(c) < 0)
3✔
586
                        return -errno;
×
587

588
        return 0;
589
}
590

591
int capability_get_ambient(uint64_t *ret) {
641✔
592
        uint64_t a = 0;
641✔
593
        int r;
641✔
594

595
        assert(ret);
641✔
596

597
        for (unsigned i = 0; i <= cap_last_cap(); i++) {
26,922✔
598
                r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, i, 0, 0);
26,281✔
599
                if (r < 0)
26,281✔
600
                        return -errno;
×
601
                if (r > 0)
26,281✔
602
                        SET_BIT(a, i);
103✔
603
        }
604

605
        *ret = a;
641✔
606
        return 1;
641✔
607
}
608

609
int pidref_get_capability(const PidRef *pidref, CapabilityQuintet *ret) {
16,688✔
610
        int r;
16,688✔
611

612
        if (!pidref_is_set(pidref))
16,688✔
613
                return -ESRCH;
16,688✔
614
        if (pidref_is_remote(pidref))
16,688✔
615
                return -EREMOTE;
616

617
        const char *path = procfs_file_alloca(pidref->pid, "status");
16,688✔
618
        _cleanup_fclose_ FILE *f = fopen(path, "re");
33,376✔
619
        if (!f) {
16,688✔
620
                if (errno == ENOENT && proc_mounted() == 0)
4,307✔
621
                        return -ENOSYS;
622

623
                return -errno;
4,307✔
624
        }
625

626
        CapabilityQuintet q = CAPABILITY_QUINTET_NULL;
12,381✔
627
        for (;;) {
1,507,751✔
628
                _cleanup_free_ char *line = NULL;
747,685✔
629

630
                r = read_line(f, LONG_LINE_MAX, &line);
760,066✔
631
                if (r < 0)
760,066✔
632
                        return r;
633
                if (r == 0)
760,066✔
634
                        break;
635

636
                static const struct {
637
                        const char *field;
638
                        size_t offset;
639
                } fields[] = {
640
                        { "CapBnd:", offsetof(CapabilityQuintet, bounding)    },
641
                        { "CapInh:", offsetof(CapabilityQuintet, inheritable) },
642
                        { "CapPrm:", offsetof(CapabilityQuintet, permitted)   },
643
                        { "CapEff:", offsetof(CapabilityQuintet, effective)   },
644
                        { "CapAmb:", offsetof(CapabilityQuintet, ambient)     },
645
                };
646

647
                FOREACH_ELEMENT(i, fields) {
4,486,110✔
648

649
                        const char *p = first_word(line, i->field);
3,738,425✔
650
                        if (!p)
3,738,425✔
651
                                continue;
3,676,520✔
652

653
                        uint64_t *v = (uint64_t*) ((uint8_t*) &q + i->offset);
61,905✔
654

655
                        if (*v != CAP_MASK_UNSET)
61,905✔
656
                                return -EBADMSG;
657

658
                        r = safe_atoux64(p, v);
61,905✔
659
                        if (r < 0)
61,905✔
660
                                return r;
661

662
                        if (*v == CAP_MASK_UNSET)
61,905✔
663
                                return -EBADMSG;
664
                }
665
        }
666

667
        if (!capability_quintet_is_fully_set(&q))
12,381✔
668
                return -EBADMSG;
669

670
        r = pidref_verify(pidref);
12,381✔
671
        if (r < 0)
12,381✔
672
                return r;
673

674
        if (ret)
12,381✔
675
                *ret = q;
12,381✔
676

677
        return 0;
678
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc