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

systemd / systemd / 18795135167

24 Oct 2025 08:21PM UTC coverage: 72.26% (-0.02%) from 72.284%
18795135167

push

github

poettering
rules: apply loopback block device rule only onto loopback block devices

Fixes: #39426
Follow-up for: 9422ce83c

304809 of 421823 relevant lines covered (72.26%)

1112914.25 hits per line

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

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

3
#include <linux/prctl.h>
4
#include <netinet/in.h>
5
#include <pwd.h>
6
#include <stdlib.h>
7
#include <sys/prctl.h>
8
#include <sys/socket.h>
9
#include <sys/wait.h>
10
#include <unistd.h>
11
#include "pidref.h"
12

13
#define TEST_CAPABILITY_C
14

15
#include "alloc-util.h"
16
#include "capability-list.h"
17
#include "capability-util.h"
18
#include "errno-util.h"
19
#include "fd-util.h"
20
#include "fileio.h"
21
#include "parse-util.h"
22
#include "process-util.h"
23
#include "tests.h"
24

25
static uid_t test_uid = -1;
26
static gid_t test_gid = -1;
27

28
#if HAS_FEATURE_ADDRESS_SANITIZER
29
/* Keep CAP_SYS_PTRACE when running under Address Sanitizer */
30
static const uint64_t test_flags = UINT64_C(1) << CAP_SYS_PTRACE;
31
#else
32
/* We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage */
33
static const uint64_t test_flags = UINT64_C(1) << CAP_DAC_OVERRIDE;
34
#endif
35

36
/* verify cap_last_cap() against /proc/sys/kernel/cap_last_cap */
37
static void test_last_cap_file(void) {
1✔
38
        _cleanup_free_ char *content = NULL;
1✔
39
        unsigned long val = 0;
1✔
40
        int r;
1✔
41

42
        r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content);
1✔
43
        if (ERRNO_IS_NEG_PRIVILEGE(r))
1✔
44
                return (void) log_tests_skipped_errno(r, "Failed to /proc/sys/kernel/cap_last_cap");
×
45
        ASSERT_OK(r);
1✔
46

47
        r = safe_atolu(content, &val);
1✔
48
        ASSERT_OK(r);
1✔
49
        assert_se(val != 0);
1✔
50
        ASSERT_EQ(val, cap_last_cap());
1✔
51
}
52

53
/* verify cap_last_cap() against syscall probing */
54
static void test_last_cap_probe(void) {
1✔
55
        unsigned long p = (unsigned long)CAP_LAST_CAP;
1✔
56

57
        if (prctl(PR_CAPBSET_READ, p) < 0) {
1✔
58
                for (p--; p > 0; p--)
×
59
                        if (prctl(PR_CAPBSET_READ, p) >= 0)
×
60
                                break;
61
        } else {
62
                for (;; p++)
1✔
63
                        if (prctl(PR_CAPBSET_READ, p+1) < 0)
1✔
64
                                break;
65
        }
66

67
        assert_se(p != 0);
1✔
68
        ASSERT_EQ(p, cap_last_cap());
1✔
69
}
1✔
70

71
static void fork_test(void (*test_func)(void)) {
5✔
72
        pid_t pid = 0;
5✔
73

74
        pid = fork();
5✔
75
        assert_se(pid >= 0);
10✔
76
        if (pid == 0) {
10✔
77
                test_func();
5✔
78
                exit(EXIT_SUCCESS);
5✔
79
        } else if (pid > 0) {
5✔
80
                int status;
5✔
81

82
                assert_se(waitpid(pid, &status, 0) > 0);
5✔
83
                assert_se(WIFEXITED(status) && WEXITSTATUS(status) == 0);
5✔
84
        }
85
}
5✔
86

87
static void show_capabilities(void) {
3✔
88
        _cleanup_free_ char *e = NULL, *p = NULL, *i = NULL;
×
89
        CapabilityQuintet q;
3✔
90

91
        ASSERT_OK(capability_get(&q));
3✔
92
        ASSERT_OK(capability_set_to_string(q.effective, &e));
3✔
93
        ASSERT_OK(capability_set_to_string(q.permitted, &p));
3✔
94
        ASSERT_OK(capability_set_to_string(q.inheritable, &i));
3✔
95

96
        log_info("Capabilities:e=%s p=%s, i=%s", e, p, i);
3✔
97
}
3✔
98

99
static int setup_tests(bool *run_ambient) {
1✔
100
        struct passwd *nobody;
1✔
101
        int r;
1✔
102

103
        nobody = getpwnam(NOBODY_USER_NAME);
1✔
104
        if (!nobody)
1✔
105
                return log_warning_errno(SYNTHETIC_ERRNO(ENOENT), "Couldn't find 'nobody' user.");
×
106

107
        test_uid = nobody->pw_uid;
1✔
108
        test_gid = nobody->pw_gid;
1✔
109

110
        r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
1✔
111
        /* There's support for PR_CAP_AMBIENT if the prctl() call succeeded or error code was something else
112
         * than EINVAL. The EINVAL check should be good enough to rule out false positives. */
113
        *run_ambient = r >= 0 || errno != EINVAL;
1✔
114

115
        return 0;
1✔
116
}
117

