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

systemd / systemd / 23172097450

16 Mar 2026 07:45PM UTC coverage: 72.568% (+0.06%) from 72.513%
23172097450

push

github

keszybz
add-ug-bo-translation

316055 of 435531 relevant lines covered (72.57%)

1182407.5 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,364✔
23
        log_debug("CPUID func %" PRIx32 " %" PRIx32, *eax, *ecx);
1,364✔
24
        __cpuid_count(*eax, *ecx, *eax, *ebx, *ecx, *edx);
1,364✔
25
        log_debug("CPUID result %" PRIx32 " %" PRIx32 " %" PRIx32 " %" PRIx32, *eax, *ebx, *ecx, *edx);
1,364✔
26
}
1,364✔
27

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

32
        if (swapped)
741✔
33
                cpuid(&eax, &sig[0], &sig[2], &sig[1]);
494✔
34
        else
35
                cpuid(&eax, &sig[0], &sig[1], &sig[2]);
247✔
36
        memcpy(ret_sig, sig, sizeof(sig));
741✔
37
        ret_sig[12] = 0; /* \0-terminate the string to make string comparison possible */
741✔
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,482✔
41

42
        return eax;
741✔
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) {
247✔
81
        uint32_t eax, ebx, ecx, edx, feat;
247✔
82
        char sig[13] = {};
247✔
83

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

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

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

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

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

98
        if (ebx & CPUID_HYPERV_ISOLATION && !(ebx & CPUID_HYPERV_CPU_MANAGEMENT)) {
129✔
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

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

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

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

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

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

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
         */
134
        if (!(eax & EAX_SEV)) {
×
135
                log_debug("No sev in CPUID, trying hyperv CPUID");
×
136

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

140
                log_debug("No hyperv CPUID");
×
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) {
247✔
159
        uint32_t eax, ebx, ecx, edx;
247✔
160
        char sig[13] = {};
247✔
161

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

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

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

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

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

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

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

180
        return CONFIDENTIAL_VIRTUALIZATION_NONE;
181
}
182

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

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

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

192
        is_hv = ecx & CPUID_FEATURE_HYPERVISOR;
247✔
193

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

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

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

205
                if (memcmp(sig, CPUID_SIG_AMD, sizeof(sig)) == 0)
247✔
206
                        return detect_sev();
×
207
                else if (memcmp(sig, CPUID_SIG_INTEL, sizeof(sig)) == 0)
247✔
208
                        return detect_tdx();
247✔
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) {
336✔
250
        static thread_local ConfidentialVirtualization cached_found = _CONFIDENTIAL_VIRTUALIZATION_INVALID;
336✔
251

252
        if (cached_found == _CONFIDENTIAL_VIRTUALIZATION_INVALID)
336✔
253
                cached_found = detect_confidential_virtualization_impl();
247✔
254

255
        return cached_found;
336✔
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