systemd-252-43

Resolves: RHEL-50103,RHEL-50651
This commit is contained in:
Lukas Nykryn 2024-08-22 10:49:16 +02:00
parent a9a01af816
commit 79df79b44e
17 changed files with 2125 additions and 1 deletions

View File

@ -0,0 +1,31 @@
From 366cfe45170487488d33997f832487f8841556c7 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 1 Aug 2023 03:22:57 +0900
Subject: [PATCH] udev-builtin-net_id: skip non-directory entry earlier
In the below, we will try to read 'address' file in the directory,
hence the entry must be a directory.
No functional change, just a tiny optimization.
(cherry picked from commit 4103dca1b5664f937ce125219ca70ea54f810ac8)
Related: RHEL-50103
---
src/udev/udev-builtin-net_id.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index c20df41c37..40f7454ba0 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -441,6 +441,9 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
if (dot_or_dot_dot(de->d_name))
continue;
+ if (de->d_type != DT_DIR)
+ continue;
+
r = safe_atou32(de->d_name, &i);
if (r < 0 || i <= 0)
continue;

View File

@ -0,0 +1,72 @@
From f1dc0bef81dbb101dcc53545accbe680a548d3eb Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 1 Aug 2023 03:25:39 +0900
Subject: [PATCH] udev-builtin-net_id: return earlier when hotplug slot is not
found
Then we can reduce indentation.
No functional change, just refactoring.
(cherry picked from commit 73fb4b20c1f653619286b2e9ce51c19169ccbfc6)
Related: RHEL-50103
---
src/udev/udev-builtin-net_id.c | 45 +++++++++++++++++-----------------
1 file changed, 23 insertions(+), 22 deletions(-)
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 40f7454ba0..5e76a894f7 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -487,28 +487,29 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
rewinddir(dir);
}
- if (hotplug_slot > 0) {
- s = names->pci_slot;
- l = sizeof(names->pci_slot);
- if (domain > 0)
- l = strpcpyf(&s, l, "P%u", domain);
- l = strpcpyf(&s, l, "s%"PRIu32, hotplug_slot);
- if (func > 0 || is_pci_multifunction(names->pcidev) > 0)
- l = strpcpyf(&s, l, "f%u", func);
- if (naming_scheme_has(NAMING_SR_IOV_R) && info->vf_representor_id >= 0)
- /* For VF representor append 'r<VF_NUM>' and not phys_port_name */
- l = strpcpyf(&s, l, "r%d", info->vf_representor_id);
- else if (!isempty(info->phys_port_name))
- l = strpcpyf(&s, l, "n%s", info->phys_port_name);
- else if (dev_port > 0)
- l = strpcpyf(&s, l, "d%lu", dev_port);
- if (l == 0)
- names->pci_slot[0] = '\0';
-
- log_device_debug(dev, "Slot identifier: domain=%u slot=%"PRIu32" func=%u phys_port=%s dev_port=%lu %s %s",
- domain, hotplug_slot, func, strempty(info->phys_port_name), dev_port,
- special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), empty_to_na(names->pci_slot));
- }
+ if (hotplug_slot == 0)
+ return 0;
+
+ s = names->pci_slot;
+ l = sizeof(names->pci_slot);
+ if (domain > 0)
+ l = strpcpyf(&s, l, "P%u", domain);
+ l = strpcpyf(&s, l, "s%"PRIu32, hotplug_slot);
+ if (func > 0 || is_pci_multifunction(names->pcidev) > 0)
+ l = strpcpyf(&s, l, "f%u", func);
+ if (naming_scheme_has(NAMING_SR_IOV_R) && info->vf_representor_id >= 0)
+ /* For VF representor append 'r<VF_NUM>' and not phys_port_name */
+ l = strpcpyf(&s, l, "r%d", info->vf_representor_id);
+ else if (!isempty(info->phys_port_name))
+ l = strpcpyf(&s, l, "n%s", info->phys_port_name);
+ else if (dev_port > 0)
+ l = strpcpyf(&s, l, "d%lu", dev_port);
+ if (l == 0)
+ names->pci_slot[0] = '\0';
+
+ log_device_debug(dev, "Slot identifier: domain=%u slot=%"PRIu32" func=%u phys_port=%s dev_port=%lu %s %s",
+ domain, hotplug_slot, func, strempty(info->phys_port_name), dev_port,
+ special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), empty_to_na(names->pci_slot));
return 0;
}

View File

@ -0,0 +1,237 @@
From 5685910315fb3b6c343db797fef9ef9d6e4ff01e Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 1 Aug 2023 03:27:33 +0900
Subject: [PATCH] udev-builtin-net_id: split-out pci_get_hotplug_slot() and
pci_get_hotplug_slot_from_address()
No functional changes, just refactoring.
(cherry picked from commit f1e3eaa730190a60fdb780be26ee331b8c811e34)
Related: RHEL-50103
---
src/udev/udev-builtin-net_id.c | 199 +++++++++++++++++++--------------
1 file changed, 117 insertions(+), 82 deletions(-)
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 5e76a894f7..16c9971876 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -332,14 +332,121 @@ static int parse_hotplug_slot_from_function_id(sd_device *dev, int slots_dirfd,
return 1;
}
-static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
- const char *sysname, *attr;
+static int pci_get_hotplug_slot_from_address(
+ sd_device *dev,
+ sd_device *pci,
+ DIR *dir,
+ uint32_t *ret) {
+
+ const char *sysname;
+ int r;
+
+ assert(dev);
+ assert(pci);
+ assert(dir);
+ assert(ret);
+
+ r = sd_device_get_sysname(dev, &sysname);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to get sysname: %m");
+
+ rewinddir(dir);
+ FOREACH_DIRENT_ALL(de, dir, break) {
+ _cleanup_free_ char *path = NULL;
+ const char *address;
+ uint32_t slot;
+
+ if (dot_or_dot_dot(de->d_name))
+ continue;
+
+ if (de->d_type != DT_DIR)
+ continue;
+
+ r = safe_atou32(de->d_name, &slot);
+ if (r < 0 || slot <= 0)
+ continue;
+
+ path = path_join("slots", de->d_name, "address");
+ if (!path)
+ return -ENOMEM;
+
+ if (sd_device_get_sysattr_value(pci, path, &address) < 0)
+ continue;
+
+ /* match slot address with device by stripping the function */
+ if (!startswith(sysname, address))
+ continue;
+
+ *ret = slot;
+ return 1; /* found */
+ }
+
+ *ret = 0;
+ return 0; /* not found */
+}
+
+static int pci_get_hotplug_slot(sd_device *dev, uint32_t *ret) {
_cleanup_(sd_device_unrefp) sd_device *pci = NULL;
_cleanup_closedir_ DIR *dir = NULL;
+ int r;
+
+ assert(dev);
+ assert(ret);
+
+ /* ACPI _SUN — slot user number */
+ r = sd_device_new_from_subsystem_sysname(&pci, "subsystem", "pci");
+ if (r < 0)
+ return log_debug_errno(r, "Failed to create sd_device object for pci subsystem: %m");
+
+ r = device_opendir(pci, "slots", &dir);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Cannot open 'slots' subdirectory: %m");
+
+ for (sd_device *slot_dev = dev; slot_dev; ) {
+ uint32_t slot = 0; /* avoid false maybe-uninitialized warning */
+
+ r = parse_hotplug_slot_from_function_id(slot_dev, dirfd(dir), &slot);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ *ret = slot;
+ return 1; /* domain should be ignored. */
+ }
+
+ r = pci_get_hotplug_slot_from_address(slot_dev, pci, dir, &slot);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ /* We found the match between PCI device and slot. However, we won't use the slot
+ * index if the device is a PCI bridge, because it can have other child devices that
+ * will try to claim the same index and that would create name collision. */
+ if (naming_scheme_has(NAMING_BRIDGE_NO_SLOT) && is_pci_bridge(slot_dev)) {
+ if (naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT) && is_pci_multifunction(dev) <= 0)
+ return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ESTALE),
+ "Not using slot information because the PCI device associated with "
+ "the hotplug slot is a bridge and the PCI device has a single function.");
+
+ if (!naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT))
+ return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ESTALE),
+ "Not using slot information because the PCI device is a bridge.");
+ }
+
+ *ret = slot;
+ return 0; /* domain can be still used. */
+ }
+
+ if (sd_device_get_parent_with_subsystem_devtype(slot_dev, "pci", NULL, &slot_dev) < 0)
+ break;
+ }
+
+ return -ENOENT;
+}
+
+static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
+ const char *sysname, *attr;
unsigned domain, bus, slot, func;
- sd_device *hotplug_slot_dev;
unsigned long dev_port = 0;
- uint32_t hotplug_slot = 0;
+ uint32_t hotplug_slot = 0; /* avoid false maybe-uninitialized warning */
size_t l;
char *s;
int r;
@@ -410,85 +517,13 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
domain, bus, slot, func, strempty(info->phys_port_name), dev_port,
special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), empty_to_na(names->pci_path));
- /* ACPI _SUN — slot user number */
- r = sd_device_new_from_subsystem_sysname(&pci, "subsystem", "pci");
- if (r < 0)
- return log_debug_errno(r, "sd_device_new_from_subsystem_sysname() failed: %m");
-
- r = device_opendir(pci, "slots", &dir);
+ r = pci_get_hotplug_slot(names->pcidev, &hotplug_slot);
if (r < 0)
- return log_device_debug_errno(dev, r, "Cannot access 'slots' subdirectory: %m");
-
- hotplug_slot_dev = names->pcidev;
- while (hotplug_slot_dev) {
- r = parse_hotplug_slot_from_function_id(hotplug_slot_dev, dirfd(dir), &hotplug_slot);
- if (r < 0)
- return 0;
- if (r > 0) {
- domain = 0; /* See comments in parse_hotplug_slot_from_function_id(). */
- break;
- }
-
- r = sd_device_get_sysname(hotplug_slot_dev, &sysname);
- if (r < 0)
- return log_device_debug_errno(hotplug_slot_dev, r, "Failed to get sysname: %m");
-
- FOREACH_DIRENT_ALL(de, dir, break) {
- _cleanup_free_ char *path = NULL;
- const char *address;
- uint32_t i;
-
- if (dot_or_dot_dot(de->d_name))
- continue;
-
- if (de->d_type != DT_DIR)
- continue;
-
- r = safe_atou32(de->d_name, &i);
- if (r < 0 || i <= 0)
- continue;
-
- path = path_join("slots", de->d_name, "address");
- if (!path)
- return -ENOMEM;
-
- if (device_get_sysattr_value_filtered(pci, path, &address) < 0)
- continue;
-
- /* match slot address with device by stripping the function */
- if (!startswith(sysname, address))
- continue;
-
- hotplug_slot = i;
-
- /* We found the match between PCI device and slot. However, we won't use the slot
- * index if the device is a PCI bridge, because it can have other child devices that
- * will try to claim the same index and that would create name collision. */
- if (naming_scheme_has(NAMING_BRIDGE_NO_SLOT) && is_pci_bridge(hotplug_slot_dev)) {
- if (naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT) && is_pci_multifunction(names->pcidev) <= 0) {
- log_device_debug(dev,
- "Not using slot information because the PCI device associated with "
- "the hotplug slot is a bridge and the PCI device has a single function.");
- return 0;
- }
-
- if (!naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT)) {
- log_device_debug(dev, "Not using slot information because the PCI device is a bridge.");
- return 0;
- }
- }
-
- break;
- }
- if (hotplug_slot > 0)
- break;
- if (sd_device_get_parent_with_subsystem_devtype(hotplug_slot_dev, "pci", NULL, &hotplug_slot_dev) < 0)
- break;
- rewinddir(dir);
- }
-
- if (hotplug_slot == 0)
- return 0;
+ return r;
+ if (r > 0)
+ /* If the hotplug slot is found through the function ID, then drop the domain from the name.
+ * See comments in parse_hotplug_slot_from_function_id(). */
+ domain = 0;
s = names->pci_slot;
l = sizeof(names->pci_slot);

