diff --git a/1021-udev-builtin-net_id-skip-non-directory-entry-earlier.patch b/1021-udev-builtin-net_id-skip-non-directory-entry-earlier.patch new file mode 100644 index 0000000..ae6ffd6 --- /dev/null +++ b/1021-udev-builtin-net_id-skip-non-directory-entry-earlier.patch @@ -0,0 +1,31 @@ +From 366cfe45170487488d33997f832487f8841556c7 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +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; diff --git a/1022-udev-builtin-net_id-return-earlier-when-hotplug-slot.patch b/1022-udev-builtin-net_id-return-earlier-when-hotplug-slot.patch new file mode 100644 index 0000000..f2888bc --- /dev/null +++ b/1022-udev-builtin-net_id-return-earlier-when-hotplug-slot.patch @@ -0,0 +1,72 @@ +From f1dc0bef81dbb101dcc53545accbe680a548d3eb Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +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' 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' 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; + } diff --git a/1023-udev-builtin-net_id-split-out-pci_get_hotplug_slot-a.patch b/1023-udev-builtin-net_id-split-out-pci_get_hotplug_slot-a.patch new file mode 100644 index 0000000..4fee4f9 --- /dev/null +++ b/1023-udev-builtin-net_id-split-out-pci_get_hotplug_slot-a.patch @@ -0,0 +1,237 @@ +From 5685910315fb3b6c343db797fef9ef9d6e4ff01e Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +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); diff --git a/1024-udev-builtin-net_id-use-firmware_node-sun-for-ID_NET.patch b/1024-udev-builtin-net_id-use-firmware_node-sun-for-ID_NET.patch new file mode 100644 index 0000000..1776467 --- /dev/null +++ b/1024-udev-builtin-net_id-use-firmware_node-sun-for-ID_NET.patch @@ -0,0 +1,170 @@ +From 7af151ca282d506a8e409a68b656f6d1cd2f13fb Mon Sep 17 00:00:00 2001 +From: Etienne Champetier +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. + ++ ++ PCI slot number is now read from firmware_node/sun sysfs file. + + +- + + + By default rhel-9.0 is used. +@@ -666,7 +667,7 @@ ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1 + + + +- PCI Ethernet card in hotplug slot with firmware index number ++ PCI Ethernet card in slot with firmware index number + + # /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); diff --git a/1025-Include-threads.h-if-possible-to-get-thread_local-de.patch b/1025-Include-threads.h-if-possible-to-get-thread_local-de.patch new file mode 100644 index 0000000..d2716f1 --- /dev/null +++ b/1025-Include-threads.h-if-possible-to-get-thread_local-de.patch @@ -0,0 +1,343 @@ +From 07e0a7f9a4f38e163082af202db0fbc795bc369c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Tue, 3 Jan 2023 17:52:08 +0000 +Subject: [PATCH] Include 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 +(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 + + #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 ++#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 + + #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" diff --git a/1026-add-APIs-for-detecting-confidential-virtualization.patch b/1026-add-APIs-for-detecting-confidential-virtualization.patch new file mode 100644 index 0000000..f900ed9 --- /dev/null +++ b/1026-add-APIs-for-detecting-confidential-virtualization.patch @@ -0,0 +1,395 @@ +From 945dd3348084b1cc71721e9ed35041ef37689e49 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +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é +(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 ++#endif ++#include ++#include ++#include ++#include ++#include ++ ++#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 Programmer’s 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 Programmer’s 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 Programmer’s 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 ++ ++#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); diff --git a/1027-detect-virt-add-cvm-option.patch b/1027-detect-virt-add-cvm-option.patch new file mode 100644 index 0000000..35edbc3 --- /dev/null +++ b/1027-detect-virt-add-cvm-option.patch @@ -0,0 +1,134 @@ +From dfd60d406727c03e5d6390639361aeb4f8a5849a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +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é +(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. + + ++ ++ ++ ++ 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. ++ ++ + + + +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 + + #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(); diff --git a/1028-detect-virt-add-list-cvm-option.patch b/1028-detect-virt-add-list-cvm-option.patch new file mode 100644 index 0000000..eb26ae6 --- /dev/null +++ b/1028-detect-virt-add-list-cvm-option.patch @@ -0,0 +1,92 @@ +From a7d640fa28095c246b4c648bc6052fd4d091f268 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +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é +(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 @@ + Output all currently known and detectable container and VM environments. + + ++ ++ ++ ++ Output all currently known and detectable confidential virtualization technologies. ++ ++ + + + +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; + diff --git a/1029-unit-add-cvm-option-for-ConditionSecurity.patch b/1029-unit-add-cvm-option-for-ConditionSecurity.patch new file mode 100644 index 0000000..f76f75a --- /dev/null +++ b/1029-unit-add-cvm-option-for-ConditionSecurity.patch @@ -0,0 +1,92 @@ +From 00cb3bb597a6fb8bf825b79c96945bd051669080 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +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é +(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 + selinux, apparmor, tomoyo, + ima, smack, audit, +- uefi-secureboot and tpm2. The test may be negated by prepending +- an exclamation mark. ++ uefi-secureboot, tpm2 and cvm. ++ The test may be negated by prepending an exclamation mark. + + + +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("-------------------------------------------"); + } + diff --git a/1030-dbus-add-ConfidentialVirtualization-property-to-mana.patch b/1030-dbus-add-ConfidentialVirtualization-property-to-mana.patch new file mode 100644 index 0000000..b76f526 --- /dev/null +++ b/1030-dbus-add-ConfidentialVirtualization-property-to-mana.patch @@ -0,0 +1,105 @@ +From 9ebd1d71a61e4e036e65452c1c04516ea58d74b7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +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é +(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 { + + + ++ ++ + + + +@@ -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). + ++ ConfidentialVirtualization 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 sev, sev-es, sev-snp, ++ tdx and so on. For a full list of IDs see ++ systemd-detect-virt1. ++ + Architecture contains a short ID string describing the architecture the + systemd instance is running on. This follows the same vocabulary as + ConditionArchitectures=. +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), diff --git a/1031-core-log-detected-confidential-virtualization-type.patch b/1031-core-log-detected-confidential-virtualization-type.patch new file mode 100644 index 0000000..8eaf10b --- /dev/null +++ b/1031-core-log-detected-confidential-virtualization-type.patch @@ -0,0 +1,40 @@ +From 8e90076fa7503595ebf413ebeb9dff46907e9967 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +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é +(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()) diff --git a/1032-core-set-SYSTEMD_CONFIDENTIAL_VIRTUALIZATION-env-for.patch b/1032-core-set-SYSTEMD_CONFIDENTIAL_VIRTUALIZATION-env-for.patch new file mode 100644 index 0000000..6c71c97 --- /dev/null +++ b/1032-core-set-SYSTEMD_CONFIDENTIAL_VIRTUALIZATION-env-for.patch @@ -0,0 +1,80 @@ +From 727b779b866e11834d1d0414d677b29702cadbfa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +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é +(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 @@ + ConditionArchitecture= in + systemd.unit5. + ++ ++ ++ $SYSTEMD_CONFIDENTIAL_VIRTUALIZATION ++ ++ If the service manager is run in a confidential virtualized environment, ++ $SYSTEMD_CONFIDENTIAL_VIRTUALIZATION 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 ++ systemd-detect-virt1 ++ detects and reports, and uses the same vocabulary of confidential virtualization ++ technology identifiers. ++ + + + +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; diff --git a/1033-udev-add-conf-virt-constant-for-confidential-virtual.patch b/1033-udev-add-conf-virt-constant-for-confidential-virtual.patch new file mode 100644 index 0000000..f9913da --- /dev/null +++ b/1033-udev-add-conf-virt-constant-for-confidential-virtual.patch @@ -0,0 +1,59 @@ +From 586b33b02ddc3375181fc37a14b7eb94d3eba796 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +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é +(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. + + ++ ++ cvm ++ ++ System's confidential virtualization technology. See ++ systemd-detect-virt1 ++ for possible values. ++ ++ + + Unknown keys will never match. + +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); diff --git a/1034-confidential-virt-split-caching-of-CVM-detection-int.patch b/1034-confidential-virt-split-caching-of-CVM-detection-int.patch new file mode 100644 index 0000000..7df7304 --- /dev/null +++ b/1034-confidential-virt-split-caching-of-CVM-detection-int.patch @@ -0,0 +1,76 @@ +From 59055cd4f4ce89150dfe6bdadf3a3ced78009b15 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +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é +(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", diff --git a/1035-confidential-virt-add-detection-for-s390x-target.patch b/1035-confidential-virt-add-detection-for-s390x-target.patch new file mode 100644 index 0000000..52b9470 --- /dev/null +++ b/1035-confidential-virt-add-detection-for-s390x-target.patch @@ -0,0 +1,90 @@ +From f47239f3e5aed9d7887aac1b15021f5c63996378 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +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é +(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, diff --git a/1036-man-systemd-detect-virt-list-known-CVM-technologies.patch b/1036-man-systemd-detect-virt-list-known-CVM-technologies.patch new file mode 100644 index 0000000..0d66e22 --- /dev/null +++ b/1036-man-systemd-detect-virt-list-known-CVM-technologies.patch @@ -0,0 +1,74 @@ +From 11992ca0dbeb077dbf4c033fe8a19a1ef19d7e57 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +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é +(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. ++ ++ When executed with , instead of ++ printing the virtualization technology, it will display the ++ confidential virtual machine technology, if any. The ++ following technologies are currently identified: ++ ++ ++ Known confidential virtualization technologies ++ ++ ++ ++ ++ ++ Arch ++ ID ++ Technology ++ ++ ++ ++ ++ x86_64 ++ sev ++ AMD Secure Encrypted Virtualization ++ ++ ++ sev-es ++ AMD Secure Encrypted Virtualization - Encrypted State ++ ++ ++ sev-snp ++ AMD Secure Encrypted Virtualization - Secure Nested Paging ++ ++ ++ tdx ++ Intel Trust Domain Extensions ++ ++ ++ s390x ++ protvirt ++ IBM Protected Virtualization (Secure Execution) ++ ++ ++ ++
+ + + diff --git a/systemd.spec b/systemd.spec index d81df10..c256ef7 100644 --- a/systemd.spec +++ b/systemd.spec @@ -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 (9000–9999) @@ -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 - 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 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 - fix applying patches