]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/virt.c
Merge pull request #8552 from keszybz/test-improvements
[thirdparty/systemd.git] / src / basic / virt.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
b52aae1d
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
b52aae1d
LP
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 15 Lesser General Public License for more details.
b52aae1d 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
b52aae1d
LP
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
d31b0033
MG
21#if defined(__i386__) || defined(__x86_64__)
22#include <cpuid.h>
23#endif
b52aae1d 24#include <errno.h>
11c3a366
TA
25#include <stdint.h>
26#include <stdlib.h>
07630cea 27#include <string.h>
b52aae1d
LP
28#include <unistd.h>
29
b5efdb8a 30#include "alloc-util.h"
ade61d3b 31#include "dirent-util.h"
295ee984 32#include "env-util.h"
ade61d3b 33#include "fd-util.h"
07630cea 34#include "fileio.h"
11c3a366 35#include "macro.h"
93cc7779 36#include "process-util.h"
b5efdb8a 37#include "stat-util.h"
8b43440b 38#include "string-table.h"
07630cea 39#include "string-util.h"
b52aae1d
LP
40#include "virt.h"
41
75f86906 42static int detect_vm_cpuid(void) {
b52aae1d 43
2ef8a4c4 44 /* CPUID is an x86 specific interface. */
bdb628ee 45#if defined(__i386__) || defined(__x86_64__)
b52aae1d 46
75f86906
LP
47 static const struct {
48 const char *cpuid;
49 int id;
50 } cpuid_vendor_table[] = {
51 { "XenVMMXenVMM", VIRTUALIZATION_XEN },
52 { "KVMKVMKVM", VIRTUALIZATION_KVM },
5588612e 53 { "TCGTCGTCGTCG", VIRTUALIZATION_QEMU },
b52aae1d 54 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
75f86906 55 { "VMwareVMware", VIRTUALIZATION_VMWARE },
ff85f271 56 /* https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs */
75f86906 57 { "Microsoft Hv", VIRTUALIZATION_MICROSOFT },
aa0c3427
LBS
58 /* https://wiki.freebsd.org/bhyve */
59 { "bhyve bhyve ", VIRTUALIZATION_BHYVE },
1fdf07f5 60 { "QNXQVMBSQG", VIRTUALIZATION_QNX },
75f86906 61 };
b52aae1d 62
d31b0033 63 uint32_t eax, ebx, ecx, edx;
b52aae1d
LP
64 bool hypervisor;
65
66 /* http://lwn.net/Articles/301888/ */
b52aae1d 67
b52aae1d 68 /* First detect whether there is a hypervisor */
d31b0033
MG
69 if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) == 0)
70 return VIRTUALIZATION_NONE;
b52aae1d
LP
71
72 hypervisor = !!(ecx & 0x80000000U);
73
74 if (hypervisor) {
75f86906
LP
75 union {
76 uint32_t sig32[3];
77 char text[13];
78 } sig = {};
79 unsigned j;
b52aae1d
LP
80
81 /* There is a hypervisor, see what it is */
8481e3e7 82 __cpuid(0x40000000U, eax, ebx, ecx, edx);
d31b0033
MG
83
84 sig.sig32[0] = ebx;
85 sig.sig32[1] = ecx;
86 sig.sig32[2] = edx;
b52aae1d 87
9f63a08d
SS
88 log_debug("Virtualization found, CPUID=%s", sig.text);
89
75f86906
LP
90 for (j = 0; j < ELEMENTSOF(cpuid_vendor_table); j ++)
91 if (streq(sig.text, cpuid_vendor_table[j].cpuid))
92 return cpuid_vendor_table[j].id;
bdb628ee 93
75f86906 94 return VIRTUALIZATION_VM_OTHER;
b52aae1d 95 }
bdb628ee 96#endif
9f63a08d 97 log_debug("No virtualization found in CPUID");
bdb628ee 98
75f86906 99 return VIRTUALIZATION_NONE;
bdb628ee
ZJS
100}
101
75f86906 102static int detect_vm_device_tree(void) {
db6a8689 103#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__)
d831deb5
CA
104 _cleanup_free_ char *hvtype = NULL;
105 int r;
106
b8f1df82 107 r = read_one_line_file("/proc/device-tree/hypervisor/compatible", &hvtype);
75f86906 108 if (r == -ENOENT) {
ce09c71d
AJ
109 _cleanup_closedir_ DIR *dir = NULL;
110 struct dirent *dent;
111
112 dir = opendir("/proc/device-tree");
113 if (!dir) {
9f63a08d
SS
114 if (errno == ENOENT) {
115 log_debug_errno(errno, "/proc/device-tree: %m");
75f86906 116 return VIRTUALIZATION_NONE;
9f63a08d 117 }
ce09c71d
AJ
118 return -errno;
119 }
120
75f86906 121 FOREACH_DIRENT(dent, dir, return -errno)
9f63a08d
SS
122 if (strstr(dent->d_name, "fw-cfg")) {
123 log_debug("Virtualization QEMU: \"fw-cfg\" present in /proc/device-tree/%s", dent->d_name);
75f86906 124 return VIRTUALIZATION_QEMU;
9f63a08d 125 }
75f86906 126
9f63a08d 127 log_debug("No virtualization found in /proc/device-tree/*");
75f86906
LP
128 return VIRTUALIZATION_NONE;
129 } else if (r < 0)
130 return r;
131
9f63a08d 132 log_debug("Virtualization %s found in /proc/device-tree/hypervisor/compatible", hvtype);
75f86906
LP
133 if (streq(hvtype, "linux,kvm"))
134 return VIRTUALIZATION_KVM;
135 else if (strstr(hvtype, "xen"))
136 return VIRTUALIZATION_XEN;
137 else
138 return VIRTUALIZATION_VM_OTHER;
139#else
9f63a08d 140 log_debug("This platform does not support /proc/device-tree");
75f86906 141 return VIRTUALIZATION_NONE;
d831deb5 142#endif
d831deb5
CA
143}
144
75f86906 145static int detect_vm_dmi(void) {
2ef8a4c4 146#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
bdb628ee
ZJS
147
148 static const char *const dmi_vendors[] = {
3728dcde 149 "/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */
bdb628ee
ZJS
150 "/sys/class/dmi/id/sys_vendor",
151 "/sys/class/dmi/id/board_vendor",
152 "/sys/class/dmi/id/bios_vendor"
153 };
154
75f86906
LP
155 static const struct {
156 const char *vendor;
157 int id;
158 } dmi_vendor_table[] = {
3728dcde 159 { "KVM", VIRTUALIZATION_KVM },
75f86906 160 { "QEMU", VIRTUALIZATION_QEMU },
bdb628ee 161 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
75f86906
LP
162 { "VMware", VIRTUALIZATION_VMWARE },
163 { "VMW", VIRTUALIZATION_VMWARE },
164 { "innotek GmbH", VIRTUALIZATION_ORACLE },
165 { "Xen", VIRTUALIZATION_XEN },
166 { "Bochs", VIRTUALIZATION_BOCHS },
167 { "Parallels", VIRTUALIZATION_PARALLELS },
aa0c3427
LBS
168 /* https://wiki.freebsd.org/bhyve */
169 { "BHYVE", VIRTUALIZATION_BHYVE },
75f86906 170 };
bdb628ee 171 unsigned i;
75f86906 172 int r;
b52aae1d
LP
173
174 for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
b1b8e816 175 _cleanup_free_ char *s = NULL;
75f86906 176 unsigned j;
b52aae1d 177
b1b8e816
LP
178 r = read_one_line_file(dmi_vendors[i], &s);
179 if (r < 0) {
75f86906
LP
180 if (r == -ENOENT)
181 continue;
b52aae1d 182
75f86906 183 return r;
b52aae1d
LP
184 }
185
75f86906 186 for (j = 0; j < ELEMENTSOF(dmi_vendor_table); j++)
9f63a08d
SS
187 if (startswith(s, dmi_vendor_table[j].vendor)) {
188 log_debug("Virtualization %s found in DMI (%s)", s, dmi_vendors[i]);
75f86906 189 return dmi_vendor_table[j].id;
9f63a08d 190 }
b52aae1d 191 }
bdb628ee
ZJS
192#endif
193
9f63a08d
SS
194 log_debug("No virtualization found in DMI");
195
75f86906 196 return VIRTUALIZATION_NONE;
bdb628ee
ZJS
197}
198
75f86906 199static int detect_vm_xen(void) {
45e1c7d5 200
3f61278b 201 /* Check for Dom0 will be executed later in detect_vm_xen_dom0
87dc723a
OH
202 The presence of /proc/xen indicates some form of a Xen domain */
203 if (access("/proc/xen", F_OK) < 0) {
204 log_debug("Virtualization XEN not found, /proc/xen does not exist");
3f61278b
SS
205 return VIRTUALIZATION_NONE;
206 }
207
87dc723a 208 log_debug("Virtualization XEN found (/proc/xen exists)");
45e1c7d5 209 return VIRTUALIZATION_XEN;
3f61278b
SS
210}
211
575e6588
OH
212#define XENFEAT_dom0 11 /* xen/include/public/features.h */
213#define PATH_FEATURES "/sys/hypervisor/properties/features"
1a8e4148
OH
214/* Returns -errno, or 0 for domU, or 1 for dom0 */
215static int detect_vm_xen_dom0(void) {
75f86906
LP
216 _cleanup_free_ char *domcap = NULL;
217 char *cap, *i;
bdb628ee 218 int r;
b52aae1d 219
575e6588
OH
220 r = read_one_line_file(PATH_FEATURES, &domcap);
221 if (r < 0 && r != -ENOENT)
222 return r;
223 if (r == 0) {
224 unsigned long features;
225
47dbb99a
YW
226 /* Here, we need to use sscanf() instead of safe_atoul()
227 * as the string lacks the leading "0x". */
13e0f9fe
OH
228 r = sscanf(domcap, "%lx", &features);
229 if (r == 1) {
575e6588
OH
230 r = !!(features & (1U << XENFEAT_dom0));
231 log_debug("Virtualization XEN, found %s with value %08lx, "
232 "XENFEAT_dom0 (indicating the 'hardware domain') is%s set.",
233 PATH_FEATURES, features, r ? "" : " not");
234 return r;
235 }
236 log_debug("Virtualization XEN, found %s, unhandled content '%s'",
237 PATH_FEATURES, domcap);
238 }
239
75f86906 240 r = read_one_line_file("/proc/xen/capabilities", &domcap);
9f63a08d 241 if (r == -ENOENT) {
1a8e4148
OH
242 log_debug("Virtualization XEN because /proc/xen/capabilities does not exist");
243 return 0;
9f63a08d 244 }
d5b687e7
LP
245 if (r < 0)
246 return r;
bdb628ee 247
75f86906
LP
248 i = domcap;
249 while ((cap = strsep(&i, ",")))
250 if (streq(cap, "control_d"))
251 break;
9f63a08d
SS
252 if (!cap) {
253 log_debug("Virtualization XEN DomU found (/proc/xen/capabilites)");
1a8e4148 254 return 0;
9f63a08d
SS
255 }
256
257 log_debug("Virtualization XEN Dom0 ignored (/proc/xen/capabilities)");
1a8e4148 258 return 1;
75f86906 259}
37287585 260
75f86906
LP
261static int detect_vm_hypervisor(void) {
262 _cleanup_free_ char *hvtype = NULL;
263 int r;
37287585 264
75f86906
LP
265 r = read_one_line_file("/sys/hypervisor/type", &hvtype);
266 if (r == -ENOENT)
267 return VIRTUALIZATION_NONE;
268 if (r < 0)
269 return r;
37287585 270
9f63a08d
SS
271 log_debug("Virtualization %s found in /sys/hypervisor/type", hvtype);
272
75f86906
LP
273 if (streq(hvtype, "xen"))
274 return VIRTUALIZATION_XEN;
275 else
276 return VIRTUALIZATION_VM_OTHER;
277}
37287585 278
75f86906
LP
279static int detect_vm_uml(void) {
280 _cleanup_free_ char *cpuinfo_contents = NULL;
281 int r;
37287585 282
75f86906
LP
283 /* Detect User-Mode Linux by reading /proc/cpuinfo */
284 r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
ef2a48aa
ZJS
285 if (r == -ENOENT) {
286 log_debug("/proc/cpuinfo not found, assuming no UML virtualization.");
287 return VIRTUALIZATION_NONE;
288 }
75f86906 289 if (r < 0)
bdb628ee 290 return r;
9f63a08d
SS
291
292 if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) {
293 log_debug("UML virtualization found in /proc/cpuinfo");
75f86906 294 return VIRTUALIZATION_UML;
9f63a08d 295 }
bdb628ee 296
ef2a48aa 297 log_debug("UML virtualization not found in /proc/cpuinfo.");
75f86906
LP
298 return VIRTUALIZATION_NONE;
299}
e32886e0 300
75f86906 301static int detect_vm_zvm(void) {
bdb628ee 302
75f86906
LP
303#if defined(__s390__)
304 _cleanup_free_ char *t = NULL;
305 int r;
e32886e0 306
c4cd1d4d 307 r = get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE, &t);
75f86906
LP
308 if (r == -ENOENT)
309 return VIRTUALIZATION_NONE;
310 if (r < 0)
311 return r;
e32886e0 312
9f63a08d 313 log_debug("Virtualization %s found in /proc/sysinfo", t);
75f86906
LP
314 if (streq(t, "z/VM"))
315 return VIRTUALIZATION_ZVM;
316 else
317 return VIRTUALIZATION_KVM;
318#else
9f63a08d 319 log_debug("This platform does not support /proc/sysinfo");
75f86906
LP
320 return VIRTUALIZATION_NONE;
321#endif
322}
e32886e0 323
75f86906
LP
324/* Returns a short identifier for the various VM implementations */
325int detect_vm(void) {
326 static thread_local int cached_found = _VIRTUALIZATION_INVALID;
28b1a3ea 327 int r, dmi;
530c1c30 328 bool other = false;
e32886e0 329
75f86906
LP
330 if (cached_found >= 0)
331 return cached_found;
bdb628ee 332
f6875b0a 333 /* We have to use the correct order here:
f6875b0a 334 *
28b1a3ea
CH
335 * -> First try to detect Oracle Virtualbox, even if it uses KVM.
336 * -> Second try to detect from cpuid, this will report KVM for
337 * whatever software is used even if info in dmi is overwritten.
338 * -> Third try to detect from dmi. */
5f1c788c 339
28b1a3ea 340 dmi = detect_vm_dmi();
2f8e375d
BR
341 if (dmi == VIRTUALIZATION_ORACLE) {
342 r = dmi;
343 goto finish;
344 }
5f1c788c 345
28b1a3ea 346 r = detect_vm_cpuid();
75f86906
LP
347 if (r < 0)
348 return r;
530c1c30
RC
349 if (r != VIRTUALIZATION_NONE) {
350 if (r == VIRTUALIZATION_VM_OTHER)
351 other = true;
352 else
353 goto finish;
354 }
d831deb5 355
28b1a3ea 356 r = dmi;
75f86906
LP
357 if (r < 0)
358 return r;
530c1c30
RC
359 if (r != VIRTUALIZATION_NONE) {
360 if (r == VIRTUALIZATION_VM_OTHER)
361 other = true;
362 else
363 goto finish;
364 }
b52aae1d 365
42685451 366 /* x86 xen will most likely be detected by cpuid. If not (most likely
87dc723a
OH
367 * because we're not an x86 guest), then we should try the /proc/xen
368 * directory next. If that's not found, then we check for the high-level
369 * hypervisor sysfs file.
2f5fa62b 370 */
42685451
AJ
371
372 r = detect_vm_xen();
7080ea16
RR
373 if (r < 0)
374 return r;
530c1c30
RC
375 if (r != VIRTUALIZATION_NONE) {
376 if (r == VIRTUALIZATION_VM_OTHER)
377 other = true;
378 else
379 goto finish;
380 }
7080ea16 381
75f86906
LP
382 r = detect_vm_hypervisor();
383 if (r < 0)
384 return r;
530c1c30
RC
385 if (r != VIRTUALIZATION_NONE) {
386 if (r == VIRTUALIZATION_VM_OTHER)
387 other = true;
388 else
389 goto finish;
390 }
f41925b4 391
75f86906
LP
392 r = detect_vm_device_tree();
393 if (r < 0)
394 return r;
530c1c30
RC
395 if (r != VIRTUALIZATION_NONE) {
396 if (r == VIRTUALIZATION_VM_OTHER)
397 other = true;
398 else
399 goto finish;
400 }
f41925b4 401
75f86906
LP
402 r = detect_vm_uml();
403 if (r < 0)
404 return r;
530c1c30
RC
405 if (r != VIRTUALIZATION_NONE) {
406 if (r == VIRTUALIZATION_VM_OTHER)
407 other = true;
408 else
409 goto finish;
410 }
f41925b4 411
75f86906
LP
412 r = detect_vm_zvm();
413 if (r < 0)
414 return r;
0fb533a5
LP
415
416finish:
3f61278b
SS
417 /* x86 xen Dom0 is detected as XEN in hypervisor and maybe others.
418 * In order to detect the Dom0 as not virtualization we need to
419 * double-check it */
1a8e4148
OH
420 if (r == VIRTUALIZATION_XEN) {
421 int ret = detect_vm_xen_dom0();
422 if (ret < 0)
423 return ret;
424 if (ret > 0)
425 r = VIRTUALIZATION_NONE;
426 } else if (r == VIRTUALIZATION_NONE && other)
530c1c30 427 r = VIRTUALIZATION_VM_OTHER;
3f61278b 428
0fb533a5 429 cached_found = r;
9f63a08d 430 log_debug("Found VM virtualization %s", virtualization_to_string(r));
0fb533a5 431 return r;
b52aae1d
LP
432}
433
75f86906 434int detect_container(void) {
0fb533a5 435
75f86906
LP
436 static const struct {
437 const char *value;
438 int id;
439 } value_table[] = {
440 { "lxc", VIRTUALIZATION_LXC },
441 { "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT },
442 { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN },
443 { "docker", VIRTUALIZATION_DOCKER },
9fb16425 444 { "rkt", VIRTUALIZATION_RKT },
75f86906 445 };
0fb533a5 446
75f86906 447 static thread_local int cached_found = _VIRTUALIZATION_INVALID;
fdd25311 448 _cleanup_free_ char *m = NULL;
75f86906
LP
449 const char *e = NULL;
450 unsigned j;
ab94af92 451 int r;
b52aae1d 452
75f86906 453 if (cached_found >= 0)
0fb533a5 454 return cached_found;
0fb533a5 455
8d6e8034 456 /* /proc/vz exists in container and outside of the container, /proc/bc only outside of the container. */
b52aae1d
LP
457 if (access("/proc/vz", F_OK) >= 0 &&
458 access("/proc/bc", F_OK) < 0) {
75f86906 459 r = VIRTUALIZATION_OPENVZ;
0fb533a5 460 goto finish;
b52aae1d
LP
461 }
462
df0ff127 463 if (getpid_cached() == 1) {
8d6e8034 464 /* If we are PID 1 we can just check our own environment variable, and that's authoritative. */
fdd25311
LP
465
466 e = getenv("container");
467 if (isempty(e)) {
75f86906 468 r = VIRTUALIZATION_NONE;
fdd25311
LP
469 goto finish;
470 }
fdd25311 471
8d6e8034
LP
472 goto translate_name;
473 }
474
475 /* Otherwise, PID 1 might have dropped this information into a file in /run. This is better than accessing
476 * /proc/1/environ, since we don't need CAP_SYS_PTRACE for that. */
477 r = read_one_line_file("/run/systemd/container", &m);
478 if (r >= 0) {
479 e = m;
480 goto translate_name;
481 }
482 if (r != -ENOENT)
483 return log_debug_errno(r, "Failed to read /run/systemd/container: %m");
484
485 /* Fallback for cases where PID 1 was not systemd (for example, cases where init=/bin/sh is used. */
486 r = getenv_for_pid(1, "container", &m);
487 if (r > 0) {
fdd25311 488 e = m;
8d6e8034 489 goto translate_name;
fdd25311 490 }
8d6e8034
LP
491 if (r < 0) /* This only works if we have CAP_SYS_PTRACE, hence let's better ignore failures here */
492 log_debug_errno(r, "Failed to read $container of PID 1, ignoring: %m");
493
494 /* Interestingly /proc/1/sched actually shows the host's PID for what we see as PID 1. Hence, if the PID shown
495 * there is not 1, we know we are in a PID namespace. and hence a container. */
496 r = read_one_line_file("/proc/1/sched", &m);
497 if (r >= 0) {
498 const char *t;
499
500 t = strrchr(m, '(');
501 if (!t)
502 return -EIO;
503
504 if (!startswith(t, "(1,")) {
505 r = VIRTUALIZATION_CONTAINER_OTHER;
506 goto finish;
507 }
508 } else if (r != -ENOENT)
509 return r;
510
511 /* If that didn't work, give up, assume no container manager. */
512 r = VIRTUALIZATION_NONE;
513 goto finish;
b52aae1d 514
8d6e8034 515translate_name:
75f86906
LP
516 for (j = 0; j < ELEMENTSOF(value_table); j++)
517 if (streq(e, value_table[j].value)) {
518 r = value_table[j].id;
519 goto finish;
520 }
0fb533a5 521
f499daf4 522 r = VIRTUALIZATION_CONTAINER_OTHER;
fdd25311 523
0fb533a5 524finish:
8d6e8034 525 log_debug("Found container virtualization %s.", virtualization_to_string(r));
0fb533a5 526 cached_found = r;
ab94af92 527 return r;
b52aae1d
LP
528}
529
75f86906 530int detect_virtualization(void) {
b52aae1d 531 int r;
b52aae1d 532
75f86906 533 r = detect_container();
9f63a08d
SS
534 if (r == 0)
535 r = detect_vm();
b52aae1d 536
9f63a08d 537 return r;
b52aae1d 538}
75f86906 539
299a34c1
ZJS
540static int userns_has_mapping(const char *name) {
541 _cleanup_fclose_ FILE *f = NULL;
542 _cleanup_free_ char *buf = NULL;
543 size_t n_allocated = 0;
544 ssize_t n;
545 uint32_t a, b, c;
546 int r;
547
548 f = fopen(name, "re");
549 if (!f) {
550 log_debug_errno(errno, "Failed to open %s: %m", name);
abd67ce7 551 return errno == ENOENT ? false : -errno;
299a34c1
ZJS
552 }
553
554 n = getline(&buf, &n_allocated, f);
555 if (n < 0) {
556 if (feof(f)) {
557 log_debug("%s is empty, we're in an uninitialized user namespace", name);
558 return true;
559 }
560
561 return log_debug_errno(errno, "Failed to read %s: %m", name);
562 }
563
564 r = sscanf(buf, "%"PRIu32" %"PRIu32" %"PRIu32, &a, &b, &c);
565 if (r < 3)
566 return log_debug_errno(errno, "Failed to parse %s: %m", name);
567
568 if (a == 0 && b == 0 && c == UINT32_MAX) {
569 /* The kernel calls mappings_overlap() and does not allow overlaps */
570 log_debug("%s has a full 1:1 mapping", name);
571 return false;
572 }
573
574 /* Anything else implies that we are in a user namespace */
575 log_debug("Mapping found in %s, we're in a user namespace", name);
576 return true;
577}
578
579int running_in_userns(void) {
580 _cleanup_free_ char *line = NULL;
581 int r;
582
583 r = userns_has_mapping("/proc/self/uid_map");
584 if (r != 0)
585 return r;
586
587 r = userns_has_mapping("/proc/self/gid_map");
588 if (r != 0)
589 return r;
590
591 /* "setgroups" file was added in kernel v3.18-rc6-15-g9cc46516dd. It is also
592 * possible to compile a kernel without CONFIG_USER_NS, in which case "setgroups"
593 * also does not exist. We cannot distinguish those two cases, so assume that
594 * we're running on a stripped-down recent kernel, rather than on an old one,
595 * and if the file is not found, return false.
596 */
597 r = read_one_line_file("/proc/self/setgroups", &line);
598 if (r < 0) {
599 log_debug_errno(r, "/proc/self/setgroups: %m");
600 return r == -ENOENT ? false : r;
601 }
602
603 truncate_nl(line);
604 r = streq(line, "deny");
605 /* See user_namespaces(7) for a description of this "setgroups" contents. */
606 log_debug("/proc/self/setgroups contains \"%s\", %s user namespace", line, r ? "in" : "not in");
607 return r;
608}
609
7f4b3c5e 610int running_in_chroot(void) {
ef2a48aa 611 int r;
7f4b3c5e 612
08a28eec
LN
613 if (getenv_bool("SYSTEMD_IGNORE_CHROOT") > 0)
614 return 0;
615
ef2a48aa
ZJS
616 r = files_same("/proc/1/root", "/", 0);
617 if (r < 0)
618 return r;
7f4b3c5e 619
ef2a48aa 620 return r == 0;
7f4b3c5e
LP
621}
622
75f86906
LP
623static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
624 [VIRTUALIZATION_NONE] = "none",
625 [VIRTUALIZATION_KVM] = "kvm",
626 [VIRTUALIZATION_QEMU] = "qemu",
627 [VIRTUALIZATION_BOCHS] = "bochs",
628 [VIRTUALIZATION_XEN] = "xen",
629 [VIRTUALIZATION_UML] = "uml",
630 [VIRTUALIZATION_VMWARE] = "vmware",
631 [VIRTUALIZATION_ORACLE] = "oracle",
632 [VIRTUALIZATION_MICROSOFT] = "microsoft",
633 [VIRTUALIZATION_ZVM] = "zvm",
634 [VIRTUALIZATION_PARALLELS] = "parallels",
aa0c3427 635 [VIRTUALIZATION_BHYVE] = "bhyve",
1fdf07f5 636 [VIRTUALIZATION_QNX] = "qnx",
75f86906
LP
637 [VIRTUALIZATION_VM_OTHER] = "vm-other",
638
639 [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn",
640 [VIRTUALIZATION_LXC_LIBVIRT] = "lxc-libvirt",
641 [VIRTUALIZATION_LXC] = "lxc",
642 [VIRTUALIZATION_OPENVZ] = "openvz",
643 [VIRTUALIZATION_DOCKER] = "docker",
9fb16425 644 [VIRTUALIZATION_RKT] = "rkt",
75f86906
LP
645 [VIRTUALIZATION_CONTAINER_OTHER] = "container-other",
646};
647
648DEFINE_STRING_TABLE_LOOKUP(virtualization, int);