View File

@ -0,0 +1,170 @@
From 7af151ca282d506a8e409a68b656f6d1cd2f13fb Mon Sep 17 00:00:00 2001
From: Etienne Champetier <e.champetier@ateme.com>
Date: Tue, 9 Jul 2024 11:53:50 -0400
Subject: [PATCH] udev-builtin-net_id: use firmware_node/sun for
ID_NET_NAME_SLOT
pci_get_hotplug_slot() has the following limitations:
- if slots are not hotpluggable, they are not in /sys/bus/pci/slots.
- the address at /sys/bus/pci/slots/X/addr doesn't contains the function part,
so on some system, 2 different slots with different _SUN end up with the same
hotplug_slot, leading to naming conflicts.
- it tries all parent devices until it finds a slot number, which is incorrect,
and what led to NAMING_BRIDGE_MULTIFUNCTION_SLOT being disabled.
The use of PCI hotplug to find the slot (ACPI _SUN) was introduced in
https://github.com/systemd/systemd/commit/0035597a30d120f70df2dd7da3d6128fb8ba6051
"udev: net_id - export PCI hotplug slot names" on 2012/11/26.
At the same time on the kernel side we got
https://github.com/torvalds/linux/commit/bb74ac23b10820d8722c3e1f4add9ef59e703f63
"ACPI: create _SUN sysfs file" on 2012/11/16.
Using PCI hotplug was the only way at the time, but now 12 years later we can use
firmware_node/sun sysfs file.
Looking at a small selection of server HW, for HPE (Gen10 DL325), the _SUN is attached
to the NIC device, whereas for Dell (R640/R6515/R6615) and Cisco (UCSC-C220-M5SX),
the _SUN is on the first parent pcieport.
We still fallback to pci_get_hotplug_slot() to handle the s390 case and
maybe some other coner cases (_SUN on grand parent device that is not a
bridge ?).
(cherry picked from commit 0a4ecc54cb9f2d3418b970c51bfadb69c34ae9eb)
Resolves: RHEL-50103
---
man/systemd.net-naming-scheme.xml | 5 ++-
src/shared/netif-naming-scheme.h | 3 +-
src/udev/udev-builtin-net_id.c | 66 +++++++++++++++++++++++++++----
3 files changed, 64 insertions(+), 10 deletions(-)
diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml
index 83293e5636..c9a7e1e493 100644
--- a/man/systemd.net-naming-scheme.xml
+++ b/man/systemd.net-naming-scheme.xml
@@ -510,9 +510,10 @@
to distinguish between devices. However, name conflict can occur if these devices are not
children of the same PCI bridge, e.g. there are multiple PCI bridges in the same slot.
</para>
+
+ <para>PCI slot number is now read from <constant>firmware_node/sun</constant> sysfs file.</para>
</listitem>
</varlistentry>
-
</variablelist>
<para>By default <constant>rhel-9.0</constant> is used.</para>
@@ -666,7 +667,7 @@ ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
</example>
<example>
- <title>PCI Ethernet card in hotplug slot with firmware index number</title>
+ <title>PCI Ethernet card in slot with firmware index number</title>
<programlisting># /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
ID_NET_NAME_MAC=enx000000000466
diff --git a/src/shared/netif-naming-scheme.h b/src/shared/netif-naming-scheme.h
index 5bc071f8db..b1ac2e4320 100644
--- a/src/shared/netif-naming-scheme.h
+++ b/src/shared/netif-naming-scheme.h
@@ -42,6 +42,7 @@ typedef enum NamingSchemeFlags {
* This is disabled since rhel-9.5, as it seems not to work at least for some setups. See upstream issue #28929. */
NAMING_DEVICETREE_ALIASES = 1 << 15, /* Generate names from devicetree aliases */
NAMING_SR_IOV_R = 1 << 17, /* Use "r" suffix for SR-IOV VF representors */
+ NAMING_FIRMWARE_NODE_SUN = 1 << 18, /* Use firmware_node/sun to get PCI slot number */
/* And now the masks that combine the features above */
NAMING_V238 = 0,
@@ -73,7 +74,7 @@ typedef enum NamingSchemeFlags {
NAMING_RHEL_9_2 = NAMING_RHEL_9_0,
NAMING_RHEL_9_3 = NAMING_RHEL_9_0 | NAMING_SR_IOV_R,
NAMING_RHEL_9_4 = NAMING_RHEL_9_3,
- NAMING_RHEL_9_5 = NAMING_RHEL_9_4 & ~NAMING_BRIDGE_MULTIFUNCTION_SLOT,
+ NAMING_RHEL_9_5 = (NAMING_RHEL_9_4 & ~NAMING_BRIDGE_MULTIFUNCTION_SLOT) | NAMING_FIRMWARE_NODE_SUN,
EXTRA_NET_NAMING_SCHEMES
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 16c9971876..291fb4ba36 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -442,6 +442,51 @@ static int pci_get_hotplug_slot(sd_device *dev, uint32_t *ret) {
return -ENOENT;
}
+static int get_device_firmware_node_sun(sd_device *dev, uint32_t *ret) {
+ const char *attr;
+ int r;
+
+ assert(dev);
+ assert(ret);
+
+ r = device_get_sysattr_value_filtered(dev, "firmware_node/sun", &attr);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to read firmware_node/sun, ignoring: %m");
+
+ r = safe_atou32(attr, ret);
+ if (r < 0)
+ return log_device_warning_errno(dev, r, "Failed to parse firmware_node/sun '%s', ignoring: %m", attr);
+
+ return 0;
+}
+
+static int pci_get_slot_from_firmware_node_sun(sd_device *dev, uint32_t *ret) {
+ int r;
+ sd_device *slot_dev;
+
+ assert(dev);
+ assert(ret);
+
+ /* Try getting the ACPI _SUN for the device */
+ if (get_device_firmware_node_sun(dev, ret) >= 0)
+ return 0;
+
+ r = sd_device_get_parent_with_subsystem_devtype(dev, "pci", NULL, &slot_dev);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to find pci parent, ignoring: %m");
+
+ if (is_pci_bridge(slot_dev) && is_pci_multifunction(dev) <= 0)
+ return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ESTALE),
+ "Not using slot information because the parent pcieport "
+ "is a bridge and the PCI device is not multifunction.");
+
+ /* Try getting the ACPI _SUN from the parent pcieport */
+ if (get_device_firmware_node_sun(slot_dev, ret) >= 0)
+ return 0;
+
+ return -ENOENT;
+}
+
static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
const char *sysname, *attr;
unsigned domain, bus, slot, func;
@@ -517,13 +562,20 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
domain, bus, slot, func, strempty(info->phys_port_name), dev_port,
special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), empty_to_na(names->pci_path));
- r = pci_get_hotplug_slot(names->pcidev, &hotplug_slot);
- if (r < 0)
- return r;
- if (r > 0)
- /* If the hotplug slot is found through the function ID, then drop the domain from the name.
- * See comments in parse_hotplug_slot_from_function_id(). */
- domain = 0;
+ if (naming_scheme_has(NAMING_FIRMWARE_NODE_SUN))
+ r = pci_get_slot_from_firmware_node_sun(names->pcidev, &hotplug_slot);
+ else
+ r = -1;
+ /* If we don't find a slot using firmware_node/sun, fallback to hotplug_slot */
+ if (r < 0) {
+ r = pci_get_hotplug_slot(names->pcidev, &hotplug_slot);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ /* If the hotplug slot is found through the function ID, then drop the domain from the name.
+ * See comments in parse_hotplug_slot_from_function_id(). */
+ domain = 0;
+ }
s = names->pci_slot;
l = sizeof(names->pci_slot);

View File

