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

systemd / systemd / 25351067578

04 May 2026 06:45PM UTC coverage: 72.674% (+0.7%) from 71.943%
25351067578

push

github

keszybz
test: suppress PCR public key auto-loading in TEST-70-TPM2 dditest

The dditest block calls systemd-repart with Encrypt=tpm2 but without
--tpm2-public-key-pcrs=. Since systemd-stub drops
/run/systemd/tpm2-pcr-public-key.pem when booting from a signed UKI
systemd-repart auto-loads it and enrolls a signed PCR policy, and
then systemd-cryptsetup tpm2-device=auto has no matching signature file,
so unlock fails.

--tpm2-public-key= is not enough as the default kicks in then.

Follow-up for cd18656d4

325892 of 448432 relevant lines covered (72.67%)

1195556.07 hits per line

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

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

3
#include "alloc-util.h"
4
#include "errno-util.h"
5
#include "extract-word.h"
6
#include "fd-util.h"
7
#include "fileio.h"
8
#include "format-util.h"
9
#include "log.h"
10
#include "parse-util.h"
11
#include "process-util.h"
12
#include "rlimit-util.h"
13
#include "string-table.h"
14
#include "strv.h"
15
#include "time-util.h"
16

17
int setrlimit_closest(int resource, const struct rlimit *rlim) {
45,186✔
18
        struct rlimit highest, fixed;
45,186✔
19

20
        assert(rlim);
45,186✔
21

22
        if (setrlimit(resource, rlim) >= 0)
45,186✔
23
                return 0;
45,186✔
24

25
        if (errno != EPERM)
249✔
26
                return -errno;
1✔
27

28
        /* So we failed to set the desired setrlimit, then let's try
29
         * to get as close as we can */
30
        if (getrlimit(resource, &highest) < 0)
248✔
31
                return -errno;
×
32

33
        /* If the hard limit is unbounded anyway, then the EPERM had other reasons, let's propagate the original EPERM
34
         * then */
35
        if (highest.rlim_max == RLIM_INFINITY)
248✔
36
                return -EPERM;
37

38
        fixed = (struct rlimit) {
248✔
39
                .rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max),
248✔
40
                .rlim_max = MIN(rlim->rlim_max, highest.rlim_max),
248✔
41
        };
42

43
        /* Shortcut things if we wouldn't change anything. */
44
        if (fixed.rlim_cur == highest.rlim_cur &&
248✔
45
            fixed.rlim_max == highest.rlim_max)
46
                return 0;
47

48
        log_debug("Failed at setting rlimit " RLIM_FMT " for resource RLIMIT_%s. Will attempt setting value " RLIM_FMT " instead.", rlim->rlim_max, rlimit_to_string(resource), fixed.rlim_max);
125✔
49

50
        return RET_NERRNO(setrlimit(resource, &fixed));
125✔
51
}
52

53
int setrlimit_closest_all(const struct rlimit *const *rlim, int *which_failed) {
10,640✔
54
        int r;
10,640✔
55

56
        assert(rlim);
10,640✔
57

58
        /* On failure returns the limit's index that failed in *which_failed, but only if non-NULL */
59

60
        for (int i = 0; i < _RLIMIT_MAX; i++) {
180,880✔
61
                if (!rlim[i])
170,240✔
62
                        continue;
147,271✔
63

64
                r = setrlimit_closest(i, rlim[i]);
22,969✔
65
                if (r < 0) {
22,969✔
66
                        if (which_failed)
×
67
                                *which_failed = i;
×
68

69
                        return r;
70
                }
71
        }
72

73
        if (which_failed)
10,640✔
74
                *which_failed = -1;
10,640✔
75

76
        return 0;
77
}
78

