From 0acda3abb713d13ee9c7778766a1fff5bbfdd87e Mon Sep 17 00:00:00 2001
From: Daniel Baumann <daniel.baumann@progress-linux.org>
Date: Mon, 16 Sep 2024 20:27:01 +0200
Subject: Merging upstream version 256.5.

Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
---
 src/basic/cgroup-util.c       | 10 ++++++-
 src/basic/confidential-virt.c | 66 ++++++++++++++++++++++++++++++-------------
 src/basic/confidential-virt.h |  1 +
 src/basic/hexdecoct.c         | 18 ++++++------
 src/basic/log.c               | 11 +++++---
 src/basic/log.h               | 16 ++++++++---
 6 files changed, 85 insertions(+), 37 deletions(-)

(limited to 'src/basic')

diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 553ee60..b0fe0ec 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -149,7 +149,9 @@ int cg_read_pidref(FILE *f, PidRef *ret, CGroupFlags flags) {
                 if (pid == 0)
                         return -EREMOTE;
 
-                if (FLAGS_SET(flags, CGROUP_NO_PIDFD)) {
+                /* We might read kernel thread pids from cgroup.procs for which we cannot create a pidfd so
+                 * catch those and don't try to create a pidfd for them. */
+                if (FLAGS_SET(flags, CGROUP_NO_PIDFD) || pid_is_kernel_thread(pid) > 0) {
                         *ret = PIDREF_MAKE_FROM_PID(pid);
                         return 1;
                 }
@@ -369,6 +371,12 @@ static int cg_kill_items(
                         if (set_get(s, PID_TO_PTR(pidref.pid)) == PID_TO_PTR(pidref.pid))
                                 continue;
 
+                        /* Ignore kernel threads to mimick the behavior of cgroup.kill. */
+                        if (pidref_is_kernel_thread(&pidref) > 0) {
+                                log_debug("Ignoring kernel thread with pid " PID_FMT " in cgroup '%s'", pidref.pid, path);
+                                continue;
+                        }
+
                         if (log_kill)
                                 ret_log_kill = log_kill(&pidref, sig, userdata);
 
diff --git a/src/basic/confidential-virt.c b/src/basic/confidential-virt.c
index b6521cf..c246636 100644
--- a/src/basic/confidential-virt.c
+++ b/src/basic/confidential-virt.c
@@ -11,6 +11,7 @@
 #include "confidential-virt-fundamental.h"
 #include "confidential-virt.h"
 #include "fd-util.h"
+#include "fileio.h"
 #include "missing_threads.h"
 #include "string-table.h"
 #include "utf8.h"
@@ -76,7 +77,7 @@ static uint64_t msr(uint64_t index) {
         return ret;
 }
 
-static bool detect_hyperv_sev(void) {
+static bool detect_hyperv_cvm(uint32_t isoltype) {
         uint32_t eax, ebx, ecx, edx, feat;
         char sig[13] = {};
 
@@ -100,7 +101,7 @@ static bool detect_hyperv_sev(void) {
                 ebx = ecx = edx = 0;
                 cpuid(&eax, &ebx, &ecx, &edx);
 
-                if ((ebx & CPUID_HYPERV_ISOLATION_TYPE_MASK) == CPUID_HYPERV_ISOLATION_TYPE_SNP)
+                if ((ebx & CPUID_HYPERV_ISOLATION_TYPE_MASK) == isoltype)
                         return true;
         }
 
@@ -133,7 +134,7 @@ static ConfidentialVirtualization detect_sev(void) {
         if (!(eax & EAX_SEV)) {
                 log_debug("No sev in CPUID, trying hyperv CPUID");
 
-                if (detect_hyperv_sev())
+                if (detect_hyperv_cvm(CPUID_HYPERV_ISOLATION_TYPE_SNP))
                         return CONFIDENTIAL_VIRTUALIZATION_SEV_SNP;
 
                 log_debug("No hyperv CPUID");
@@ -171,6 +172,11 @@ static ConfidentialVirtualization detect_tdx(void) {
         if (memcmp(sig, CPUID_SIG_INTEL_TDX, sizeof(sig)) == 0)
                 return CONFIDENTIAL_VIRTUALIZATION_TDX;
 
+        log_debug("No tdx in CPUID, trying hyperv CPUID");
+
+        if (detect_hyperv_cvm(CPUID_HYPERV_ISOLATION_TYPE_TDX))
+                return CONFIDENTIAL_VIRTUALIZATION_TDX;
+
         return CONFIDENTIAL_VIRTUALIZATION_NONE;
 }
 
@@ -189,40 +195,62 @@ 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;
 }
+#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 */
-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",
-        [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 c02f3b2..f92e3e8 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/src/basic/hexdecoct.c b/src/basic/hexdecoct.c
index 4cb67d9..e02aa9e 100644
--- a/src/basic/hexdecoct.c
+++ b/src/basic/hexdecoct.c
@@ -36,7 +36,7 @@ int undecchar(char c) {
 }
 
 char hexchar(int x) {
-        static const char table[16] = "0123456789abcdef";
+        static const char table[] = "0123456789abcdef";
 
         return table[x & 15];
 }
@@ -168,8 +168,8 @@ int unhexmem_full(
  * useful when representing NSEC3 hashes, as one can then verify the
  * order of hashes directly from their representation. */
 char base32hexchar(int x) {
-        static const char table[32] = "0123456789"
-                                      "ABCDEFGHIJKLMNOPQRSTUV";
+        static const char table[] = "0123456789"
+                                    "ABCDEFGHIJKLMNOPQRSTUV";
 
         return table[x & 31];
 }
@@ -519,9 +519,9 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l
 
 /* https://tools.ietf.org/html/rfc4648#section-4 */
 char base64char(int x) {
-        static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                                      "abcdefghijklmnopqrstuvwxyz"
-                                      "0123456789+/";
+        static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                    "abcdefghijklmnopqrstuvwxyz"
+                                    "0123456789+/";
         return table[x & 63];
 }
 
@@ -529,9 +529,9 @@ char base64char(int x) {
  * since we don't want "/" appear in interface names (since interfaces appear in sysfs as filenames).
  * See section #5 of RFC 4648. */
 char urlsafe_base64char(int x) {
-        static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                                      "abcdefghijklmnopqrstuvwxyz"
-                                      "0123456789-_";
+        static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                    "abcdefghijklmnopqrstuvwxyz"
+                                    "0123456789-_";
         return table[x & 63];
 }
 
diff --git a/src/basic/log.c b/src/basic/log.c
index 13ad19a..2675d59 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -395,9 +395,10 @@ void log_forget_fds(void) {
         console_fd_is_tty = -1;
 }
 
-void log_set_max_level(int level) {
+int log_set_max_level(int level) {
         assert(level == LOG_NULL || LOG_PRI(level) == level);
 
+        int old = log_max_level;
         log_max_level = level;
 
         /* Also propagate max log level to libc's syslog(), just in case some other component loaded into our
@@ -410,6 +411,8 @@ void log_set_max_level(int level) {
 
         /* Ensure that our own LOG_NULL define maps sanely to the log mask */
         assert_cc(LOG_UPTO(LOG_NULL) == 0);
+
+        return old;
 }
 
 void log_set_facility(int facility) {
@@ -743,7 +746,7 @@ static int write_to_journal(
         if (LOG_PRI(level) > log_target_max_level[LOG_TARGET_JOURNAL])
                 return 0;
 
-        iovec_len = MIN(6 + _log_context_num_fields * 2, IOVEC_MAX);
+        iovec_len = MIN(6 + _log_context_num_fields * 3, IOVEC_MAX);
         iovec = newa(struct iovec, iovec_len);
 
         log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra);
@@ -1095,7 +1098,7 @@ int log_struct_internal(
                         int r;
                         bool fallback = false;
 
-                        iovec_len = MIN(17 + _log_context_num_fields * 2, IOVEC_MAX);
+                        iovec_len = MIN(17 + _log_context_num_fields * 3, IOVEC_MAX);
                         iovec = newa(struct iovec, iovec_len);
 
                         /* If the journal is available do structured logging.
@@ -1192,7 +1195,7 @@ int log_struct_iovec_internal(
                 struct iovec *iovec;
                 size_t n = 0, iovec_len;
 
-                iovec_len = MIN(1 + n_input_iovec * 2 + _log_context_num_fields * 2, IOVEC_MAX);
+                iovec_len = MIN(1 + n_input_iovec * 2 + _log_context_num_fields * 3, IOVEC_MAX);
                 iovec = newa(struct iovec, iovec_len);
 
                 log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
diff --git a/src/basic/log.h b/src/basic/log.h
index 726f035..4543556 100644
--- a/src/basic/log.h
+++ b/src/basic/log.h
@@ -35,9 +35,8 @@ typedef enum LogTarget{
  * used as a regular log level. */
 #define LOG_NULL (LOG_EMERG - 1)
 
-/* Note to readers: << and >> have lower precedence (are evaluated earlier) than & and | */
-#define SYNTHETIC_ERRNO(num)                (1 << 30 | (num))
-#define IS_SYNTHETIC_ERRNO(val)             ((val) >> 30 & 1)
+#define SYNTHETIC_ERRNO(num)                (abs(num) | (1 << 30))
+#define IS_SYNTHETIC_ERRNO(val)             (((val) >> 30) == 1)
 #define ERRNO_VALUE(val)                    (abs(val) & ~(1 << 30))
 
 /* The callback function to be invoked when syntax warnings are seen
@@ -57,7 +56,7 @@ int log_set_target_from_string(const char *e);
 LogTarget log_get_target(void) _pure_;
 void log_settle_target(void);
 
-void log_set_max_level(int level);
+int log_set_max_level(int level);
 int log_set_max_level_from_string(const char *e);
 int log_get_max_level(void) _pure_;
 int log_max_levels_to_string(int level, char **ret);
@@ -492,6 +491,15 @@ size_t log_context_num_contexts(void);
 /* Returns the number of fields in all attached log contexts. */
 size_t log_context_num_fields(void);
 
+static inline void _reset_log_level(int *saved_log_level) {
+        assert(saved_log_level);
+
+        log_set_max_level(*saved_log_level);
+}
+
+#define LOG_CONTEXT_SET_LOG_LEVEL(level) \
+        _cleanup_(_reset_log_level) _unused_ int _saved_log_level_ = log_set_max_level(level);
+
 #define LOG_CONTEXT_PUSH(...) \
         LOG_CONTEXT_PUSH_STRV(STRV_MAKE(__VA_ARGS__))
 
-- 
cgit v1.2.3