@ -0,0 +1,343 @@
From 07e0a7f9a4f38e163082af202db0fbc795bc369c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= <crodriguez@owncloud.com>
Date: Tue, 3 Jan 2023 17:52:08 +0000
Subject: [PATCH] Include <threads.h> if possible to get thread_local
definition
IN C23, thread_local is a reserved keyword and we shall therefore
do nothing to redefine it. glibc has it defined for older standard
version with the right conditions.
v2 by Yu Watanabe:
Move the definition to missing_threads.h like the way we define e.g.
missing syscalls or missing definitions, and include it by the users.
Co-authored-by: Yu Watanabe <watanabe.yu+github@gmail.com>
(cherry picked from commit 5545f336fd09148e8d9aa7f83ed19384deaf7a64)
Related: RHEL-50651
---
meson.build | 1 +
src/basic/capability-util.c | 1 +
src/basic/cgroup-util.c | 1 +
src/basic/log.c | 1 +
src/basic/macro.h | 14 --------------
src/basic/memory-util.c | 1 +
src/basic/missing_threads.h | 15 +++++++++++++++
src/basic/process-util.c | 1 +
src/basic/random-util.c | 1 +
src/basic/signal-util.c | 1 +
src/basic/time-util.c | 1 +
src/basic/uid-alloc-range.c | 1 +
src/basic/virt.c | 1 +
src/libsystemd/sd-bus/sd-bus.c | 1 +
src/libsystemd/sd-event/sd-event.c | 1 +
src/libsystemd/sd-id128/sd-id128.c | 1 +
src/libsystemd/sd-journal/journal-file.c | 1 +
src/libsystemd/sd-resolve/sd-resolve.c | 1 +
src/login/logind-inhibit.c | 1 +
src/network/networkd-route-util.c | 1 +
src/nss-systemd/nss-systemd.c | 1 +
src/shared/cgroup-setup.c | 1 +
src/shared/psi-util.c | 1 +
23 files changed, 36 insertions(+), 14 deletions(-)
create mode 100644 src/basic/missing_threads.h
diff --git a/meson.build b/meson.build
index 274e43ba9e..cbde702211 100644
--- a/meson.build
+++ b/meson.build
@@ -745,6 +745,7 @@ foreach header : ['crypt.h',
'linux/memfd.h',
'linux/vm_sockets.h',
'sys/auxv.h',
+ 'threads.h',
'valgrind/memcheck.h',
'valgrind/valgrind.h',
'linux/time_types.h',
diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c
index fa74b5b9c6..df04d461ad 100644
--- a/src/basic/capability-util.c
+++ b/src/basic/capability-util.c
@@ -13,6 +13,7 @@
#include "log.h"
#include "macro.h"
#include "missing_prctl.h"
+#include "missing_threads.h"
#include "parse-util.h"
#include "user-util.h"
#include "util.h"
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index b03cc70e2e..5266f93606 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -23,6 +23,7 @@
#include "login-util.h"
#include "macro.h"
#include "missing_magic.h"
+#include "missing_threads.h"
#include "mkdir.h"
#include "parse-util.h"
#include "path-util.h"
diff --git a/src/basic/log.c b/src/basic/log.c
index 39d08b0928..2e1642dc20 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -23,6 +23,7 @@
#include "log.h"
#include "macro.h"
#include "missing_syscall.h"
+#include "missing_threads.h"
#include "parse-util.h"
#include "proc-cmdline.h"
#include "process-util.h"
diff --git a/src/basic/macro.h b/src/basic/macro.h
index 6893a1ff32..c2934f9951 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -319,20 +319,6 @@ static inline int __coverity_check_and_return__(int condition) {
p != (typeof(p)) POINTER_MAX; \
p = *(++_l))
-/* Define C11 thread_local attribute even on older gcc compiler
- * version */
-#ifndef thread_local
-/*
- * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__
- * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769
- */
-#if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
-#define thread_local _Thread_local
-#else
-#define thread_local __thread
-#endif
-#endif
-
#define _FOREACH_ARRAY(i, array, num, m, end) \
for (typeof(array[0]) *i = (array), *end = ({ \
typeof(num) m = (num); \
diff --git a/src/basic/memory-util.c b/src/basic/memory-util.c
index c4f54c7b4e..fcedae2d41 100644
--- a/src/basic/memory-util.c
+++ b/src/basic/memory-util.c
@@ -3,6 +3,7 @@
#include <unistd.h>
#include "memory-util.h"
+#include "missing_threads.h"
size_t page_size(void) {
static thread_local size_t pgsz = 0;
diff --git a/src/basic/missing_threads.h b/src/basic/missing_threads.h
new file mode 100644
index 0000000000..fb3b72249b
--- /dev/null
+++ b/src/basic/missing_threads.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+/* If threads.h doesn't exist, then define our own thread_local to match C11's thread_local. */
+#if HAVE_THREADS_H
+# include <threads.h>
+#elif !(defined(thread_local))
+/* Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__
+ * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 */
+# if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
+# define thread_local _Thread_local
+# else
+# define thread_local __thread
+# endif
+#endif
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index 0213f5913f..65367768c9 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -34,6 +34,7 @@
#include "memory-util.h"
#include "missing_sched.h"
#include "missing_syscall.h"
+#include "missing_threads.h"
#include "namespace-util.h"
#include "path-util.h"
#include "process-util.h"
diff --git a/src/basic/random-util.c b/src/basic/random-util.c
index d8734cc7d0..200a914196 100644
--- a/src/basic/random-util.c
+++ b/src/basic/random-util.c
@@ -24,6 +24,7 @@
#include "io-util.h"
#include "missing_random.h"
#include "missing_syscall.h"
+#include "missing_threads.h"
#include "parse-util.h"
#include "random-util.h"
#include "sha256.h"
diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c
index b61c18b2de..fdbe7f43ac 100644
--- a/src/basic/signal-util.c
+++ b/src/basic/signal-util.c
@@ -5,6 +5,7 @@
#include "errno-util.h"
#include "macro.h"
+#include "missing_threads.h"
#include "parse-util.h"
#include "signal-util.h"
#include "stdio-util.h"
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 71b2f67350..f5e10bba1a 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -17,6 +17,7 @@
#include "io-util.h"
#include "log.h"
#include "macro.h"
+#include "missing_threads.h"
#include "missing_timerfd.h"
#include "parse-util.h"
#include "path-util.h"
diff --git a/src/basic/uid-alloc-range.c b/src/basic/uid-alloc-range.c
index 1b6d761a66..8b3741e438 100644
--- a/src/basic/uid-alloc-range.c
+++ b/src/basic/uid-alloc-range.c
@@ -3,6 +3,7 @@
#include "chase-symlinks.h"
#include "fd-util.h"
#include "fileio.h"
+#include "missing_threads.h"
#include "string-util.h"
#include "uid-alloc-range.h"
#include "user-util.h"
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 710f0372ea..2a8e696a45 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -16,6 +16,7 @@
#include "fd-util.h"
#include "fileio.h"
#include "macro.h"
+#include "missing_threads.h"
#include "process-util.h"
#include "stat-util.h"
#include "string-table.h"
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index c3a1bae295..10efe53a25 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -37,6 +37,7 @@
#include "macro.h"
#include "memory-util.h"
#include "missing_syscall.h"
+#include "missing_threads.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index cd73cd8bfd..165abfc314 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -19,6 +19,7 @@
#include "macro.h"
#include "memory-util.h"
#include "missing_syscall.h"
+#include "missing_threads.h"
#include "prioq.h"
#include "process-util.h"
#include "set.h"
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index ec53617fce..15177bc3c9 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -14,6 +14,7 @@
#include "io-util.h"
#include "macro.h"
#include "missing_syscall.h"
+#include "missing_threads.h"
#include "random-util.h"
#include "stat-util.h"
#include "user-util.h"
diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c
index 2b66b3caed..e8c9d4dc3d 100644
--- a/src/libsystemd/sd-journal/journal-file.c
+++ b/src/libsystemd/sd-journal/journal-file.c
@@ -25,6 +25,7 @@
#include "journal-file.h"
#include "lookup3.h"
#include "memory-util.h"
+#include "missing_threads.h"
#include "path-util.h"
#include "random-util.h"
#include "set.h"
diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c
index 5362ec0fa8..ba88168f02 100644
--- a/src/libsystemd/sd-resolve/sd-resolve.c
+++ b/src/libsystemd/sd-resolve/sd-resolve.c
@@ -22,6 +22,7 @@
#include "list.h"
#include "memory-util.h"
#include "missing_syscall.h"
+#include "missing_threads.h"
#include "process-util.h"
#include "resolve-private.h"
#include "socket-util.h"
diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c
index 16612ddf18..26caa2b5b5 100644
--- a/src/login/logind-inhibit.c
+++ b/src/login/logind-inhibit.c
@@ -17,6 +17,7 @@
#include "io-util.h"
#include "logind-dbus.h"
#include "logind-inhibit.h"
+#include "missing_threads.h"
#include "mkdir-label.h"
#include "parse-util.h"
#include "path-util.h"
diff --git a/src/network/networkd-route-util.c b/src/network/networkd-route-util.c
index 0366382093..d461aadd65 100644
--- a/src/network/networkd-route-util.c
+++ b/src/network/networkd-route-util.c
@@ -3,6 +3,7 @@
#include <linux/rtnetlink.h>
#include "alloc-util.h"
+#include "missing_threads.h"
#include "networkd-address.h"
#include "networkd-link.h"
#include "networkd-manager.h"
diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c
index 75d749e736..1d6e25399f 100644
--- a/src/nss-systemd/nss-systemd.c
+++ b/src/nss-systemd/nss-systemd.c
@@ -9,6 +9,7 @@
#include "fd-util.h"
#include "log.h"
#include "macro.h"
+#include "missing_threads.h"
#include "nss-systemd.h"
#include "nss-util.h"
#include "pthread-util.h"
diff --git a/src/shared/cgroup-setup.c b/src/shared/cgroup-setup.c
index 2ea83f05d3..65be851014 100644
--- a/src/shared/cgroup-setup.c
+++ b/src/shared/cgroup-setup.c
@@ -8,6 +8,7 @@
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
+#include "missing_threads.h"
#include "mkdir.h"
#include "parse-util.h"
#include "path-util.h"
diff --git a/src/shared/psi-util.c b/src/shared/psi-util.c
index 8bdd0d4a85..c91bbc3013 100644
--- a/src/shared/psi-util.c
+++ b/src/shared/psi-util.c
@@ -8,6 +8,7 @@
#include "extract-word.h"
#include "fd-util.h"
#include "fileio.h"
+#include "missing_threads.h"
#include "parse-util.h"
#include "psi-util.h"
#include "string-util.h"

View File

@ -0,0 +1,395 @@
From 945dd3348084b1cc71721e9ed35041ef37689e49 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Fri, 9 Jun 2023 15:37:18 +0100
Subject: [PATCH] add APIs for detecting confidential virtualization
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This code uses various CPUID checks to be able to identify
* AMD SEV
* AMD SEV-ES
* AMD SEV-SNP
* Intel TDX
On HyperV/Azure, it has special checks for detecting SEV-SNP
since the normal CPUID is blocked.
Related: https://github.com/systemd/systemd/issues/27604
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(cherry picked from commit a577a61625b979f0198e1ed9a527ba48fd78be13)
Related: RHEL-50651
---
src/basic/confidential-virt.c | 293 ++++++++++++++++++++++++++++++++++
src/basic/confidential-virt.h | 25 +++
src/basic/meson.build | 2 +
src/test/test-tables.c | 2 +
4 files changed, 322 insertions(+)
create mode 100644 src/basic/confidential-virt.c
create mode 100644 src/basic/confidential-virt.h
diff --git a/src/basic/confidential-virt.c b/src/basic/confidential-virt.c
new file mode 100644
index 0000000000..3d4e9eac33
--- /dev/null
+++ b/src/basic/confidential-virt.c
@@ -0,0 +1,293 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#if defined(__i386__) || defined(__x86_64__)
+#include <cpuid.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "confidential-virt.h"
+#include "fd-util.h"
+#include "missing_threads.h"
+#include "string-table.h"
+#include "utf8.h"
+
+#define CPUID_PROCESSOR_INFO_AND_FEATURE_BITS UINT32_C(0x1)
+
+/*
+ * AMD64 Architecture Programmers Manual Volume 3:
+ * General-Purpose and System Instructions.
+ * Chapter: E4.1 - Maximum Extended Function Number and Vendor String
+ * https://www.amd.com/system/files/TechDocs/24594.pdf
+ */
+#define CPUID_GET_HIGHEST_FUNCTION UINT32_C(0x80000000)
+
+/*
+ * AMD64 Architecture Programmers Manual Volume 3:
+ * General-Purpose and System Instructions.
+ * Chapter: E4.17 - Encrypted Memory Capabilities
+ * https://www.amd.com/system/files/TechDocs/24594.pdf
+ */
+#define CPUID_AMD_GET_ENCRYPTED_MEMORY_CAPABILITIES UINT32_C(0x8000001f)
+
+/*
+ * AMD64 Architecture Programmers Manual Volume 3:
+ * General-Purpose and System Instructions.
+ * Chapter: 15.34.10 - SEV_STATUS MSR
+ * https://www.amd.com/system/files/TechDocs/24593.pdf
+ */
+#define MSR_AMD64_SEV UINT32_C(0xc0010131)
+
+/*
+ * Intel® TDX Module v1.5 Base Architecture Specification
+ * Chapter: 11.2
+ * https://www.intel.com/content/www/us/en/content-details/733575/intel-tdx-module-v1-5-base-architecture-specification.html
+ */
+
+#define CPUID_INTEL_TDX_ENUMERATION UINT32_C(0x21)
+
+/* Requirements for Implementing the Microsoft Hypervisor Interface
+ * https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/tlfs
+ */
+#define CPUID_HYPERV_VENDOR_AND_MAX_FUNCTIONS UINT32_C(0x40000000)
+
+#define CPUID_HYPERV_FEATURES UINT32_C(0x40000003)
+
+#define CPUID_HYPERV_ISOLATION_CONFIG UINT32_C(0x4000000C)
+
+#define CPUID_HYPERV_MIN UINT32_C(0x40000005)
+#define CPUID_HYPERV_MAX UINT32_C(0x4000ffff)
+
+#define CPUID_SIG_AMD "AuthenticAMD"
+#define CPUID_SIG_INTEL "GenuineIntel"
+#define CPUID_SIG_INTEL_TDX "IntelTDX "
+#define CPUID_SIG_HYPERV "Microsoft Hv"
+
+/* ecx bit 31: set => hyperpvisor, unset => bare metal */
+#define CPUID_FEATURE_HYPERVISOR (UINT32_C(1) << 31)
+
+/* Linux include/asm-generic/hyperv-tlfs.h */
+#define CPUID_HYPERV_CPU_MANAGEMENT (UINT32_C(1) << 12) /* root partition */
+#define CPUID_HYPERV_ISOLATION (UINT32_C(1) << 22) /* confidential VM partition */
+
+#define CPUID_HYPERV_ISOLATION_TYPE_MASK UINT32_C(0xf)
+#define CPUID_HYPERV_ISOLATION_TYPE_SNP 2
+
+#define EAX_SEV (UINT32_C(1) << 1)
+#define MSR_SEV (UINT64_C(1) << 0)
+#define MSR_SEV_ES (UINT64_C(1) << 1)
+#define MSR_SEV_SNP (UINT64_C(1) << 2)
+
+#if defined(__x86_64__)
+
+static void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) {
+ log_debug("CPUID func %" PRIx32 " %" PRIx32, *eax, *ecx);
+ __cpuid_count(*eax, *ecx, *eax, *ebx, *ecx, *edx);
+ log_debug("CPUID result %" PRIx32 " %" PRIx32 " %" PRIx32 " %" PRIx32, *eax, *ebx, *ecx, *edx);
+}
+
+static uint32_t cpuid_leaf(uint32_t eax, char ret_sig[static 13], bool swapped) {
+ /* zero-init as some queries explicitly require subleaf == 0 */
+ uint32_t sig[3] = {};
+
+ if (swapped)
+ cpuid(&eax, &sig[0], &sig[2], &sig[1]);
+ else
+ cpuid(&eax, &sig[0], &sig[1], &sig[2]);
+ memcpy(ret_sig, sig, sizeof(sig));
+ ret_sig[12] = 0; /* \0-terminate the string to make string comparison possible */
+
+ /* In some CI tests ret_sig doesn't contain valid UTF8 and prints garbage to the console */
+ log_debug("CPUID sig '%s'", strna(utf8_is_valid(ret_sig)));
+
+ return eax;
+}
+
+#define MSR_DEVICE "/dev/cpu/0/msr"
+
+static uint64_t msr(uint64_t index) {
+ uint64_t ret;
+ ssize_t rv;
+ _cleanup_close_ int fd = -EBADF;
+
+ fd = open(MSR_DEVICE, O_RDONLY|O_CLOEXEC);
+ if (fd < 0) {
+ log_debug_errno(errno,
+ "Cannot open MSR device %s (index %" PRIu64 "), ignoring: %m",
+ MSR_DEVICE,
+ index);
+ return 0;
+ }
+
+ rv = pread(fd, &ret, sizeof(ret), index);
+ if (rv < 0) {
+ log_debug_errno(errno,
+ "Cannot read MSR device %s (index %" PRIu64 "), ignoring: %m",
+ MSR_DEVICE,
+ index);
+ return 0;
+ } else if (rv != sizeof(ret)) {
+ log_debug("Short read %ld bytes from MSR device %s (index %" PRIu64 "), ignoring",
+ rv,
+ MSR_DEVICE,
+ index);
+ return 0;
+ }
+
+ log_debug("MSR %" PRIu64 " result %" PRIu64 "", index, ret);
+ return ret;
+}
+
+static bool detect_hyperv_sev(void) {
+ uint32_t eax, ebx, ecx, edx, feat;
+ char sig[13] = {};
+
+ feat = cpuid_leaf(CPUID_HYPERV_VENDOR_AND_MAX_FUNCTIONS, sig, false);
+
+ if (feat < CPUID_HYPERV_MIN || feat > CPUID_HYPERV_MAX)
+ return false;
+
+ if (memcmp(sig, CPUID_SIG_HYPERV, sizeof(sig)) != 0)
+ return false;
+
+ log_debug("CPUID is on hyperv");
+ eax = CPUID_HYPERV_FEATURES;
+ ebx = ecx = edx = 0;
+
+ cpuid(&eax, &ebx, &ecx, &edx);
+
+ if (ebx & CPUID_HYPERV_ISOLATION && !(ebx & CPUID_HYPERV_CPU_MANAGEMENT)) {
+
+ eax = CPUID_HYPERV_ISOLATION_CONFIG;
+ ebx = ecx = edx = 0;
+ cpuid(&eax, &ebx, &ecx, &edx);
+
+ if ((ebx & CPUID_HYPERV_ISOLATION_TYPE_MASK) == CPUID_HYPERV_ISOLATION_TYPE_SNP)
+ return true;
+ }
+
+ return false;
+}
+
+static ConfidentialVirtualization detect_sev(void) {
+ uint32_t eax, ebx, ecx, edx;
+ uint64_t msrval;
+
+ eax = CPUID_GET_HIGHEST_FUNCTION;
+ ebx = ecx = edx = 0;
+
+ cpuid(&eax, &ebx, &ecx, &edx);
+
+ if (eax < CPUID_AMD_GET_ENCRYPTED_MEMORY_CAPABILITIES)
+ return CONFIDENTIAL_VIRTUALIZATION_NONE;
+
+ eax = CPUID_AMD_GET_ENCRYPTED_MEMORY_CAPABILITIES;
+ ebx = ecx = edx = 0;
+
+ cpuid(&eax, &ebx, &ecx, &edx);
+
+ /* bit 1 == CPU supports SEV feature
+ *
+ * Note, Azure blocks this CPUID leaf from its SEV-SNP
+ * guests, so we must fallback to trying some HyperV
+ * specific CPUID checks.
+ */
+ if (!(eax & EAX_SEV)) {
+ log_debug("No sev in CPUID, trying hyperv CPUID");
+
+ if (detect_hyperv_sev())
+ return CONFIDENTIAL_VIRTUALIZATION_SEV_SNP;
+
+ log_debug("No hyperv CPUID");
+ return CONFIDENTIAL_VIRTUALIZATION_NONE;
+ }
+
+ msrval = msr(MSR_AMD64_SEV);
+
+ /* Test reverse order, since the SEV-SNP bit implies
+ * the SEV-ES bit, which implies the SEV bit */
+ if (msrval & MSR_SEV_SNP)
+ return CONFIDENTIAL_VIRTUALIZATION_SEV_SNP;
+ if (msrval & MSR_SEV_ES)
+ return CONFIDENTIAL_VIRTUALIZATION_SEV_ES;
+ if (msrval & MSR_SEV)
+ return CONFIDENTIAL_VIRTUALIZATION_SEV;
+
+ return CONFIDENTIAL_VIRTUALIZATION_NONE;
+}
+
+static ConfidentialVirtualization detect_tdx(void) {
+ uint32_t eax, ebx, ecx, edx;
+ char sig[13] = {};
+
+ eax = CPUID_GET_HIGHEST_FUNCTION;
+ ebx = ecx = edx = 0;
+
+ cpuid(&eax, &ebx, &ecx, &edx);
+
+ if (eax < CPUID_INTEL_TDX_ENUMERATION)
+ return CONFIDENTIAL_VIRTUALIZATION_NONE;
+
+ cpuid_leaf(CPUID_INTEL_TDX_ENUMERATION, sig, true);
+
+ if (memcmp(sig, CPUID_SIG_INTEL_TDX, sizeof(sig)) == 0)
+ return CONFIDENTIAL_VIRTUALIZATION_TDX;
+
+ return CONFIDENTIAL_VIRTUALIZATION_NONE;
+}
+
+static bool detect_hypervisor(void) {
+ uint32_t eax, ebx, ecx, edx;
+ bool is_hv;
+
+ eax = CPUID_PROCESSOR_INFO_AND_FEATURE_BITS;
+ ebx = ecx = edx = 0;
+
+ cpuid(&eax, &ebx, &ecx, &edx);
+
+ is_hv = ecx & CPUID_FEATURE_HYPERVISOR;
+
+ log_debug("CPUID is hypervisor: %s", yes_no(is_hv));
+ return is_hv;
+}
+
+ConfidentialVirtualization detect_confidential_virtualization(void) {
+ static thread_local ConfidentialVirtualization cached_found = _CONFIDENTIAL_VIRTUALIZATION_INVALID;
+ char sig[13] = {};
+ ConfidentialVirtualization cv = CONFIDENTIAL_VIRTUALIZATION_NONE;
+
+ if (cached_found >= 0)
+ return cached_found;
+
+ /* Skip everything on bare metal */
+ if (detect_hypervisor()) {
+ cpuid_leaf(0, sig, true);
+
+ if (memcmp(sig, CPUID_SIG_AMD, sizeof(sig)) == 0)
+ cv = detect_sev();
+ else if (memcmp(sig, CPUID_SIG_INTEL, sizeof(sig)) == 0)
+ cv = detect_tdx();
+ }
+
+ cached_found = cv;
+ return cv;
+}
+#else /* ! x86_64 */
+ConfidentialVirtualization detect_confidential_virtualization(void) {
+ log_debug("No confidential virtualization detection on this architecture");
+ return CONFIDENTIAL_VIRTUALIZATION_NONE;
+}
+#endif /* ! x86_64 */
+
+static const char *const confidential_virtualization_table[_CONFIDENTIAL_VIRTUALIZATION_MAX] = {
+ [CONFIDENTIAL_VIRTUALIZATION_NONE] = "none",
+ [CONFIDENTIAL_VIRTUALIZATION_SEV] = "sev",
+ [CONFIDENTIAL_VIRTUALIZATION_SEV_ES] = "sev-es",
+ [CONFIDENTIAL_VIRTUALIZATION_SEV_SNP] = "sev-snp",
+ [CONFIDENTIAL_VIRTUALIZATION_TDX] = "tdx",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(confidential_virtualization, ConfidentialVirtualization);
diff --git a/src/basic/confidential-virt.h b/src/basic/confidential-virt.h
new file mode 100644
index 0000000000..c02f3b2321
--- /dev/null
+++ b/src/basic/confidential-virt.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdbool.h>
+
+#include "errno-list.h"
+#include "macro.h"
+
+typedef enum ConfidentialVirtualization {
+ CONFIDENTIAL_VIRTUALIZATION_NONE = 0,
+
+ CONFIDENTIAL_VIRTUALIZATION_SEV,
+ CONFIDENTIAL_VIRTUALIZATION_SEV_ES,
+ CONFIDENTIAL_VIRTUALIZATION_SEV_SNP,
+ CONFIDENTIAL_VIRTUALIZATION_TDX,
+
+ _CONFIDENTIAL_VIRTUALIZATION_MAX,
+ _CONFIDENTIAL_VIRTUALIZATION_INVALID = -EINVAL,
+ _CONFIDENTIAL_VIRTUALIZATION_ERRNO_MAX = -ERRNO_MAX, /* ensure full range of errno fits into this enum */
+} ConfidentialVirtualization;
+
+ConfidentialVirtualization detect_confidential_virtualization(void);
+
+const char *confidential_virtualization_to_string(ConfidentialVirtualization v) _const_;
+ConfidentialVirtualization confidential_virtualization_from_string(const char *s) _pure_;
diff --git a/src/basic/meson.build b/src/basic/meson.build
index c0f0b07418..11053a5ecd 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -31,6 +31,8 @@ basic_sources = files(
'chattr-util.h',
'conf-files.c',
'conf-files.h',
+ 'confidential-virt.c',
+ 'confidential-virt.h',
'def.h',
'devnum-util.c',
'devnum-util.h',
diff --git a/src/test/test-tables.c b/src/test/test-tables.c
index 30ca1871cb..d47d3d75cc 100644
--- a/src/test/test-tables.c
+++ b/src/test/test-tables.c
@@ -6,6 +6,7 @@
#include "cgroup-util.h"
#include "compress.h"
#include "condition.h"
+#include "confidential-virt.h"
#include "device-private.h"
#include "device.h"
#include "discover-image.h"
@@ -50,6 +51,7 @@ int main(int argc, char **argv) {
test_table(collect_mode, COLLECT_MODE);
test_table(condition_result, CONDITION_RESULT);
test_table(condition_type, CONDITION_TYPE);
+ test_table(confidential_virtualization, CONFIDENTIAL_VIRTUALIZATION);
test_table(device_action, SD_DEVICE_ACTION);
test_table(device_state, DEVICE_STATE);
test_table(dns_over_tls_mode, DNS_OVER_TLS_MODE);

View File

@ -0,0 +1,134 @@
From dfd60d406727c03e5d6390639361aeb4f8a5849a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Fri, 30 Jun 2023 19:07:29 +0100
Subject: [PATCH] detect-virt: add --cvm option
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The --cvm option detects whether the OS is running inside a confidential
virtual machine.
Related: https://github.com/systemd/systemd/issues/27604
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(cherry picked from commit 5e0c61f64d22ed9d4ae53ed94209ed4be25feb30)
Resolves: RHEL-50651
---
man/systemd-detect-virt.xml | 10 ++++++++++
shell-completion/bash/systemd-detect-virt | 2 +-
src/detect-virt/detect-virt.c | 18 ++++++++++++++++++
3 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml
index a8c089d0b5..9b24f061bb 100644
--- a/man/systemd-detect-virt.xml
+++ b/man/systemd-detect-virt.xml
@@ -252,6 +252,16 @@
for more information.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--cvm</option></term>
+
+ <listitem><para>Detect whether invoked in a confidential virtual machine.
+ The result of this detection may be used to disable features that should
+ not be used in confidential VMs. It must not be used to release security
+ sensitive information. The latter must only be released after attestation
+ of the confidential environment.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>-q</option></term>
<term><option>--quiet</option></term>
diff --git a/shell-completion/bash/systemd-detect-virt b/shell-completion/bash/systemd-detect-virt
index 05e44903e0..e67570e674 100644
--- a/shell-completion/bash/systemd-detect-virt
+++ b/shell-completion/bash/systemd-detect-virt
@@ -28,7 +28,7 @@ _systemd_detect_virt() {
local i verb comps
local -A OPTS=(
- [STANDALONE]='-h --help --version -c --container -v --vm -q --quiet
+ [STANDALONE]='-h --help --version -c --container -v --vm -q --quiet --cvm
--private-users'
)
diff --git a/src/detect-virt/detect-virt.c b/src/detect-virt/detect-virt.c
index af2a58b78d..6b470642dd 100644
--- a/src/detect-virt/detect-virt.c
+++ b/src/detect-virt/detect-virt.c
@@ -6,6 +6,7 @@
#include <stdlib.h>
#include "alloc-util.h"
+#include "confidential-virt.h"
#include "main-func.h"
#include "pretty-print.h"
#include "string-table.h"
@@ -19,6 +20,7 @@ static enum {
ONLY_CONTAINER,
ONLY_CHROOT,
ONLY_PRIVATE_USERS,
+ ONLY_CVM,
} arg_mode = ANY_VIRTUALIZATION;
static int help(void) {
@@ -37,6 +39,7 @@ static int help(void) {
" -v --vm Only detect whether we are run in a VM\n"
" -r --chroot Detect whether we are run in a chroot() environment\n"
" --private-users Only detect whether we are running in a user namespace\n"
+ " --cvm Only detect whether we are run in a confidential VM\n"
" -q --quiet Don't output anything, just set return value\n"
" --list List all known and detectable types of virtualization\n"
"\nSee the %s for details.\n",
@@ -52,6 +55,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERSION = 0x100,
ARG_PRIVATE_USERS,
ARG_LIST,
+ ARG_CVM,
};
static const struct option options[] = {
@@ -62,6 +66,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "chroot", no_argument, NULL, 'r' },
{ "private-users", no_argument, NULL, ARG_PRIVATE_USERS },
{ "quiet", no_argument, NULL, 'q' },
+ { "cvm", no_argument, NULL, ARG_CVM },
{ "list", no_argument, NULL, ARG_LIST },
{}
};
@@ -105,6 +110,10 @@ static int parse_argv(int argc, char *argv[]) {
DUMP_STRING_TABLE(virtualization, Virtualization, _VIRTUALIZATION_MAX);
return 0;
+ case ARG_CVM:
+ arg_mode = ONLY_CVM;
+ return 1;
+
case '?':
return -EINVAL;
@@ -122,6 +131,7 @@ static int parse_argv(int argc, char *argv[]) {
static int run(int argc, char *argv[]) {
Virtualization v;
+ ConfidentialVirtualization c;
int r;
/* This is mostly intended to be used for scripts which want
@@ -159,6 +169,14 @@ static int run(int argc, char *argv[]) {
return log_error_errno(r, "Failed to check for user namespace: %m");
return !r;
+ case ONLY_CVM:
+ c = detect_confidential_virtualization();
+ if (c < 0)
+ return log_error_errno(c, "Failed to check for confidential virtualization: %m");
+ if (!arg_quiet)
+ puts(confidential_virtualization_to_string(c));
+ return c == CONFIDENTIAL_VIRTUALIZATION_NONE;
+
case ANY_VIRTUALIZATION:
default:
v = detect_virtualization();

View File

@ -0,0 +1,92 @@
From a7d640fa28095c246b4c648bc6052fd4d091f268 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Fri, 30 Jun 2023 19:07:29 +0100
Subject: [PATCH] detect-virt: add --list-cvm option
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The --list-cvm option reports the known types of confidential virtualization
technology that can be detected.
Related: https://github.com/systemd/systemd/issues/27604
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(cherry picked from commit f460fec91524b6171183e70f03e10ab025bd1f03)
Related: RHEL-50651
---
man/systemd-detect-virt.xml | 6 ++++++
shell-completion/bash/systemd-detect-virt | 2 +-
src/detect-virt/detect-virt.c | 8 ++++++++
3 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml
index 9b24f061bb..5aaff839a4 100644
--- a/man/systemd-detect-virt.xml
+++ b/man/systemd-detect-virt.xml
@@ -276,6 +276,12 @@
<listitem><para>Output all currently known and detectable container and VM environments.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--list-cvm</option></term>
+
+ <listitem><para>Output all currently known and detectable confidential virtualization technologies.</para></listitem>
+ </varlistentry>
+
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
diff --git a/shell-completion/bash/systemd-detect-virt b/shell-completion/bash/systemd-detect-virt
index e67570e674..9ade2af220 100644
--- a/shell-completion/bash/systemd-detect-virt
+++ b/shell-completion/bash/systemd-detect-virt
@@ -29,7 +29,7 @@ _systemd_detect_virt() {
local -A OPTS=(
[STANDALONE]='-h --help --version -c --container -v --vm -q --quiet --cvm
- --private-users'
+ --private-users --list --list-cvm'
)
_init_completion || return
diff --git a/src/detect-virt/detect-virt.c b/src/detect-virt/detect-virt.c
index 6b470642dd..9732e3731f 100644
--- a/src/detect-virt/detect-virt.c
+++ b/src/detect-virt/detect-virt.c
@@ -42,6 +42,8 @@ static int help(void) {
" --cvm Only detect whether we are run in a confidential VM\n"
" -q --quiet Don't output anything, just set return value\n"
" --list List all known and detectable types of virtualization\n"
+ " --list-cvm List all known and detectable types of confidential \n"
+ " virtualization\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
link);
@@ -56,6 +58,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_PRIVATE_USERS,
ARG_LIST,
ARG_CVM,
+ ARG_LIST_CVM,
};
static const struct option options[] = {
@@ -68,6 +71,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "quiet", no_argument, NULL, 'q' },
{ "cvm", no_argument, NULL, ARG_CVM },
{ "list", no_argument, NULL, ARG_LIST },
+ { "list-cvm", no_argument, NULL, ARG_LIST_CVM },
{}
};
@@ -114,6 +118,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_mode = ONLY_CVM;
return 1;
+ case ARG_LIST_CVM:
+ DUMP_STRING_TABLE(confidential_virtualization, ConfidentialVirtualization, _CONFIDENTIAL_VIRTUALIZATION_MAX);
+ return 0;
+
case '?':
return -EINVAL;

View File

@ -0,0 +1,92 @@
From 00cb3bb597a6fb8bf825b79c96945bd051669080 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Fri, 30 Jun 2023 19:01:17 +0100
Subject: [PATCH] unit: add "cvm" option for ConditionSecurity
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The "cvm" flag indicates whether the OS is running inside a confidential
virtual machine.
Related: https://github.com/systemd/systemd/issues/27604
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(cherry picked from commit 95d043b1595e7684163714aae46822b18cef0f65)
Related: RHEL-50651
---
man/systemd.unit.xml | 4 ++--
src/shared/condition.c | 3 +++
src/test/test-condition.c | 9 +++++++++
3 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index d41909bcc6..afa4aea5c9 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -1393,8 +1393,8 @@
security technology is enabled on the system. Currently, the recognized values are
<literal>selinux</literal>, <literal>apparmor</literal>, <literal>tomoyo</literal>,
<literal>ima</literal>, <literal>smack</literal>, <literal>audit</literal>,
- <literal>uefi-secureboot</literal> and <literal>tpm2</literal>. The test may be negated by prepending
- an exclamation mark.</para>
+ <literal>uefi-secureboot</literal>, <literal>tpm2</literal> and <literal>cvm</literal>.
+ The test may be negated by prepending an exclamation mark.</para>
</listitem>
</varlistentry>
diff --git a/src/shared/condition.c b/src/shared/condition.c
index a23d6a3e45..e736b78d8a 100644
--- a/src/shared/condition.c
+++ b/src/shared/condition.c
@@ -23,6 +23,7 @@
#include "cgroup-util.h"
#include "compare-operator.h"
#include "condition.h"
+#include "confidential-virt.h"
#include "cpu-set-util.h"
#include "creds-util.h"
#include "efi-api.h"
@@ -694,6 +695,8 @@ static int condition_test_security(Condition *c, char **env) {
return is_efi_secure_boot();
if (streq(c->parameter, "tpm2"))
return has_tpm2();
+ if (streq(c->parameter, "cvm"))
+ return detect_confidential_virtualization() > 0;
return false;
}
diff --git a/src/test/test-condition.c b/src/test/test-condition.c
index b16e8047c6..0894c4bfdb 100644
--- a/src/test/test-condition.c
+++ b/src/test/test-condition.c
@@ -13,6 +13,7 @@
#include "audit-util.h"
#include "cgroup-util.h"
#include "condition.h"
+#include "confidential-virt.h"
#include "cpu-set-util.h"
#include "efi-loader.h"
#include "env-util.h"
@@ -784,6 +785,12 @@ TEST(condition_test_security) {
assert_se(condition);
assert_se(condition_test(condition, environ) == is_efi_secure_boot());
condition_free(condition);
+
+ condition = condition_new(CONDITION_SECURITY, "cvm", false, false);
+ assert_se(condition);
+ assert_se(condition_test(condition, environ) ==
+ (detect_confidential_virtualization() != CONFIDENTIAL_VIRTUALIZATION_NONE));
+ condition_free(condition);
}
TEST(print_securities) {
@@ -795,6 +802,8 @@ TEST(print_securities) {
log_info("SMACK: %s", yes_no(mac_smack_use()));
log_info("Audit: %s", yes_no(use_audit()));
log_info("UEFI secure boot: %s", yes_no(is_efi_secure_boot()));
+ log_info("Confidential VM: %s", yes_no
+ (detect_confidential_virtualization() != CONFIDENTIAL_VIRTUALIZATION_NONE));
log_info("-------------------------------------------");
}

View File

@ -0,0 +1,105 @@
From 9ebd1d71a61e4e036e65452c1c04516ea58d74b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Mon, 3 Jul 2023 09:53:43 +0100
Subject: [PATCH] dbus: add 'ConfidentialVirtualization' property to manager
object
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This property reports whether the system is running inside a confidential
virtual machine.
Related: https://github.com/systemd/systemd/issues/27604
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(cherry picked from commit 1257274ad8eb0790bc3b56ba68b114c5e1e24713)
Related: RHEL-50651
---
man/org.freedesktop.systemd1.xml | 10 ++++++++++
src/core/dbus-manager.c | 23 +++++++++++++++++++++++
2 files changed, 33 insertions(+)
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index 7ee649f6a7..78781b6ed3 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -293,6 +293,8 @@ node /org/freedesktop/systemd1 {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s Virtualization = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly s ConfidentialVirtualization = '...';
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s Architecture = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s Tainted = '...';
@@ -974,6 +976,8 @@ node /org/freedesktop/systemd1 {
<variablelist class="dbus-property" generated="True" extra-ref="Virtualization"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="ConfidentialVirtualization"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="Architecture"/>
<variablelist class="dbus-property" generated="True" extra-ref="Tainted"/>
@@ -1695,6 +1699,12 @@ node /org/freedesktop/systemd1 {
Note that only the "innermost" virtualization technology is exported here. This detects both
full-machine virtualizations (VMs) and shared-kernel virtualization (containers).</para>
+ <para><varname>ConfidentialVirtualization</varname> contains a short ID string describing the confidential
+ virtualization technology the system runs in. On bare-metal hardware this is the empty string. Otherwise,
+ it contains an identifier such as <literal>sev</literal>, <literal>sev-es</literal>, <literal>sev-snp</literal>,
+ <literal>tdx</literal> and so on. For a full list of IDs see
+ <citerefentry><refentrytitle>systemd-detect-virt</refentrytitle><manvolnum>1</manvolnum></citerefentry></para>.
+
<para><varname>Architecture</varname> contains a short ID string describing the architecture the
systemd instance is running on. This follows the same vocabulary as
<varname>ConditionArchitectures=</varname>.</para>
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 44b1027588..386b319c86 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -12,6 +12,7 @@
#include "bus-get-properties.h"
#include "bus-log-control-api.h"
#include "chase-symlinks.h"
+#include "confidential-virt.h"
#include "data-fd-util.h"
#include "dbus-cgroup.h"
#include "dbus-execute.h"
@@ -91,6 +92,27 @@ static int property_get_virtualization(
v == VIRTUALIZATION_NONE ? NULL : virtualization_to_string(v));
}
+static int property_get_confidential_virtualization(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ConfidentialVirtualization v;
+
+ assert(bus);
+ assert(reply);
+
+ v = detect_confidential_virtualization();
+
+ return sd_bus_message_append(
+ reply, "s",
+ v <= 0 ? NULL : confidential_virtualization_to_string(v));
+}
+
static int property_get_tainted(
sd_bus *bus,
const char *path,
@@ -2785,6 +2807,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("Version", "s", property_get_version, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Features", "s", property_get_features, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Virtualization", "s", property_get_virtualization, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ConfidentialVirtualization", "s", property_get_confidential_virtualization, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Architecture", "s", property_get_architecture, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Tainted", "s", property_get_tainted, 0, SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("FirmwareTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_FIRMWARE]), SD_BUS_VTABLE_PROPERTY_CONST),

View File

@ -0,0 +1,40 @@
From 8e90076fa7503595ebf413ebeb9dff46907e9967 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Mon, 3 Jul 2023 10:20:47 +0100
Subject: [PATCH] core: log detected confidential virtualization type
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Related: https://github.com/systemd/systemd/issues/27604
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(cherry picked from commit 024469ddb99ebbf0e0b0f1d77f763116ca251c5d)
Related: RHEL-50651
---
src/core/main.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/core/main.c b/src/core/main.c
index e7b8e98bca..f230270340 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -32,6 +32,7 @@
#include "cgroup-util.h"
#include "clock-util.h"
#include "conf-parser.h"
+#include "confidential-virt.h"
#include "cpu-set-util.h"
#include "crash-handler.h"
#include "dbus-manager.h"
@@ -2060,6 +2061,10 @@ static void log_execution_mode(bool *ret_first_boot) {
if (v > 0)
log_info("Detected virtualization %s.", virtualization_to_string(v));
+ v = detect_confidential_virtualization();
+ if (v > 0)
+ log_info("Detected confidential virtualization %s.", confidential_virtualization_to_string(v));
+
log_info("Detected architecture %s.", architecture_to_string(uname_architecture()));
if (in_initrd())

View File

@ -0,0 +1,80 @@
From 727b779b866e11834d1d0414d677b29702cadbfa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Mon, 3 Jul 2023 10:21:07 +0100
Subject: [PATCH] core: set SYSTEMD_CONFIDENTIAL_VIRTUALIZATION env for
generators
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This reports the confidential virtualization type that was detected
Related: https://github.com/systemd/systemd/issues/27604
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(cherry picked from commit 0895124572c5a035d45f08cfbcdc0cdd61cead4c)
Related: RHEL-50651
---
man/systemd.generator.xml | 12 ++++++++++++
src/core/manager.c | 11 +++++++++++
2 files changed, 23 insertions(+)
diff --git a/man/systemd.generator.xml b/man/systemd.generator.xml
index 19ec586fa0..b3f19296f9 100644
--- a/man/systemd.generator.xml
+++ b/man/systemd.generator.xml
@@ -185,6 +185,18 @@
<varname>ConditionArchitecture=</varname> in
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><varname>$SYSTEMD_CONFIDENTIAL_VIRTUALIZATION</varname></term>
+
+ <listitem><para>If the service manager is run in a confidential virtualized environment,
+ <varname>$SYSTEMD_CONFIDENTIAL_VIRTUALIZATION</varname> is set to a string that identifies
+ the confidential virtualization hardware technology. If no confidential virtualization is
+ detected this variable will not be set. This data is identical to what
+ <citerefentry><refentrytitle>systemd-detect-virt</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ detects and reports, and uses the same vocabulary of confidential virtualization
+ technology identifiers.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/src/core/manager.c b/src/core/manager.c
index b44c7785cf..daeaa641d7 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -30,6 +30,7 @@
#include "bus-util.h"
#include "clean-ipc.h"
#include "clock-util.h"
+#include "confidential-virt.h"
#include "core-varlink.h"
#include "creds-util.h"
#include "dbus-job.h"
@@ -3706,6 +3707,7 @@ static int manager_run_environment_generators(Manager *m) {
static int build_generator_environment(Manager *m, char ***ret) {
_cleanup_strv_free_ char **nl = NULL;
Virtualization v;
+ ConfidentialVirtualization cv;
int r;
assert(m);
@@ -3754,6 +3756,15 @@ static int build_generator_environment(Manager *m, char ***ret) {
return r;
}
+ cv = detect_confidential_virtualization();
+ if (cv < 0)
+ log_debug_errno(cv, "Failed to detect confidential virtualization, ignoring: %m");
+ else if (cv > 0) {
+ r = strv_env_assign(&nl, "SYSTEMD_CONFIDENTIAL_VIRTUALIZATION", confidential_virtualization_to_string(cv));
+ if (r < 0)
+ return r;
+ }
+
r = strv_env_assign(&nl, "SYSTEMD_ARCHITECTURE", architecture_to_string(uname_architecture()));
if (r < 0)
return r;

View File

@ -0,0 +1,59 @@
From 586b33b02ddc3375181fc37a14b7eb94d3eba796 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Mon, 3 Jul 2023 10:24:30 +0100
Subject: [PATCH] udev: add 'conf-virt' constant for confidential
virtualization tech
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Related: https://github.com/systemd/systemd/issues/27604
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(cherry picked from commit 6e2e83b48734e86992cbbdb329c48cc066cf7c96)
Related: RHEL-50651
---
man/udev.xml | 8 ++++++++
src/udev/udev-rules.c | 3 +++
2 files changed, 11 insertions(+)
diff --git a/man/udev.xml b/man/udev.xml
index 5b096c7ef2..a96400e29d 100644
--- a/man/udev.xml
+++ b/man/udev.xml
@@ -279,6 +279,14 @@
for possible values.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>cvm</literal></term>
+ <listitem>
+ <para>System's confidential virtualization technology. See
+ <citerefentry><refentrytitle>systemd-detect-virt</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ for possible values.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
<para>Unknown keys will never match.</para>
</listitem>
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index 9336ce1cd3..3fcbf818d7 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -6,6 +6,7 @@
#include "architecture.h"
#include "conf-files.h"
#include "conf-parser.h"
+#include "confidential-virt.h"
#include "def.h"
#include "device-private.h"
#include "device-util.h"
@@ -1681,6 +1682,8 @@ static int udev_rule_apply_token_to_event(
val = architecture_to_string(uname_architecture());
else if (streq(k, "virt"))
val = virtualization_to_string(detect_virtualization());
+ else if (streq(k, "cvm"))
+ val = confidential_virtualization_to_string(detect_confidential_virtualization());
else
assert_not_reached();
return token_match_string(token, val);

View File

@ -0,0 +1,76 @@
From 59055cd4f4ce89150dfe6bdadf3a3ced78009b15 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Fri, 2 Aug 2024 16:26:00 +0100
Subject: [PATCH] confidential-virt: split caching of CVM detection into
separate method
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
We have different impls of detect_confidential_virtualization per
architecture. The detection is cached in the x86_64 impl, and as we
add support for more targets, we want to use caching for all. It thus
makes sense to split caching out into an architecture independent
method.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(cherry picked from commit 1c4bd7adcc281af2a2dd40867f64f2ac54a43c7a)
Related: RHEL-50651
---
src/basic/confidential-virt.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/src/basic/confidential-virt.c b/src/basic/confidential-virt.c
index 3d4e9eac33..5c96b449b1 100644
--- a/src/basic/confidential-virt.c
+++ b/src/basic/confidential-virt.c
@@ -254,34 +254,37 @@ static bool detect_hypervisor(void) {
return is_hv;
}
-ConfidentialVirtualization detect_confidential_virtualization(void) {
- static thread_local ConfidentialVirtualization cached_found = _CONFIDENTIAL_VIRTUALIZATION_INVALID;
+static ConfidentialVirtualization detect_confidential_virtualization_impl(void) {
char sig[13] = {};
- ConfidentialVirtualization cv = CONFIDENTIAL_VIRTUALIZATION_NONE;
-
- if (cached_found >= 0)
- return cached_found;
/* Skip everything on bare metal */
if (detect_hypervisor()) {
cpuid_leaf(0, sig, true);
if (memcmp(sig, CPUID_SIG_AMD, sizeof(sig)) == 0)
- cv = detect_sev();
+ return detect_sev();
else if (memcmp(sig, CPUID_SIG_INTEL, sizeof(sig)) == 0)
- cv = detect_tdx();
+ return detect_tdx();
}
- cached_found = cv;
- return cv;
+ return CONFIDENTIAL_VIRTUALIZATION_NONE;
}
#else /* ! x86_64 */
-ConfidentialVirtualization detect_confidential_virtualization(void) {
+static ConfidentialVirtualization detect_confidential_virtualization_impl(void) {
log_debug("No confidential virtualization detection on this architecture");
return CONFIDENTIAL_VIRTUALIZATION_NONE;
}
#endif /* ! x86_64 */
+ConfidentialVirtualization detect_confidential_virtualization(void) {
+ static thread_local ConfidentialVirtualization cached_found = _CONFIDENTIAL_VIRTUALIZATION_INVALID;
+
+ if (cached_found == _CONFIDENTIAL_VIRTUALIZATION_INVALID)
+ cached_found = detect_confidential_virtualization_impl();
+
+ return cached_found;
+}
+
static const char *const confidential_virtualization_table[_CONFIDENTIAL_VIRTUALIZATION_MAX] = {
[CONFIDENTIAL_VIRTUALIZATION_NONE] = "none",
[CONFIDENTIAL_VIRTUALIZATION_SEV] = "sev",

View File

@ -0,0 +1,90 @@
From f47239f3e5aed9d7887aac1b15021f5c63996378 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Fri, 2 Aug 2024 11:03:10 +0100
Subject: [PATCH] confidential-virt: add detection for s390x target
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The s390x platform provides confidential VMs using the "Secure Execution"
technology, which is also referred to as "Protected Virtualization" or
just "prot virt" in Linux / QEMU.
This can be detected through a simple sysfs attribute.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(cherry picked from commit 6c35e0a51cc6a852ce239ea46cd75c133212a68e)
Related: RHEL-50651
---
src/basic/confidential-virt.c | 30 +++++++++++++++++++++++++-----
src/basic/confidential-virt.h | 1 +
2 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/src/basic/confidential-virt.c b/src/basic/confidential-virt.c
index 5c96b449b1..746aa8c313 100644
--- a/src/basic/confidential-virt.c
+++ b/src/basic/confidential-virt.c
@@ -11,6 +11,7 @@
#include "confidential-virt.h"
#include "fd-util.h"
+#include "fileio.h"
#include "missing_threads.h"
#include "string-table.h"
#include "utf8.h"
@@ -269,6 +270,24 @@ static ConfidentialVirtualization detect_confidential_virtualization_impl(void)
return CONFIDENTIAL_VIRTUALIZATION_NONE;
}
+#elif defined(__s390x__)
+static ConfidentialVirtualization detect_confidential_virtualization_impl(void) {
+ _cleanup_free_ char *s = NULL;
+ size_t readsize;
+ int r;
+
+ r = read_full_virtual_file("/sys/firmware/uv/prot_virt_guest", &s, &readsize);
+ if (r < 0) {
+ log_debug_errno(r, "Unable to read /sys/firmware/uv/prot_virt_guest: %m");
+ return CONFIDENTIAL_VIRTUALIZATION_NONE;
+ }
+
+ if (readsize >= 1 && s[0] == '1')
+ return CONFIDENTIAL_VIRTUALIZATION_PROTVIRT;
+
+ return CONFIDENTIAL_VIRTUALIZATION_NONE;
+}
+
#else /* ! x86_64 */
static ConfidentialVirtualization detect_confidential_virtualization_impl(void) {
log_debug("No confidential virtualization detection on this architecture");
@@ -286,11 +305,12 @@ ConfidentialVirtualization detect_confidential_virtualization(void) {
}
static const char *const confidential_virtualization_table[_CONFIDENTIAL_VIRTUALIZATION_MAX] = {
- [CONFIDENTIAL_VIRTUALIZATION_NONE] = "none",
- [CONFIDENTIAL_VIRTUALIZATION_SEV] = "sev",
- [CONFIDENTIAL_VIRTUALIZATION_SEV_ES] = "sev-es",
- [CONFIDENTIAL_VIRTUALIZATION_SEV_SNP] = "sev-snp",
- [CONFIDENTIAL_VIRTUALIZATION_TDX] = "tdx",
+ [CONFIDENTIAL_VIRTUALIZATION_NONE] = "none",
+ [CONFIDENTIAL_VIRTUALIZATION_SEV] = "sev",
+ [CONFIDENTIAL_VIRTUALIZATION_SEV_ES] = "sev-es",
+ [CONFIDENTIAL_VIRTUALIZATION_SEV_SNP] = "sev-snp",
+ [CONFIDENTIAL_VIRTUALIZATION_TDX] = "tdx",
+ [CONFIDENTIAL_VIRTUALIZATION_PROTVIRT] = "protvirt",
};
DEFINE_STRING_TABLE_LOOKUP(confidential_virtualization, ConfidentialVirtualization);
diff --git a/src/basic/confidential-virt.h b/src/basic/confidential-virt.h
index c02f3b2321..f92e3e883d 100644
--- a/src/basic/confidential-virt.h
+++ b/src/basic/confidential-virt.h
@@ -13,6 +13,7 @@ typedef enum ConfidentialVirtualization {
CONFIDENTIAL_VIRTUALIZATION_SEV_ES,
CONFIDENTIAL_VIRTUALIZATION_SEV_SNP,
CONFIDENTIAL_VIRTUALIZATION_TDX,
+ CONFIDENTIAL_VIRTUALIZATION_PROTVIRT,
_CONFIDENTIAL_VIRTUALIZATION_MAX,
_CONFIDENTIAL_VIRTUALIZATION_INVALID = -EINVAL,

View File

@ -0,0 +1,74 @@
From 11992ca0dbeb077dbf4c033fe8a19a1ef19d7e57 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Fri, 2 Aug 2024 13:17:56 +0100
Subject: [PATCH] man/systemd-detect-virt: list known CVM technologies
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add a section which lists the known confidential virtual machine
technologies.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(cherry picked from commit a8fb5d21fd6127a6d05757c793cc9ba47f65c893)
Related: RHEL-50651
---
man/systemd-detect-virt.xml | 44 +++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml
index 5aaff839a4..428c5a86fa 100644
--- a/man/systemd-detect-virt.xml
+++ b/man/systemd-detect-virt.xml
@@ -207,6 +207,50 @@
WSL is categorized as a container for practical purposes.
Multiple WSL environments share the same kernel and services
should generally behave like when being run in a container.</para>
+
+ <para>When executed with <option>--cvm</option>, instead of
+ printing the virtualization technology, it will display the
+ confidential virtual machine technology, if any. The
+ following technologies are currently identified:</para>
+
+ <table>
+ <title>Known confidential virtualization technologies</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname="id" />
+ <colspec colname="product" />
+ <thead>
+ <row>
+ <entry>Arch</entry>
+ <entry>ID</entry>
+ <entry>Technology</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry valign="top" morerows="3">x86_64</entry>
+ <entry><varname>sev</varname></entry>
+ <entry>AMD Secure Encrypted Virtualization</entry>
+ </row>
+ <row>
+ <entry><varname>sev-es</varname></entry>
+ <entry>AMD Secure Encrypted Virtualization - Encrypted State</entry>
+ </row>
+ <row>
+ <entry><varname>sev-snp</varname></entry>
+ <entry>AMD Secure Encrypted Virtualization - Secure Nested Paging</entry>
+ </row>
+ <row>
+ <entry><varname>tdx</varname></entry>
+ <entry>Intel Trust Domain Extensions</entry>
+ </row>
+ <row>
+ <entry>s390x</entry>
+ <entry><varname>protvirt</varname></entry>
+ <entry>IBM Protected Virtualization (Secure Execution)</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
</refsect1>
<refsect1>

View File

@ -25,7 +25,7 @@
Name: systemd
Url: https://systemd.io
Version: 252
Release: 42%{?dist}
Release: 43%{?dist}
# For a breakdown of the licensing, see README
License: LGPLv2+ and MIT and GPLv2+
Summary: System and Service Manager
@ -1109,6 +1109,22 @@ Patch1017: 1017-add-udev-rules-for-trezor-hw-wallet-devices.patch
Patch1018: 1018-hwdb-add-axis-range-corrections-for-the-Lenovo-Think.patch
Patch1019: 1019-hwdb-fix-auto-rotate-on-Asus-Q551LB-33921.patch
Patch1020: 1020-udev-add-hwdb-execution-for-hidraw-subsystem-devices.patch
Patch1021: 1021-udev-builtin-net_id-skip-non-directory-entry-earlier.patch
Patch1022: 1022-udev-builtin-net_id-return-earlier-when-hotplug-slot.patch
Patch1023: 1023-udev-builtin-net_id-split-out-pci_get_hotplug_slot-a.patch
Patch1024: 1024-udev-builtin-net_id-use-firmware_node-sun-for-ID_NET.patch
Patch1025: 1025-Include-threads.h-if-possible-to-get-thread_local-de.patch
Patch1026: 1026-add-APIs-for-detecting-confidential-virtualization.patch
Patch1027: 1027-detect-virt-add-cvm-option.patch
Patch1028: 1028-detect-virt-add-list-cvm-option.patch
Patch1029: 1029-unit-add-cvm-option-for-ConditionSecurity.patch
Patch1030: 1030-dbus-add-ConfidentialVirtualization-property-to-mana.patch
Patch1031: 1031-core-log-detected-confidential-virtualization-type.patch
Patch1032: 1032-core-set-SYSTEMD_CONFIDENTIAL_VIRTUALIZATION-env-for.patch
Patch1033: 1033-udev-add-conf-virt-constant-for-confidential-virtual.patch
Patch1034: 1034-confidential-virt-split-caching-of-CVM-detection-int.patch
Patch1035: 1035-confidential-virt-add-detection-for-s390x-target.patch
Patch1036: 1036-man-systemd-detect-virt-list-known-CVM-technologies.patch
# Downstream-only patches (90009999)
@ -1991,6 +2007,24 @@ systemd-hwdb update &>/dev/null || :
%{_prefix}/lib/dracut/modules.d/70rhel-net-naming-sysattrs/*
%changelog
* Thu Aug 22 2024 systemd maintenance team <systemd-maint@redhat.com> - 252-43
- udev-builtin-net_id: skip non-directory entry earlier (RHEL-50103)
- udev-builtin-net_id: return earlier when hotplug slot is not found (RHEL-50103)
- udev-builtin-net_id: split-out pci_get_hotplug_slot() and pci_get_hotplug_slot_from_address() (RHEL-50103)
- udev-builtin-net_id: use firmware_node/sun for ID_NET_NAME_SLOT (RHEL-50103)
- Include <threads.h> if possible to get thread_local definition (RHEL-50651)
- add APIs for detecting confidential virtualization (RHEL-50651)
- detect-virt: add --cvm option (RHEL-50651)
- detect-virt: add --list-cvm option (RHEL-50651)
- unit: add "cvm" option for ConditionSecurity (RHEL-50651)
- dbus: add 'ConfidentialVirtualization' property to manager object (RHEL-50651)
- core: log detected confidential virtualization type (RHEL-50651)
- core: set SYSTEMD_CONFIDENTIAL_VIRTUALIZATION env for generators (RHEL-50651)
- udev: add 'conf-virt' constant for confidential virtualization tech (RHEL-50651)
- confidential-virt: split caching of CVM detection into separate method (RHEL-50651)
- confidential-virt: add detection for s390x target (RHEL-50651)
- man/systemd-detect-virt: list known CVM technologies (RHEL-50651)
* Mon Aug 19 2024 systemd team <systemd-maint@redhat.com>
- fix applying patches