79
static int rlimit_parse_u64(const char *val, rlim_t *ret) {
21,691✔
80
        uint64_t u;
21,691✔
81
        int r;
21,691✔
82

83
        assert(val);
21,691✔
84
        assert(ret);
21,691✔
85

86
        if (streq(val, "infinity")) {
21,691✔
87
                *ret = RLIM_INFINITY;
12✔
88
                return 0;
12✔
89
        }
90

91
        /* setrlimit(2) suggests rlim_t is always 64-bit on Linux. */
92
        assert_cc(sizeof(rlim_t) == sizeof(uint64_t));
21,679✔
93

94
        r = safe_atou64(val, &u);
21,679✔
95
        if (r < 0)
21,679✔
96
                return r;
97
        if (u >= (uint64_t) RLIM_INFINITY)
21,676✔
98
                return -ERANGE;
99

100
        *ret = (rlim_t) u;
21,676✔
101
        return 0;
21,676✔
102
}
103

104
static int rlimit_parse_size(const char *val, rlim_t *ret) {
10,582✔
105
        uint64_t u;
10,582✔
106
        int r;
10,582✔
107

108
        assert(val);
10,582✔
109
        assert(ret);
10,582✔
110

111
        if (streq(val, "infinity")) {
10,582✔
112
                *ret = RLIM_INFINITY;
7✔
113
                return 0;
7✔
114
        }
115

116
        r = parse_size(val, 1024, &u);
10,575✔
117
        if (r < 0)
10,575✔
118
                return r;
119
        if (u >= (uint64_t) RLIM_INFINITY)
10,575✔
120
                return -ERANGE;
121

122
        *ret = (rlim_t) u;
10,575✔
123
        return 0;
10,575✔
124
}
125

126
static int rlimit_parse_sec(const char *val, rlim_t *ret) {
19✔
127
        uint64_t u;
19✔
128
        usec_t t;
19✔
129
        int r;
19✔
130

131
        assert(val);
19✔
132
        assert(ret);
19✔
133

134
        r = parse_sec(val, &t);
19✔
135
        if (r < 0)
19✔
136
                return r;
19✔
137
        if (t == USEC_INFINITY) {
19✔
138
                *ret = RLIM_INFINITY;
2✔
139
                return 0;
2✔
140
        }
141

142
        u = (uint64_t) DIV_ROUND_UP(t, USEC_PER_SEC);
17✔
143
        if (u >= (uint64_t) RLIM_INFINITY)
17✔
144
                return -ERANGE;
145

146
        *ret = (rlim_t) u;
17✔
147
        return 0;
17✔
148
}
149

150
static int rlimit_parse_usec(const char *val, rlim_t *ret) {
19✔
151
        usec_t t;
19✔
152
        int r;
19✔
153

154
        assert(val);
19✔
155
        assert(ret);
19✔
156

157
        r = parse_time(val, &t, 1);
19✔
158
        if (r < 0)
19✔
159
                return r;
19✔
160
        if (t == USEC_INFINITY) {
19✔
161
                *ret = RLIM_INFINITY;
5✔
162
                return 0;
5✔
163
        }
164

165
        *ret = (rlim_t) t;
14✔
166
        return 0;
14✔
167
}
168