118
static void test_drop_privileges_keep_net_raw(void) {
1✔
119
        int sock;
1✔
120

121
        sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
1✔
122
        assert_se(sock >= 0);
1✔
123
        safe_close(sock);
1✔
124

125
        assert_se(drop_privileges(test_uid, test_gid, test_flags | (1ULL << CAP_NET_RAW)) >= 0);
1✔
126
        assert_se(getuid() == test_uid);
1✔
127
        assert_se(getgid() == test_gid);
1✔
128
        show_capabilities();
1✔
129

130
        sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
1✔
131
        ASSERT_OK(sock);
1✔
132
        safe_close(sock);
1✔
133
}
1✔
134

135
static void test_drop_privileges_dontkeep_net_raw(void) {
1✔
136
        int sock;
1✔
137

138
        sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
1✔
139
        ASSERT_OK(sock);
1✔
140
        safe_close(sock);
1✔
141

142
        assert_se(drop_privileges(test_uid, test_gid, test_flags) >= 0);
1✔
143
        assert_se(getuid() == test_uid);
1✔
144
        assert_se(getgid() == test_gid);
1✔
145
        show_capabilities();
1✔
146

147
        sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
1✔
148
        ASSERT_LT(sock, 0);
1✔
149
}
1✔
150

151
static void test_drop_privileges_fail(void) {
1✔
152
        assert_se(drop_privileges(test_uid, test_gid, test_flags) >= 0);
1✔
153
        assert_se(getuid() == test_uid);
1✔
154
        assert_se(getgid() == test_gid);
1✔
155

156
        ASSERT_LT(drop_privileges(test_uid, test_gid, test_flags), 0);
1✔
157
        ASSERT_LT(drop_privileges(0, 0, test_flags), 0);
1✔
158
}
1✔
159

160
static void test_drop_privileges(void) {
1✔
161
        fork_test(test_drop_privileges_fail);
1✔
162

163
        if (have_effective_cap(CAP_NET_RAW) <= 0) /* The remaining two tests only work if we have CAP_NET_RAW
1✔
164
                                                   * in the first place. If we are run in some restricted
165
                                                   * container environment we might not. */
166
                return;
167

168
        fork_test(test_drop_privileges_keep_net_raw);
1✔
169
        fork_test(test_drop_privileges_dontkeep_net_raw);
1✔
170
}
171

172
static void test_have_effective_cap(void) {
1✔
173
        ASSERT_GT(have_effective_cap(CAP_KILL), 0);
1✔
174
        ASSERT_GT(have_effective_cap(CAP_CHOWN), 0);
1✔
175

176
        ASSERT_OK(drop_privileges(test_uid, test_gid, test_flags | (1ULL << CAP_KILL)));
1✔
177
        assert_se(getuid() == test_uid);
1✔
178
        assert_se(getgid() == test_gid);
1✔
179

180
        ASSERT_GT(have_effective_cap(CAP_KILL), 0);
1✔
181
        assert_se(have_effective_cap(CAP_CHOWN) == 0);
1✔
182
}
1✔
183

184
static void test_apply_ambient_caps(void) {
1✔
185
        ASSERT_OK_EQ_ERRNO(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0), 0);
1✔
186

187
        ASSERT_OK(capability_ambient_set_apply(UINT64_C(1) << CAP_CHOWN, true));
1✔
188
        ASSERT_OK_POSITIVE(have_inheritable_cap(CAP_CHOWN));
1✔
189

190
        ASSERT_OK_EQ_ERRNO(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0), 1);
1✔
191

192
        ASSERT_OK(capability_ambient_set_apply(0, true));
1✔
193
        ASSERT_OK_ZERO(have_inheritable_cap(CAP_CHOWN));
1✔
194

195
        ASSERT_OK_EQ_ERRNO(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0), 0);
1✔
196
}
1✔
197

198
static void test_ensure_cap_64_bit(void) {
1✔
199
        _cleanup_free_ char *content = NULL;
1✔
200
        unsigned long p = 0;
1✔
201
        int r;
1✔
202

203
        r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content);
1✔
204
        if (ERRNO_IS_NEG_PRIVILEGE(r))
1✔
205
                return (void) log_tests_skipped_errno(r, "Failed to /proc/sys/kernel/cap_last_cap");
×
206
        ASSERT_OK(r);
1✔
207

208
        ASSERT_OK(safe_atolu(content, &p));
1✔
209

210
        /* If caps don't fit into 64-bit anymore, we have a problem, fail the test. Moreover, we use
211
         * UINT64_MAX as unset, hence it must be smaller than or equals to 62 (CAP_LIMIT). */
212
        assert_se(p <= CAP_LIMIT);
1✔
213
}
214

