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

systemd / systemd / 22810165351

07 Mar 2026 03:22PM UTC coverage: 72.6% (-0.03%) from 72.63%
22810165351

push

github

web-flow
user-record: fix segfault when processing matchHostname field (#40979)

Fix a typo which causes a segfault when processing a user record
with `matchHostname` when it's an array instead of a simple string:

```
$ echo '{"userName":"crashhostarray","perMachine":[{"matchHostname":["host1","host2"],"locked":false}]}' | userdbctl -F -
Segmentation fault         (core dumped)

$ coredumpctl info
...
       Message: Process 1172301 (userdbctl) of user 1000 dumped core.

                Module libz.so.1 from rpm zlib-ng-2.3.3-1.fc43.x86_64
                Module libcrypto.so.3 from rpm openssl-3.5.4-2.fc43.x86_64
                Stack trace of thread 1172301:
                #0  0x00007fded7b3a656 __strcmp_evex (libc.so.6 + 0x159656)
                #1  0x00007fded7e95397 per_machine_hostname_match (libsystemd-shared-260.so + 0x295397)
                #2  0x00007fded7e955b5 per_machine_match (libsystemd-shared-260.so + 0x2955b5)
                #3  0x00007fded7e957c6 dispatch_per_machine (libsystemd-shared-260.so + 0x2957c6)
                #4  0x00007fded7e96c97 user_record_load (libsystemd-shared-260.so + 0x296c97)
                #5  0x000000000040572d display_user (/home/fsumsal/repos/@systemd/systemd/build/userdbctl + 0x572d)
                #6  0x00007fded7ea9727 dispatch_verb (libsystemd-shared-260.so + 0x2a9727)
                #7  0x000000000041077c run (/home/fsumsal/repos/@systemd/systemd/build/userdbctl + 0x1077c)
                #8  0x00000000004107ce main (/home/fsumsal/repos/@systemd/systemd/build/userdbctl + 0x107ce)
                #9  0x00007fded79e45b5 __libc_start_call_main (libc.so.6 + 0x35b5)
                #10 0x00007fded79e4668 __libc_start_main@@GLIBC_2.34 (libc.so.6 + 0x3668)
                #11 0x00000000004038d5 _start (/home/fsumsal/repos/@systemd/systemd/build/userdbctl + 0x38d5)
                ELF object binary architecture: AMD x86-64
```

5 of 35 new or added lines in 2 files covered. (14.29%)

340 existing lines in 46 files now uncovered.

316214 of 435555 relevant lines covered (72.6%)

1144732.27 hits per line

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

57.14
/src/basic/confidential-virt.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#if defined(__i386__) || defined(__x86_64__)
4
#include <cpuid.h>
5
#endif
6
#include <fcntl.h>
7
#include <threads.h>
8
#include <unistd.h>
9

10
#include "confidential-virt.h"
11
#include "confidential-virt-fundamental.h"
12
#include "errno-util.h"                                 /* IWYU pragma: keep */
13
#include "fd-util.h"
14
#include "fileio.h"                                     /* IWYU pragma: keep */
15
#include "log.h"
16
#include "string-table.h"
17
#include "string-util.h"
18
#include "utf8.h"
19

20
#if defined(__x86_64__)
21

22
static void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) {
1,350✔
23
        log_debug("CPUID func %" PRIx32 " %" PRIx32, *eax, *ecx);
1,350✔
24
        __cpuid_count(*eax, *ecx, *eax, *ebx, *ecx, *edx);
1,350✔
25
        log_debug("CPUID result %" PRIx32 " %" PRIx32 " %" PRIx32 " %" PRIx32, *eax, *ebx, *ecx, *edx);
1,350✔
26
}
1,350✔
27