169
static int rlimit_parse_nice(const char *val, rlim_t *ret) {
26✔
170
        uint64_t rl;
26✔
171
        int r;
26✔
172

173
        assert(val);
26✔
174
        assert(ret);
26✔
175

176
        /* So, Linux is weird. The range for RLIMIT_NICE is 40..1, mapping to the nice levels -20..19. However, the
177
         * RLIMIT_NICE limit defaults to 0 by the kernel, i.e. a value that maps to nice level 20, which of course is
178
         * bogus and does not exist. In order to permit parsing the RLIMIT_NICE of 0 here we hence implement a slight
179
         * asymmetry: when parsing as positive nice level we permit 0..19. When parsing as negative nice level, we
180
         * permit -20..0. But when parsing as raw resource limit value then we also allow the special value 0.
181
         *
182
         * Yeah, Linux is quality engineering sometimes... */
183

184
        if (val[0] == '+') {
26✔
185

186
                /* Prefixed with "+": Parse as positive user-friendly nice value */
187
                r = safe_atou64(val + 1, &rl);
5✔
188
                if (r < 0)
5✔
189
                        return r;
26✔
190

191
                if (rl >= PRIO_MAX)
5✔
192
                        return -ERANGE;
193

194
                rl = 20 - rl;
4✔
195

196
        } else if (val[0] == '-') {
21✔
197

198
                /* Prefixed with "-": Parse as negative user-friendly nice value */
199
                r = safe_atou64(val + 1, &rl);
4✔
200
                if (r < 0)
4✔
201
                        return r;
202

203
                if (rl > (uint64_t) (-PRIO_MIN))
4✔
204
                        return -ERANGE;
205

206
                rl = 20 + rl;
3✔
207
        } else {
208

209
                /* Not prefixed: parse as raw resource limit value */
210
                r = safe_atou64(val, &rl);
17✔
211
                if (r < 0)
17✔
212
                        return r;
213

214
                if (rl > (uint64_t) (20 - PRIO_MIN))
17✔
215
                        return -ERANGE;
216
        }
217

218
        *ret = (rlim_t) rl;
23✔
219
        return 0;
23✔
220
}
221

222
static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret) = {
223
        [RLIMIT_CPU]        = rlimit_parse_sec,
224
        [RLIMIT_FSIZE]      = rlimit_parse_size,
225
        [RLIMIT_DATA]       = rlimit_parse_size,
226
        [RLIMIT_STACK]      = rlimit_parse_size,
227
        [RLIMIT_CORE]       = rlimit_parse_size,
228
        [RLIMIT_RSS]        = rlimit_parse_size,
229
        [RLIMIT_NOFILE]     = rlimit_parse_u64,
230
        [RLIMIT_AS]         = rlimit_parse_size,
231
        [RLIMIT_NPROC]      = rlimit_parse_u64,
232
        [RLIMIT_MEMLOCK]    = rlimit_parse_size,
233
        [RLIMIT_LOCKS]      = rlimit_parse_u64,
234
        [RLIMIT_SIGPENDING] = rlimit_parse_u64,
235
        [RLIMIT_MSGQUEUE]   = rlimit_parse_size,
236
        [RLIMIT_NICE]       = rlimit_parse_nice,
237
        [RLIMIT_RTPRIO]     = rlimit_parse_u64,
238
        [RLIMIT_RTTIME]     = rlimit_parse_usec,
239
};
240

241
int rlimit_parse_one(int resource, const char *val, rlim_t *ret) {
32,337✔
242
        assert(val);
32,337✔
243
        assert(ret);
32,337✔
244

245
        if (resource < 0)
32,337✔
246
                return -EINVAL;
247
        if (resource >= _RLIMIT_MAX)
32,337✔
248
                return -EINVAL;
249

250
        return rlimit_parse_table[resource](val, ret);
32,337✔
251
}
252