215
static void test_capability_get_ambient(void) {
1✔
216
        uint64_t c;
1✔
217
        int r;
1✔
218

219
        ASSERT_OK(capability_get_ambient(&c));
1✔
220

221
        r = prctl(PR_CAPBSET_READ, CAP_MKNOD);
1✔
222
        if (r <= 0)
1✔
223
                return (void) log_tests_skipped("Lacking CAP_MKNOD, skipping getambient test.");
×
224
        r = prctl(PR_CAPBSET_READ, CAP_LINUX_IMMUTABLE);
1✔
225
        if (r <= 0)
1✔
226
                return (void) log_tests_skipped("Lacking CAP_LINUX_IMMUTABLE, skipping getambient test.");
×
227

228
        r = safe_fork("(getambient)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG, NULL);
1✔
229
        ASSERT_OK(r);
2✔
230

231
        if (r == 0) {
2✔
232
                int x, y;
1✔
233
                /* child */
234
                assert_se(capability_get_ambient(&c) >= 0);
1✔
235

236
                x = capability_ambient_set_apply(
1✔
237
                                (UINT64_C(1) << CAP_MKNOD)|
238
                                (UINT64_C(1) << CAP_LINUX_IMMUTABLE),
239
                                /* also_inherit= */ true);
240
                assert_se(x >= 0 || ERRNO_IS_PRIVILEGE(x));
1✔
241

242
                assert_se(capability_get_ambient(&c) >= 0);
1✔
243
                assert_se(x < 0 || FLAGS_SET(c, UINT64_C(1) << CAP_MKNOD));
1✔
244
                assert_se(x < 0 || FLAGS_SET(c, UINT64_C(1) << CAP_LINUX_IMMUTABLE));
1✔
245
                assert_se(x < 0 || !FLAGS_SET(c, UINT64_C(1) << CAP_SETPCAP));
1✔
246

247
                y = capability_bounding_set_drop(
1✔
248
                                ((UINT64_C(1) << CAP_LINUX_IMMUTABLE)|
249
                                 (UINT64_C(1) << CAP_SETPCAP)),
250
                                /* right_now= */ true);
251
                assert_se(y >= 0 || ERRNO_IS_PRIVILEGE(y));
1✔
252

253
                assert_se(capability_get_ambient(&c) >= 0);
1✔
254
                assert_se(x < 0 || y < 0 || !FLAGS_SET(c, UINT64_C(1) << CAP_MKNOD));
1✔
255
                assert_se(x < 0 || y < 0 || FLAGS_SET(c, UINT64_C(1) << CAP_LINUX_IMMUTABLE));
1✔
256
                assert_se(x < 0 || y < 0 || !FLAGS_SET(c, UINT64_C(1) << CAP_SETPCAP));
1✔
257

258
                y = capability_bounding_set_drop(
1✔
259
                                (UINT64_C(1) << CAP_SETPCAP),
260
                                /* right_now= */ true);
261
                assert_se(y >= 0 || ERRNO_IS_PRIVILEGE(y));
1✔
262

263
                assert_se(capability_get_ambient(&c) >= 0);
1✔
264
                assert_se(x < 0 || y < 0 || !FLAGS_SET(c, UINT64_C(1) << CAP_MKNOD));
1✔
265
                assert_se(x < 0 || y < 0 || !FLAGS_SET(c, UINT64_C(1) << CAP_LINUX_IMMUTABLE));
1✔
266
                assert_se(x < 0 || y < 0 || !FLAGS_SET(c, UINT64_C(1) << CAP_SETPCAP));
1✔
267

268
                _exit(EXIT_SUCCESS);
1✔
269
        }
270
}
271

272
static void test_pidref_get_capability(void) {
1✔
273
        CapabilityQuintet q = CAPABILITY_QUINTET_NULL;
1✔
274

275
        assert_se(pidref_get_capability(&PIDREF_MAKE_FROM_PID(getpid_cached()), &q) >= 0);
1✔
276

277
        assert_se(q.effective != CAP_MASK_UNSET);
1✔
278
        assert_se(q.inheritable != CAP_MASK_UNSET);
1✔
279
        assert_se(q.permitted != CAP_MASK_UNSET);
1✔
280
        assert_se(q.effective != CAP_MASK_UNSET);
1✔
281
        assert_se(q.ambient != CAP_MASK_UNSET);
1✔
282
}
1✔
283

284
int main(int argc, char *argv[]) {
1✔
285
        bool run_ambient;
1✔
286

287
        test_setup_logging(LOG_DEBUG);
1✔
288

289
        test_ensure_cap_64_bit();
1✔
290

291
        test_last_cap_file();
1✔
292
        test_last_cap_probe();
1✔
293

294
        if (getuid() != 0)
1✔
295
                return log_tests_skipped("not running as root");
×
296

297
        if (setup_tests(&run_ambient) < 0)
1✔
298
                return log_tests_skipped("setup failed");
×
299

300
        show_capabilities();
1✔
301

302
        if (!userns_has_single_user())
1✔
303
                test_drop_privileges();
1✔
304

305
        if (!userns_has_single_user())
1✔
306
                fork_test(test_have_effective_cap);
1✔
307

308
        if (run_ambient)
1✔
309
                fork_test(test_apply_ambient_caps);
1✔
310

311
        test_capability_get_ambient();
1✔
312

313
        test_pidref_get_capability();
1✔
314

315
        return 0;
316
}
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