28
static uint32_t cpuid_leaf(uint32_t eax, char ret_sig[static 13], bool swapped) {
732✔
29
        /* zero-init as some queries explicitly require subleaf == 0 */
30
        uint32_t sig[3] = {};
732✔
31

32
        if (swapped)
732✔
33
                cpuid(&eax, &sig[0], &sig[2], &sig[1]);
488✔
34
        else
35
                cpuid(&eax, &sig[0], &sig[1], &sig[2]);
244✔
36
        memcpy(ret_sig, sig, sizeof(sig));
732✔
37
        ret_sig[12] = 0; /* \0-terminate the string to make string comparison possible */
732✔
38

39
        /* In some CI tests ret_sig doesn't contain valid UTF8 and prints garbage to the console */
40
        log_debug("CPUID sig '%s'", strna(utf8_is_valid(ret_sig)));
1,464✔
41

42
        return eax;
732✔
43
}
44

45
#define MSR_DEVICE "/dev/cpu/0/msr"
46

47
static uint64_t msr(uint64_t index) {
×
48
        uint64_t ret;
×
49
        ssize_t rv;
×
50
        _cleanup_close_ int fd = -EBADF;
×
51

52
        fd = open(MSR_DEVICE, O_RDONLY|O_CLOEXEC);
×
53
        if (fd < 0) {
×
54
                log_debug_errno(errno,
×
55
                                "Cannot open MSR device %s (index %" PRIu64 "), ignoring: %m",
56
                                MSR_DEVICE,
57
                                index);
58
                return 0;
×
59
        }
60

61
        rv = pread(fd, &ret, sizeof(ret), index);
×
62
        if (rv < 0) {
×
63
                log_debug_errno(errno,
×
64
                                "Cannot read MSR device %s (index %" PRIu64 "), ignoring: %m",
65
                                MSR_DEVICE,
66
                                index);
67
                return 0;
×
68
        } else if (rv != sizeof(ret)) {
×
69
                log_debug("Short read %zd bytes from MSR device %s (index %" PRIu64 "), ignoring",
×
70
                          rv,
71
                          MSR_DEVICE,
72
                          index);
73
                return 0;
×
74
        }
75

76
        log_debug("MSR %" PRIu64 " result %" PRIu64 "", index, ret);
×
77
        return ret;
×
78
}
79

80
static bool detect_hyperv_cvm(uint32_t isoltype) {
244✔
81
        uint32_t eax, ebx, ecx, edx, feat;
244✔
82
        char sig[13] = {};
244✔
83

84
        feat = cpuid_leaf(CPUID_HYPERV_VENDOR_AND_MAX_FUNCTIONS, sig, false);
244✔
85

86
        if (feat < CPUID_HYPERV_MIN || feat > CPUID_HYPERV_MAX)
244✔
87
                return false;
244✔
88

89
        if (memcmp(sig, CPUID_SIG_HYPERV, sizeof(sig)) != 0)
130✔
90
                return false;
91

92
        log_debug("CPUID is on hyperv");
130✔
93
        eax = CPUID_HYPERV_FEATURES;
130✔
94
        ebx = ecx = edx = 0;
130✔
95

96
        cpuid(&eax, &ebx, &ecx, &edx);
130✔
97

98
        if (ebx & CPUID_HYPERV_ISOLATION && !(ebx & CPUID_HYPERV_CPU_MANAGEMENT)) {
130✔
99

100
                eax = CPUID_HYPERV_ISOLATION_CONFIG;
×
101
                ebx = ecx = edx = 0;
×
102
                cpuid(&eax, &ebx, &ecx, &edx);
×
103

104
                if ((ebx & CPUID_HYPERV_ISOLATION_TYPE_MASK) == isoltype)
×
105
                        return true;
×
106
        }
107

108
        return false;
109
}
110