253
int rlimit_parse(int resource, const char *val, struct rlimit *ret) {
22,506✔
254
        _cleanup_free_ char *hard = NULL, *soft = NULL;
22,506✔
255
        rlim_t hl, sl;
22,506✔
256
        int r;
22,506✔
257

258
        assert(val);
22,506✔
259
        assert(ret);
22,506✔
260

261
        r = extract_first_word(&val, &soft, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
22,506✔
262
        if (r < 0)
22,506✔
263
                return r;
264
        if (r == 0)
22,506✔
265
                return -EINVAL;
266

267
        r = rlimit_parse_one(resource, soft, &sl);
22,506✔
268
        if (r < 0)
22,506✔
269
                return r;
270

271
        r = extract_first_word(&val, &hard, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
22,501✔
272
        if (r < 0)
22,501✔
273
                return r;
274
        if (!isempty(val))
45,007✔
275
                return -EINVAL;
276
        if (r == 0)
22,499✔
277
                hl = sl;
12,668✔
278
        else {
279
                r = rlimit_parse_one(resource, hard, &hl);
9,831✔
280
                if (r < 0)
9,831✔
281
                        return r;
282
                if (sl > hl)
9,830✔
283
                        return -EILSEQ;
284
        }
285

286
        *ret = (struct rlimit) {
22,496✔
287
                .rlim_cur = sl,
288
                .rlim_max = hl,
289
        };
290

291
        return 0;
22,496✔
292
}
293

294
int rlimit_format(const struct rlimit *rl, char **ret) {
14,386✔
295
        char *s;
14,386✔
296

297
        assert(rl);
14,386✔
298
        assert(ret);
14,386✔
299

300
        if (rl->rlim_cur >= RLIM_INFINITY && rl->rlim_max >= RLIM_INFINITY)
14,386✔
301
                s = strdup("infinity");
3,798✔
302
        else if (rl->rlim_cur >= RLIM_INFINITY)
10,588✔
303
                s = asprintf_safe("infinity:" RLIM_FMT, rl->rlim_max);
1✔
304
        else if (rl->rlim_max >= RLIM_INFINITY)
10,587✔
305
                s = asprintf_safe(RLIM_FMT ":infinity", rl->rlim_cur);
1,088✔
306
        else if (rl->rlim_cur == rl->rlim_max)
9,499✔
307
                s = asprintf_safe(RLIM_FMT, rl->rlim_cur);
6,292✔
308
        else
309
                s = asprintf_safe(RLIM_FMT ":" RLIM_FMT, rl->rlim_cur, rl->rlim_max);
3,207✔
310
        if (!s)
14,386✔
311
                return -ENOMEM;
312

313
        *ret = s;
14,386✔
314
        return 0;
14,386✔
315
}
316

317
static const char* const rlimit_table[_RLIMIT_MAX] = {
318
        [RLIMIT_AS]         = "AS",
319
        [RLIMIT_CORE]       = "CORE",
320
        [RLIMIT_CPU]        = "CPU",
321
        [RLIMIT_DATA]       = "DATA",
322
        [RLIMIT_FSIZE]      = "FSIZE",
323
        [RLIMIT_LOCKS]      = "LOCKS",
324
        [RLIMIT_MEMLOCK]    = "MEMLOCK",
325
        [RLIMIT_MSGQUEUE]   = "MSGQUEUE",
326
        [RLIMIT_NICE]       = "NICE",
327
        [RLIMIT_NOFILE]     = "NOFILE",
328
        [RLIMIT_NPROC]      = "NPROC",
329
        [RLIMIT_RSS]        = "RSS",
330
        [RLIMIT_RTPRIO]     = "RTPRIO",
331
        [RLIMIT_RTTIME]     = "RTTIME",
332
        [RLIMIT_SIGPENDING] = "SIGPENDING",
333
        [RLIMIT_STACK]      = "STACK",
334
};
335

336
DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
146,808✔
337

338
void rlimits_list(const char *prefix) {
14✔
339
        FOREACH_ELEMENT(field, rlimit_table)
238✔
340
                printf("%s%s\n", strempty(prefix), *field);
224✔
341
}
14✔
342

343
int rlimit_from_string_harder(const char *s) {
54✔
344
        const char *suffix;
54✔
345

346
        /* The official prefix */
347
        suffix = startswith(s, "RLIMIT_");
54✔
348
        if (suffix)
54✔
349
                return rlimit_from_string(suffix);
17✔
350

351
        /* Our own unit file setting prefix */
352
        suffix = startswith(s, "Limit");
37✔
353
        if (suffix)
37✔
354
                return rlimit_from_string(suffix);
17✔
355

356
        return rlimit_from_string(s);
20✔
357
}
358

359
void rlimit_free_all(struct rlimit **rl) {
106,377✔
360
        free_many((void**) rl, _RLIMIT_MAX);
106,377✔
361
}
106,377✔
362

363
int rlimit_copy_all(struct rlimit* target[static _RLIMIT_MAX], struct rlimit* const source[static _RLIMIT_MAX]) {
385✔
364
        struct rlimit* copy[_RLIMIT_MAX] = {};
385✔
365

366
        assert(target);
385✔
367
        assert(source);
385✔
368

369
        for (int i = 0; i < _RLIMIT_MAX; i++) {
6,545✔
370
                if (!source[i])
6,160✔
371
                        continue;
5,390✔
372

373
                copy[i] = newdup(struct rlimit, source[i], 1);
770✔
374
                if (!copy[i]) {
770✔
375
                        rlimit_free_all(copy);
×
376
                        return -ENOMEM;
×
377
                }
378
        }
379

380
        memcpy(target, copy, sizeof(struct rlimit*) * _RLIMIT_MAX);
385✔
381
        return 0;
385✔
382
}
383

384
int rlimit_nofile_bump(int limit) {
21,712✔
385
        int r;
21,712✔
386

387
        /* Bumps the (soft) RLIMIT_NOFILE resource limit as close as possible to the specified limit. If a negative
388
         * limit is specified, bumps it to the maximum the kernel and the hard resource limit allows. This call should
389
         * be used by all our programs that might need a lot of fds, and that know how to deal with high fd numbers
390
         * (i.e. do not use select() — which chokes on fds >= 1024) */
391

392
        if (limit < 0)
21,712✔
393
                limit = read_nr_open();
58✔
394

395
        if (limit < 3)
21,712✔
396
                limit = 3;
×
397

398
        r = setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(limit));
21,712✔
399
        if (r < 0)
21,712✔
400
                return log_debug_errno(r, "Failed to set RLIMIT_NOFILE: %m");
×
401

402
        return 0;
403
}
404

405
int rlimit_nofile_safe(void) {
17,656✔
406
        struct rlimit rl;
17,656✔
407

408
        /* Resets RLIMIT_NOFILE's soft limit FD_SETSIZE (i.e. 1024), for compatibility with software still using
409
         * select() */
410

411
        if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
17,656✔
412
                return log_debug_errno(errno, "Failed to query RLIMIT_NOFILE: %m");
×
413

414
        if (rl.rlim_cur <= FD_SETSIZE)
17,656✔
415
                return 0;
416

417
        /* So we might have inherited a hard limit that's larger than the kernel's maximum limit as stored in
418
         * /proc/sys/fs/nr_open. If we pass this hard limit unmodified to setrlimit(), we'll get EPERM. To
419
         * make sure that doesn't happen, let's limit our hard limit to the value from nr_open. */
420
        rl.rlim_max = MIN(rl.rlim_max, (rlim_t) read_nr_open());
15,596✔
421
        rl.rlim_cur = MIN((rlim_t) FD_SETSIZE, rl.rlim_max);
15,596✔
422
        if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
15,596✔
423
                return log_debug_errno(errno, "Failed to lower RLIMIT_NOFILE's soft limit to " RLIM_FMT ": %m", rl.rlim_cur);
×
424

425
        return 1;
426
}
427

428
int pid_getrlimit(pid_t pid, int resource, struct rlimit *ret) {
1,098✔
429

430
        static const char * const prefix_table[_RLIMIT_MAX] = {
1,098✔
431
                [RLIMIT_CPU]        = "Max cpu time",
432
                [RLIMIT_FSIZE]      = "Max file size",
433
                [RLIMIT_DATA]       = "Max data size",
434
                [RLIMIT_STACK]      = "Max stack size",
435
                [RLIMIT_CORE]       = "Max core file size",
436
                [RLIMIT_RSS]        = "Max resident set",
437
                [RLIMIT_NPROC]      = "Max processes",
438
                [RLIMIT_NOFILE]     = "Max open files",
439
                [RLIMIT_MEMLOCK]    = "Max locked memory",
440
                [RLIMIT_AS]         = "Max address space",
441
                [RLIMIT_LOCKS]      = "Max file locks",
442
                [RLIMIT_SIGPENDING] = "Max pending signals",
443
                [RLIMIT_MSGQUEUE]   = "Max msgqueue size",
444
                [RLIMIT_NICE]       = "Max nice priority",
445
                [RLIMIT_RTPRIO]     = "Max realtime priority",
446
                [RLIMIT_RTTIME]     = "Max realtime timeout",
447
        };
448

449
        int r;
1,098✔
450

451
        assert(resource >= 0);
1,098✔
452
        assert(resource < _RLIMIT_MAX);
1,098✔
453
        assert(pid >= 0);
1,098✔
454
        assert(ret);
1,098✔
455

456
        if (pid == 0 || pid == getpid_cached())
1,098✔
457
                return RET_NERRNO(getrlimit(resource, ret));
×
458

459
        r = RET_NERRNO(prlimit(pid, resource, /* new_limit= */ NULL, ret));
1,098✔
460
        if (!ERRNO_IS_NEG_PRIVILEGE(r))
1,166✔
461
                return r;
462

463
        /* We don't have access? Then try to go via /proc/$PID/limits. Weirdly that's world readable in
464
         * contrast to querying the data via prlimit() */
465

466
        const char *p = procfs_file_alloca(pid, "limits");
68✔
467
        _cleanup_free_ char *limits = NULL;
68✔
468

469
        r = read_full_file(p, &limits, /* ret_size= */ NULL);
68✔
470
        if (r < 0)
68✔
471
                return -EPERM; /* propagate original permission error if we can't access the limits file */
472

473
        _cleanup_strv_free_ char **l = NULL;
68✔
474
        l = strv_split_newlines(limits);
68✔
475
        if (!l)
68✔
476
                return -ENOMEM;
477

478
        STRV_FOREACH(i, strv_skip(l, 1)) {
630✔
479
                _cleanup_free_ char *soft = NULL, *hard = NULL;
630✔
480
                uint64_t sv, hv;
630✔
481
                const char *e;
630✔
482

483
                e = startswith(*i, prefix_table[resource]);
630✔
484
                if (!e)
630✔
485
                        continue;
562✔
486

487
                if (*e != ' ')
68✔
488
                        continue;
×
489

490
                e += strspn(e, WHITESPACE);
68✔
491

492
                size_t n;
68✔
493
                n = strcspn(e, WHITESPACE);
68✔
494
                if (n == 0)
68✔
495
                        continue;
×
496

497
                soft = strndup(e, n);
68✔
498
                if (!soft)
68✔
499
                        return -ENOMEM;
500

501
                e += n;
68✔
502
                if (*e != ' ')
68✔
503
                        continue;
×
504

505
                e += strspn(e, WHITESPACE);
68✔
506
                n = strcspn(e, WHITESPACE);
68✔
507
                if (n == 0)
68✔
508
                        continue;
×
509

510
                hard = strndup(e, n);
68✔
511
                if (!hard)
68✔
512
                        return -ENOMEM;
513

514
                if (streq(soft, "unlimited"))
68✔
515
                        sv = RLIM_INFINITY;
8✔
516
                else {
517
                        r = safe_atou64(soft, &sv);
60✔
518
                        if (r < 0)
60✔
519
                                return r;
520
                }
521

522
                if (streq(hard, "unlimited"))
68✔
523
                        hv = RLIM_INFINITY;
9✔
524
                else {
525
                        r = safe_atou64(hard, &hv);
59✔
526
                        if (r < 0)
59✔
527
                                return r;
528
                }
529

530
                *ret = (struct rlimit) {
68✔
531
                        .rlim_cur = sv,
532
                        .rlim_max = hv,
533
                };
534

535
                return 0;
68✔
536
        }
537

538
        return -ENOTRECOVERABLE;
539
}
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