Coverage Report

Created: 2026-09-14 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/systemd/src/core/taint.c
Line
Count
Source
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3
#include <sys/utsname.h>
4
5
#include "alloc-util.h"
6
#include "clock-util.h"
7
#include "constants.h"
8
#include "errno-util.h"
9
#include "fileio.h"
10
#include "fs-util.h"
11
#include "log.h"
12
#include "os-util.h"
13
#include "path-util.h"
14
#include "string-util.h"
15
#include "strv.h"
16
#include "taint.h"
17
#include "uid-range.h"
18
19
0
static int short_uid_gid_range(UIDRangeUsernsMode mode) {
20
0
        _cleanup_(uid_range_freep) UIDRange *p = NULL;
21
0
        int r;
22
23
        /* Taint systemd if we the UID/GID range assigned to this environment doesn't at least cover 0…65534,
24
         * i.e. from root to nobody. */
25
26
0
        r = uid_range_load_userns(/* path= */ NULL, mode, &p);
27
0
        if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
28
0
                return false;
29
0
        if (r < 0)
30
0
                return log_debug_errno(r, "Failed to load uid_map or gid_map: %m");
31
32
0
        return !uid_range_covers(p, 0, 65535);
33
0
}
34
35
0
char** taint_strv(void) {
36
0
        const char *stage[11] = {};
37
0
        size_t n = 0;
38
39
        /* Returns a "taint string", e.g. "local-hwclock:var-run-bad". Only things that are detected at
40
         * runtime should be tagged here. For stuff that is known during compilation, emit a warning in the
41
         * configuration phase. */
42
43
0
        _cleanup_free_ char *bin = NULL, *usr_sbin = NULL, *var_run = NULL;
44
45
0
        if (readlink_malloc("/bin", &bin) < 0 || !PATH_IN_SET(bin, "usr/bin", "/usr/bin"))
46
0
                stage[n++] = "unmerged-usr";
47
48
        /* Note that the check is different from default_PATH(), as we want to taint on uncanonical symlinks
49
         * too. */
50
0
        if (readlink_malloc("/usr/sbin", &usr_sbin) < 0 || !PATH_IN_SET(usr_sbin, "bin", "/usr/bin"))
51
0
                stage[n++] = "unmerged-bin";
52
53
0
        if (readlink_malloc("/var/run", &var_run) < 0 || !PATH_IN_SET(var_run, "../run", "/run"))
54
0
                stage[n++] = "var-run-bad";
55
56
0
        if (clock_is_localtime(NULL) > 0)
57
0
                stage[n++] = "local-hwclock";
58
59
0
        if (os_release_support_ended(NULL, /* quiet= */ true, NULL) > 0)
60
0
                stage[n++] = "support-ended";
61
62
0
        struct utsname uts;
63
0
        assert_se(uname(&uts) >= 0);
64
0
        if (strverscmp_improved(uts.release, KERNEL_BASELINE_VERSION) < 0)
65
0
                stage[n++] = "old-kernel";
66
67
0
        _cleanup_free_ char *overflowuid = NULL, *overflowgid = NULL;
68
0
        if (read_one_line_file("/proc/sys/kernel/overflowuid", &overflowuid) >= 0 &&
69
0
            !streq(overflowuid, "65534"))
70
0
                stage[n++] = "overflowuid-not-65534";
71
0
        if (read_one_line_file("/proc/sys/kernel/overflowgid", &overflowgid) >= 0 &&
72
0
            !streq(overflowgid, "65534"))
73
0
                stage[n++] = "overflowgid-not-65534";
74
75
0
        if (short_uid_gid_range(UID_RANGE_USERNS_INSIDE) > 0)
76
0
                stage[n++] = "short-uid-range";
77
0
        if (short_uid_gid_range(GID_RANGE_USERNS_INSIDE) > 0)
78
0
                stage[n++] = "short-gid-range";
79
80
0
        assert(n < ELEMENTSOF(stage) - 1);  /* One extra for NULL terminator */
81
82
0
        return strv_copy((char *const *) stage);
83
0
}
84
85
0
char* taint_string(void) {
86
0
        _cleanup_strv_free_ char **taints = NULL;
87
88
0
        taints = taint_strv();
89
0
        if (!taints)
90
0
                return NULL;
91
92
0
        return strv_join(taints, ":");
93
0
}