UNCOV
111
static ConfidentialVirtualization detect_sev(void) {
×
UNCOV
112
        uint32_t eax, ebx, ecx, edx;
×
UNCOV
113
        uint64_t msrval;
×
114

UNCOV
115
        eax = CPUID_GET_HIGHEST_FUNCTION;
×
UNCOV
116
        ebx = ecx = edx = 0;
×
117

UNCOV
118
        cpuid(&eax, &ebx, &ecx, &edx);
×
119

UNCOV
120
        if (eax < CPUID_AMD_GET_ENCRYPTED_MEMORY_CAPABILITIES)
×
UNCOV
121
                return CONFIDENTIAL_VIRTUALIZATION_NONE;
×
122

UNCOV
123
        eax = CPUID_AMD_GET_ENCRYPTED_MEMORY_CAPABILITIES;
×
UNCOV
124
        ebx = ecx = edx = 0;
×
125

UNCOV
126
        cpuid(&eax, &ebx, &ecx, &edx);
×
127

128
        /* bit 1 == CPU supports SEV feature
129
         *
130
         * Note, Azure blocks this CPUID leaf from its SEV-SNP
131
         * guests, so we must fallback to trying some HyperV
132
         * specific CPUID checks.
133
         */
UNCOV
134
        if (!(eax & EAX_SEV)) {
×
UNCOV
135
                log_debug("No sev in CPUID, trying hyperv CPUID");
×
136

UNCOV
137
                if (detect_hyperv_cvm(CPUID_HYPERV_ISOLATION_TYPE_SNP))
×
138
                        return CONFIDENTIAL_VIRTUALIZATION_SEV_SNP;
139

UNCOV
140
                log_debug("No hyperv CPUID");
×
UNCOV
141
                return CONFIDENTIAL_VIRTUALIZATION_NONE;
×
142
        }
143

144
        msrval = msr(MSR_AMD64_SEV);
×
145

146
        /* Test reverse order, since the SEV-SNP bit implies
147
         * the SEV-ES bit, which implies the SEV bit */
148
        if (msrval & MSR_SEV_SNP)
×
149
                return CONFIDENTIAL_VIRTUALIZATION_SEV_SNP;
150
        if (msrval & MSR_SEV_ES)
×
151
                return CONFIDENTIAL_VIRTUALIZATION_SEV_ES;
152
        if (msrval & MSR_SEV)
×
153
                return CONFIDENTIAL_VIRTUALIZATION_SEV;
×
154

155
        return CONFIDENTIAL_VIRTUALIZATION_NONE;
156
}
157

158
static ConfidentialVirtualization detect_tdx(void) {
244✔
159
        uint32_t eax, ebx, ecx, edx;
244✔
160
        char sig[13] = {};
244✔
161

162
        eax = CPUID_GET_HIGHEST_FUNCTION;
244✔
163
        ebx = ecx = edx = 0;
244✔
164

165
        cpuid(&eax, &ebx, &ecx, &edx);
244✔
166

167
        if (eax < CPUID_INTEL_TDX_ENUMERATION)
244✔
168
                return CONFIDENTIAL_VIRTUALIZATION_NONE;
244✔
169

170
        cpuid_leaf(CPUID_INTEL_TDX_ENUMERATION, sig, true);
244✔
171

172
        if (memcmp(sig, CPUID_SIG_INTEL_TDX, sizeof(sig)) == 0)
244✔
173
                return CONFIDENTIAL_VIRTUALIZATION_TDX;
174

175
        log_debug("No tdx in CPUID, trying hyperv CPUID");
244✔
176

177
        if (detect_hyperv_cvm(CPUID_HYPERV_ISOLATION_TYPE_TDX))
244✔
178
                return CONFIDENTIAL_VIRTUALIZATION_TDX;
×
179

180
        return CONFIDENTIAL_VIRTUALIZATION_NONE;
181
}
182

183
static bool detect_hypervisor(void) {
244✔
184
        uint32_t eax, ebx, ecx, edx;
244✔
185
        bool is_hv;
244✔
186

187
        eax = CPUID_PROCESSOR_INFO_AND_FEATURE_BITS;
244✔
188
        ebx = ecx = edx = 0;
244✔
189

190
        cpuid(&eax, &ebx, &ecx, &edx);
244✔
191

192
        is_hv = ecx & CPUID_FEATURE_HYPERVISOR;
244✔
193

194
        log_debug("CPUID is hypervisor: %s", yes_no(is_hv));
488✔
195
        return is_hv;
244✔
196
}
197

198
static ConfidentialVirtualization detect_confidential_virtualization_impl(void) {
244✔
199
        char sig[13] = {};
244✔
200

201
        /* Skip everything on bare metal */
202
        if (detect_hypervisor()) {
244✔
203
                cpuid_leaf(0, sig, true);
244✔
204

205
                if (memcmp(sig, CPUID_SIG_AMD, sizeof(sig)) == 0)
244✔
UNCOV
206
                        return detect_sev();
×
207
                else if (memcmp(sig, CPUID_SIG_INTEL, sizeof(sig)) == 0)
244✔
208
                        return detect_tdx();
244✔
209
        }
210

211
        return CONFIDENTIAL_VIRTUALIZATION_NONE;
212
}
213
#elif defined(__s390x__)
214
static ConfidentialVirtualization detect_confidential_virtualization_impl(void) {
215
        _cleanup_free_ char *s = NULL;
216
        size_t readsize;
217
        int r;
218

219
        r = read_full_virtual_file("/sys/firmware/uv/prot_virt_guest", &s, &readsize);
220
        if (r < 0) {
221
                log_debug_errno(r, "Unable to read /sys/firmware/uv/prot_virt_guest: %m");
222
                return CONFIDENTIAL_VIRTUALIZATION_NONE;
223
        }
224

225
        if (readsize >= 1 && s[0] == '1')
226
                return CONFIDENTIAL_VIRTUALIZATION_PROTVIRT;
227

228
        return CONFIDENTIAL_VIRTUALIZATION_NONE;
229
}
230
#elif defined(__aarch64__)
231
static ConfidentialVirtualization detect_confidential_virtualization_impl(void) {
232
        int r;
233

234
        r = RET_NERRNO(access("/sys/devices/platform/arm-cca-dev", F_OK));
235
        if (r < 0) {
236
                log_debug_errno(r, "Unable to check /sys/devices/platform/arm-cca-dev: %m");
237
                return CONFIDENTIAL_VIRTUALIZATION_NONE;
238
        }
239

240
        return CONFIDENTIAL_VIRTUALIZATION_CCA;
241
}
242
#else /* ! x86_64 */
243
static ConfidentialVirtualization detect_confidential_virtualization_impl(void) {
244
        log_debug("No confidential virtualization detection on this architecture");
245
        return CONFIDENTIAL_VIRTUALIZATION_NONE;
246
}
247
#endif /* ! x86_64 */
248

249
ConfidentialVirtualization detect_confidential_virtualization(void) {
327✔
250
        static thread_local ConfidentialVirtualization cached_found = _CONFIDENTIAL_VIRTUALIZATION_INVALID;
327✔
251

252
        if (cached_found == _CONFIDENTIAL_VIRTUALIZATION_INVALID)
327✔
253
                cached_found = detect_confidential_virtualization_impl();
244✔
254

255
        return cached_found;
327✔
256
}
257

258
static const char *const confidential_virtualization_table[_CONFIDENTIAL_VIRTUALIZATION_MAX] = {
259
        [CONFIDENTIAL_VIRTUALIZATION_NONE]     = "none",
260
        [CONFIDENTIAL_VIRTUALIZATION_SEV]      = "sev",
261
        [CONFIDENTIAL_VIRTUALIZATION_SEV_ES]   = "sev-es",
262
        [CONFIDENTIAL_VIRTUALIZATION_SEV_SNP]  = "sev-snp",
263
        [CONFIDENTIAL_VIRTUALIZATION_TDX]      = "tdx",
264
        [CONFIDENTIAL_VIRTUALIZATION_PROTVIRT] = "protvirt",
265
        [CONFIDENTIAL_VIRTUALIZATION_CCA]      = "cca",
266
};
267

268
DEFINE_STRING_TABLE_LOOKUP(confidential_virtualization, ConfidentialVirtualization);
62✔
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