diff --git a/SOURCES/0854-manager-limit-access-to-private-dbus-socket.patch b/SOURCES/0854-manager-limit-access-to-private-dbus-socket.patch
new file mode 100644
index 0000000..42ff3fa
--- /dev/null
+++ b/SOURCES/0854-manager-limit-access-to-private-dbus-socket.patch
@@ -0,0 +1,44 @@
+From 004130ae74688eb321aadc05192bab69fe5cbcbf Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Fri, 22 Jul 2022 11:45:12 +0200
+Subject: [PATCH] manager: limit access to private dbus socket
+
+For the system manager, /run/systemd/private is publicly accessible, because
+/run/systemd is 0755, and /run/systemd/private is 0777. For the user manager,
+/run/user/<uid> is 0700, and /run/user/<uid>/systemd/private is 0777. This
+does not directly cause any security issue because we check the sender in
+bus_check_peercred (ucred.uid != 0 && ucred.uid != geteuid()).
+
+But it makes sense to limit access to the socket to avoid wasting time in PID1.
+Somebody could send messages there that'd we'd reject anyway. It also makes
+things more explicit.
+
+(cherry picked from commit df1cbd1adf26071aab41d96e054452a3d66103a4)
+
+Resolves: #2119405
+---
+ src/core/dbus.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/core/dbus.c b/src/core/dbus.c
+index 66d838cdb4..ec6c52cb85 100644
+--- a/src/core/dbus.c
++++ b/src/core/dbus.c
+@@ -42,6 +42,7 @@
+ #include "string-util.h"
+ #include "strv.h"
+ #include "strxcpyx.h"
++#include "umask-util.h"
+ #include "user-util.h"
+ 
+ #define CONNECTIONS_MAX 4096
+@@ -1019,7 +1020,8 @@ int bus_init_private(Manager *m) {
+         if (fd < 0)
+                 return log_error_errno(errno, "Failed to allocate private socket: %m");
+ 
+-        r = bind(fd, &sa.sa, salen);
++        RUN_WITH_UMASK(0077)
++                r = bind(fd, &sa.sa, salen);
+         if (r < 0)
+                 return log_error_errno(errno, "Failed to bind private socket: %m");
+ 
diff --git a/SOURCES/0855-journalctl-do-not-treat-EINTR-as-an-error-when-waiti.patch b/SOURCES/0855-journalctl-do-not-treat-EINTR-as-an-error-when-waiti.patch
new file mode 100644
index 0000000..d53c85d
--- /dev/null
+++ b/SOURCES/0855-journalctl-do-not-treat-EINTR-as-an-error-when-waiti.patch
@@ -0,0 +1,35 @@
+From b0574acc0bddceb0af47f6cce327a87041ab4b52 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Sun, 11 Nov 2018 12:33:06 +0100
+Subject: [PATCH] journalctl: do not treat EINTR as an error when waiting for
+ events
+
+Fixup for 2a1e0f2228bbdfbc18635e959f47df7da50b62fe. Fixes #10724.
+
+Reproducer: start 'journalctl -f' in a terminal window, change window size.
+(cherry picked from commit 8e143a123276a9636987b08f555603927ca9e186)
+
+Resolves: #2161683
+---
+ src/journal/journalctl.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
+index fa83dce562..228cfe7e49 100644
+--- a/src/journal/journalctl.c
++++ b/src/journal/journalctl.c
+@@ -2084,8 +2084,13 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
+         if (r < 0)
+                 return log_error_errno(r, "Failed to determine journal waiting time: %m");
+ 
+-        if (ppoll(pollfds, ELEMENTSOF(pollfds), timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL) < 0)
++        if (ppoll(pollfds, ELEMENTSOF(pollfds),
++                  timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL) < 0) {
++                if (errno == EINTR)
++                        return 0;
++
+                 return log_error_errno(errno, "Couldn't wait for journal event: %m");
++        }
+ 
+         if (pollfds[1].revents & (POLLHUP|POLLERR)) { /* STDOUT has been closed? */
+                 log_debug("Standard output has been closed.");
diff --git a/SOURCES/0856-core-bring-manager_startup-and-manager_reload-more-i.patch b/SOURCES/0856-core-bring-manager_startup-and-manager_reload-more-i.patch
new file mode 100644
index 0000000..e785fdf
--- /dev/null
+++ b/SOURCES/0856-core-bring-manager_startup-and-manager_reload-more-i.patch
@@ -0,0 +1,76 @@
+From b9dd7ee5f4d0f6d51899d7e14ac7ef2fd2840b8f Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Tue, 9 Oct 2018 17:37:57 +0200
+Subject: [PATCH] core: bring manager_startup() and manager_reload() more
+ inline
+
+Both functions do partly the same, let's make sure they do it in the
+same order, and that we don't miss some calls.
+
+This makes a number of changes:
+
+1. Moves exec_runtime_vacuum() two calls down in manager_startup(). This
+   should not have any effect but makes manager_startup() more like
+   manager_reload().
+
+2. Calls manager_recheck_journal(), manager_recheck_dbus(),
+   manager_enqueue_sync_bus_names() in manager_startup() too. This is a
+   good idea since during reeexec we pass through manager_startup() and
+   hence can't assume dbus and journald weren't up yet, hence let's
+   check if they are ready to be connected to.
+
+3. Include manager_enumerate_perpetual() in manager_reload(), too. This
+   is not strictly necessary, since these units are included in the
+   serialization anyway, but it's still a nice thing, in particular as
+   theoretically the deserialization could fail.
+
+(cherry picked from commit 3ad2afb6a204513c7834c64ab864e40169874390)
+
+Resolves: #2059633
+---
+ src/core/manager.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/src/core/manager.c b/src/core/manager.c
+index e083596e58..4a9f9bfcf9 100644
+--- a/src/core/manager.c
++++ b/src/core/manager.c
+@@ -1665,12 +1665,12 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
+         /* Release any dynamic users no longer referenced */
+         dynamic_user_vacuum(m, true);
+ 
+-        exec_runtime_vacuum(m);
+-
+         /* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
+         manager_vacuum_uid_refs(m);
+         manager_vacuum_gid_refs(m);
+ 
++        exec_runtime_vacuum(m);
++
+         if (serialization) {
+                 assert(m->n_reloading > 0);
+                 m->n_reloading--;
+@@ -1681,6 +1681,13 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
+                 m->send_reloading_done = true;
+         }
+ 
++        /* It might be safe to log to the journal now and connect to dbus */
++        manager_recheck_journal(m);
++        manager_recheck_dbus(m);
++
++        /* Sync current state of bus names with our set of listening units */
++        (void) manager_enqueue_sync_bus_names(m);
++
+         /* Let's finally catch up with any changes that took place while we were reloading/reexecing */
+         manager_catchup(m);
+ 
+@@ -3505,7 +3512,8 @@ int manager_reload(Manager *m) {
+         lookup_paths_reduce(&m->lookup_paths);
+         manager_build_unit_path_cache(m);
+ 
+-        /* First, enumerate what we can from all config files */
++        /* First, enumerate what we can from kernel and suchlike */
++        manager_enumerate_perpetual(m);
+         manager_enumerate(m);
+ 
+         /* Second, deserialize our stored data */
diff --git a/SOURCES/0857-pam-add-a-call-to-pam_namespace.patch b/SOURCES/0857-pam-add-a-call-to-pam_namespace.patch
new file mode 100644
index 0000000..8825e9e
--- /dev/null
+++ b/SOURCES/0857-pam-add-a-call-to-pam_namespace.patch
@@ -0,0 +1,35 @@
+From b1b7aaf83414c5b0bed6e61d38aefe29a21fdbcf Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Wed, 23 Nov 2022 16:09:56 +0100
+Subject: [PATCH] pam: add a call to pam_namespace
+
+A call to pam_namespace is required so that children of user@.service end up in
+a namespace as expected. pam_namespace gets called as part of the stack that
+creates a session (login, sshd, gdm, etc.) and those processes end up in a
+namespace, but it also needs to be called from our stack which is parallel and
+descends from pid1 itself.
+
+The call to pam_namespace is similar to the call to pam_keyinit that was added
+in ab79099d1684457d040ee7c28b2012e8c1ea9a4f. The pam stack for user@.service
+creates a new session which is disconnected from the parent environment. Both
+calls are not suitable for inclusion in the shared part of the stack (e.g.
+@system-auth on Fedora/RHEL systems), because for example su/sudo/runuser
+should not include them.
+
+(cherry picked from commit 0ef48896d9f23b9fd547a532a4e6e6b8f8b12901)
+
+Resolves: #1861836
+---
+ src/login/systemd-user.m4 | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/login/systemd-user.m4 b/src/login/systemd-user.m4
+index 20c8999331..eb291beaed 100644
+--- a/src/login/systemd-user.m4
++++ b/src/login/systemd-user.m4
+@@ -9,4 +9,5 @@ session required pam_selinux.so nottys open
+ )m4_dnl
+ session required pam_loginuid.so
+ session optional pam_keyinit.so force revoke
++session required pam_namespace.so
+ session optional pam_systemd.so
diff --git a/SOURCES/0858-virt-Support-detection-for-ARM64-Hyper-V-guests.patch b/SOURCES/0858-virt-Support-detection-for-ARM64-Hyper-V-guests.patch
new file mode 100644
index 0000000..8f71336
--- /dev/null
+++ b/SOURCES/0858-virt-Support-detection-for-ARM64-Hyper-V-guests.patch
@@ -0,0 +1,31 @@
+From 4b573adbcc040fa50f1130cb8cf1bdb9559565cf Mon Sep 17 00:00:00 2001
+From: Boqun Feng <boqun.feng@gmail.com>
+Date: Wed, 13 Oct 2021 11:32:09 +0800
+Subject: [PATCH] virt: Support detection for ARM64 Hyper-V guests
+
+The detection of Microsoft Hyper-V VMs is done by cpuid currently,
+however there is no cpuid on ARM64. And since ARM64 is now a supported
+architecture for Microsoft Hyper-V guests[1], then use DMI tables to
+detect a Hyper-V guest, which is more generic and works for ARM64.
+
+[1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7aff79e297ee1aa0126924921fd87a4ae59d2467
+
+(cherry picked from commit 506bbc8569014253ea8614b680ccbc4fc2513a87)
+
+Resolves: #2158307
+---
+ src/basic/virt.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/basic/virt.c b/src/basic/virt.c
+index 00d1c894e6..cc95097101 100644
+--- a/src/basic/virt.c
++++ b/src/basic/virt.c
+@@ -162,6 +162,7 @@ static int detect_vm_dmi_vendor(void) {
+                 { "Parallels",     VIRTUALIZATION_PARALLELS },
+                 /* https://wiki.freebsd.org/bhyve */
+                 { "BHYVE",         VIRTUALIZATION_BHYVE     },
++                { "Microsoft",           VIRTUALIZATION_MICROSOFT },
+         };
+         unsigned i;
+         int r;
diff --git a/SOURCES/0859-virt-Fix-the-detection-for-Hyper-V-VMs.patch b/SOURCES/0859-virt-Fix-the-detection-for-Hyper-V-VMs.patch
new file mode 100644
index 0000000..8a91e30
--- /dev/null
+++ b/SOURCES/0859-virt-Fix-the-detection-for-Hyper-V-VMs.patch
@@ -0,0 +1,41 @@
+From e732bc987f2f779e89f30193bf694e0456ab7ce0 Mon Sep 17 00:00:00 2001
+From: Boqun Feng <boqun.feng@gmail.com>
+Date: Tue, 23 Nov 2021 15:09:26 +0800
+Subject: [PATCH] virt: Fix the detection for Hyper-V VMs
+
+Use product_version instead of product_name in DMI table and the string
+"Hyper-V" to avoid misdetection.
+
+Fixes: #21468
+
+Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
+(cherry picked from commit 76eec0649936d9ae2f9087769f463feaf0cf5cb4)
+
+Related: #2158307
+---
+ src/basic/virt.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/basic/virt.c b/src/basic/virt.c
+index cc95097101..f750a0463f 100644
+--- a/src/basic/virt.c
++++ b/src/basic/virt.c
+@@ -143,7 +143,8 @@ static int detect_vm_dmi_vendor(void) {
+                 "/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */
+                 "/sys/class/dmi/id/sys_vendor",
+                 "/sys/class/dmi/id/board_vendor",
+-                "/sys/class/dmi/id/bios_vendor"
++                "/sys/class/dmi/id/bios_vendor",
++                "/sys/class/dmi/id/product_version" /* For Hyper-V VMs test */
+         };
+ 
+         static const struct {
+@@ -162,7 +163,7 @@ static int detect_vm_dmi_vendor(void) {
+                 { "Parallels",     VIRTUALIZATION_PARALLELS },
+                 /* https://wiki.freebsd.org/bhyve */
+                 { "BHYVE",         VIRTUALIZATION_BHYVE     },
+-                { "Microsoft",           VIRTUALIZATION_MICROSOFT },
++                { "Hyper-V",             VIRTUALIZATION_MICROSOFT },
+         };
+         unsigned i;
+         int r;
diff --git a/SOURCES/0860-basic-add-STRERROR-wrapper-for-strerror_r.patch b/SOURCES/0860-basic-add-STRERROR-wrapper-for-strerror_r.patch
new file mode 100644
index 0000000..4d1c5e5
--- /dev/null
+++ b/SOURCES/0860-basic-add-STRERROR-wrapper-for-strerror_r.patch
@@ -0,0 +1,98 @@
+From 9c95d8dda42de288a57638a44dd5ea967469063d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Fri, 7 Oct 2022 12:28:31 +0200
+Subject: [PATCH] basic: add STRERROR() wrapper for strerror_r()
+
+(cherry picked from commit 2c5d05b3cd986568105d67891e4010b868dea24f)
+
+Related: #2155520
+---
+ src/basic/util.h     | 10 ++++++++++
+ src/test/test-util.c | 40 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 50 insertions(+)
+
+diff --git a/src/basic/util.h b/src/basic/util.h
+index 76b76d7e91..195f02cf5f 100644
+--- a/src/basic/util.h
++++ b/src/basic/util.h
+@@ -153,6 +153,16 @@ static inline void _reset_errno_(int *saved_errno) {
+         errno = *saved_errno;
+ }
+ 
++/* strerror(3) says that glibc uses a maximum length of 1024 bytes. */
++#define ERRNO_BUF_LEN 1024
++
++/* Note: the lifetime of the compound literal is the immediately surrounding block,
++ * see C11 §6.5.2.5, and
++ * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks
++ *
++ * Note that we use the GNU variant of strerror_r() here. */
++#define STRERROR(errnum) strerror_r(abs(errnum), (char[ERRNO_BUF_LEN]){}, ERRNO_BUF_LEN)
++
+ #define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno
+ 
+ #define UNPROTECT_ERRNO                         \
+diff --git a/src/test/test-util.c b/src/test/test-util.c
+index df60d89115..c93eaf7fc6 100644
+--- a/src/test/test-util.c
++++ b/src/test/test-util.c
+@@ -12,6 +12,7 @@
+ #include "process-util.h"
+ #include "raw-clone.h"
+ #include "rm-rf.h"
++#include "stdio-util.h"
+ #include "string-util.h"
+ #include "util.h"
+ 
+@@ -321,6 +322,42 @@ static void test_system_tasks_max_scale(void) {
+         assert_se(system_tasks_max_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX);
+ }
+ 
++static void test_strerror_not_threadsafe(void) {
++        /* Just check that strerror really is not thread-safe. */
++        log_info("strerror(%d) → %s", 200, strerror(200));
++        log_info("strerror(%d) → %s", 201, strerror(201));
++        log_info("strerror(%d) → %s", INT_MAX, strerror(INT_MAX));
++
++        log_info("strerror(%d), strerror(%d) → %p, %p", 200, 201, strerror(200), strerror(201));
++
++        /* This call is not allowed, because the first returned string becomes invalid when
++         * we call strerror the second time:
++         *
++         * log_info("strerror(%d), strerror(%d) → %s, %s", 200, 201, strerror(200), strerror(201));
++         */
++}
++
++static void test_STRERROR(void) {
++        /* Just check that STRERROR really is thread-safe. */
++        log_info("STRERROR(%d) → %s", 200, STRERROR(200));
++        log_info("STRERROR(%d) → %s", 201, STRERROR(201));
++        log_info("STRERROR(%d), STRERROR(%d) → %s, %s", 200, 201, STRERROR(200), STRERROR(201));
++
++        const char *a = STRERROR(200), *b = STRERROR(201);
++        assert_se(strstr(a, "200"));
++        assert_se(strstr(b, "201"));
++
++        /* Check with negative values */
++        assert_se(streq(a, STRERROR(-200)));
++        assert_se(streq(b, STRERROR(-201)));
++
++        const char *c = STRERROR(INT_MAX);
++        char buf[DECIMAL_STR_MAX(int)];
++        xsprintf(buf, "%d", INT_MAX);  /* INT_MAX is hexadecimal, use printf to convert to decimal */
++        log_info("STRERROR(%d) → %s", INT_MAX, c);
++        assert_se(strstr(c, buf));
++}
++
+ int main(int argc, char *argv[]) {
+         log_parse_environment();
+         log_open();
+@@ -340,5 +377,8 @@ int main(int argc, char *argv[]) {
+         test_system_tasks_max();
+         test_system_tasks_max_scale();
+ 
++        test_strerror_not_threadsafe();
++        test_STRERROR();
++
+         return 0;
+ }
diff --git a/SOURCES/0861-coredump-put-context-array-into-a-struct.patch b/SOURCES/0861-coredump-put-context-array-into-a-struct.patch
new file mode 100644
index 0000000..75029e7
--- /dev/null
+++ b/SOURCES/0861-coredump-put-context-array-into-a-struct.patch
@@ -0,0 +1,529 @@
+From f53c6620c55488e2a3bd92957b21b6b95a7a3d35 Mon Sep 17 00:00:00 2001
+From: David Tardon <dtardon@redhat.com>
+Date: Thu, 12 Jan 2023 15:47:09 +0100
+Subject: [PATCH] coredump: put context array into a struct
+
+[dtardon: This is based on commit f46c706bdd4316ae8ed6baf7a8c382b90b84f648 ,
+but does just the minimal change to introduce the Context struct that is
+needed by the following commit.]
+
+Related: #2155520
+---
+ src/coredump/coredump.c | 208 +++++++++++++++++++++-------------------
+ 1 file changed, 108 insertions(+), 100 deletions(-)
+
+diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
+index fb3a6ecfe9..ebc56d8342 100644
+--- a/src/coredump/coredump.c
++++ b/src/coredump/coredump.c
+@@ -91,6 +91,10 @@ enum {
+         _CONTEXT_MAX
+ };
+ 
++typedef struct Context {
++        const char *meta[_CONTEXT_MAX];
++} Context;
++
+ typedef enum CoredumpStorage {
+         COREDUMP_STORAGE_NONE,
+         COREDUMP_STORAGE_EXTERNAL,
+@@ -184,7 +188,7 @@ static int fix_acl(int fd, uid_t uid) {
+         return 0;
+ }
+ 
+-static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) {
++static int fix_xattr(int fd, const Context *context) {
+ 
+         static const char * const xattrs[_CONTEXT_MAX] = {
+                 [CONTEXT_PID] = "user.coredump.pid",
+@@ -209,10 +213,10 @@ static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) {
+         for (i = 0; i < _CONTEXT_MAX; i++) {
+                 int k;
+ 
+-                if (isempty(context[i]) || !xattrs[i])
++                if (isempty(context->meta[i]) || !xattrs[i])
+                         continue;
+ 
+-                k = fsetxattr(fd, xattrs[i], context[i], strlen(context[i]), XATTR_CREATE);
++                k = fsetxattr(fd, xattrs[i], context->meta[i], strlen(context->meta[i]), XATTR_CREATE);
+                 if (k < 0 && r == 0)
+                         r = -errno;
+         }
+@@ -230,7 +234,7 @@ static int fix_permissions(
+                 int fd,
+                 const char *filename,
+                 const char *target,
+-                const char *context[_CONTEXT_MAX],
++                const Context *context,
+                 uid_t uid) {
+ 
+         int r;
+@@ -273,18 +277,18 @@ static int maybe_remove_external_coredump(const char *filename, uint64_t size) {
+         return 1;
+ }
+ 
+-static int make_filename(const char *context[_CONTEXT_MAX], char **ret) {
++static int make_filename(const Context *context, char **ret) {
+         _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
+         sd_id128_t boot = {};
+         int r;
+ 
+         assert(context);
+ 
+-        c = filename_escape(context[CONTEXT_COMM]);
++        c = filename_escape(context->meta[CONTEXT_COMM]);
+         if (!c)
+                 return -ENOMEM;
+ 
+-        u = filename_escape(context[CONTEXT_UID]);
++        u = filename_escape(context->meta[CONTEXT_UID]);
+         if (!u)
+                 return -ENOMEM;
+ 
+@@ -292,11 +296,11 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) {
+         if (r < 0)
+                 return r;
+ 
+-        p = filename_escape(context[CONTEXT_PID]);
++        p = filename_escape(context->meta[CONTEXT_PID]);
+         if (!p)
+                 return -ENOMEM;
+ 
+-        t = filename_escape(context[CONTEXT_TIMESTAMP]);
++        t = filename_escape(context->meta[CONTEXT_TIMESTAMP]);
+         if (!t)
+                 return -ENOMEM;
+ 
+@@ -313,7 +317,7 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) {
+ }
+ 
+ static int save_external_coredump(
+-                const char *context[_CONTEXT_MAX],
++                const Context *context,
+                 int input_fd,
+                 char **ret_filename,
+                 int *ret_node_fd,
+@@ -334,19 +338,19 @@ static int save_external_coredump(
+         assert(ret_data_fd);
+         assert(ret_size);
+ 
+-        r = parse_uid(context[CONTEXT_UID], &uid);
++        r = parse_uid(context->meta[CONTEXT_UID], &uid);
+         if (r < 0)
+                 return log_error_errno(r, "Failed to parse UID: %m");
+ 
+-        r = safe_atou64(context[CONTEXT_RLIMIT], &rlimit);
++        r = safe_atou64(context->meta[CONTEXT_RLIMIT], &rlimit);
+         if (r < 0)
+-                return log_error_errno(r, "Failed to parse resource limit: %s", context[CONTEXT_RLIMIT]);
++                return log_error_errno(r, "Failed to parse resource limit: %s", context->meta[CONTEXT_RLIMIT]);
+         if (rlimit < page_size()) {
+                 /* Is coredumping disabled? Then don't bother saving/processing the coredump.
+                  * Anything below PAGE_SIZE cannot give a readable coredump (the kernel uses
+                  * ELF_EXEC_PAGESIZE which is not easily accessible, but is usually the same as PAGE_SIZE. */
+                 log_info("Resource limits disable core dumping for process %s (%s).",
+-                         context[CONTEXT_PID], context[CONTEXT_COMM]);
++                         context->meta[CONTEXT_PID], context->meta[CONTEXT_COMM]);
+                 return -EBADSLT;
+         }
+ 
+@@ -371,7 +375,7 @@ static int save_external_coredump(
+ 
+         r = copy_bytes(input_fd, fd, max_size, 0);
+         if (r < 0) {
+-                log_error_errno(r, "Cannot store coredump of %s (%s): %m", context[CONTEXT_PID], context[CONTEXT_COMM]);
++                log_error_errno(r, "Cannot store coredump of %s (%s): %m", context->meta[CONTEXT_PID], context->meta[CONTEXT_COMM]);
+                 goto fail;
+         }
+         *ret_truncated = r == 1;
+@@ -659,12 +663,12 @@ static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) {
+         return 1;
+ }
+ 
+-static int change_uid_gid(const char *context[]) {
++static int change_uid_gid(const Context *context) {
+         uid_t uid;
+         gid_t gid;
+         int r;
+ 
+-        r = parse_uid(context[CONTEXT_UID], &uid);
++        r = parse_uid(context->meta[CONTEXT_UID], &uid);
+         if (r < 0)
+                 return r;
+ 
+@@ -677,7 +681,7 @@ static int change_uid_gid(const char *context[]) {
+                         uid = gid = 0;
+                 }
+         } else {
+-                r = parse_gid(context[CONTEXT_GID], &gid);
++                r = parse_gid(context->meta[CONTEXT_GID], &gid);
+                 if (r < 0)
+                         return r;
+         }
+@@ -685,23 +689,23 @@ static int change_uid_gid(const char *context[]) {
+         return drop_privileges(uid, gid, 0);
+ }
+ 
+-static bool is_journald_crash(const char *context[_CONTEXT_MAX]) {
++static bool is_journald_crash(const Context *context) {
+         assert(context);
+ 
+-        return streq_ptr(context[CONTEXT_UNIT], SPECIAL_JOURNALD_SERVICE);
++        return streq_ptr(context->meta[CONTEXT_UNIT], SPECIAL_JOURNALD_SERVICE);
+ }
+ 
+-static bool is_pid1_crash(const char *context[_CONTEXT_MAX]) {
++static bool is_pid1_crash(const Context *context) {
+         assert(context);
+ 
+-        return streq_ptr(context[CONTEXT_UNIT], SPECIAL_INIT_SCOPE) ||
+-                streq_ptr(context[CONTEXT_PID], "1");
++        return streq_ptr(context->meta[CONTEXT_UNIT], SPECIAL_INIT_SCOPE) ||
++                streq_ptr(context->meta[CONTEXT_PID], "1");
+ }
+ 
+ #define SUBMIT_COREDUMP_FIELDS 4
+ 
+ static int submit_coredump(
+-                const char *context[_CONTEXT_MAX],
++                Context *context,
+                 struct iovec *iovec,
+                 size_t n_iovec_allocated,
+                 size_t n_iovec,
+@@ -760,11 +764,11 @@ static int submit_coredump(
+         if (coredump_size <= arg_process_size_max) {
+                 _cleanup_free_ char *stacktrace = NULL;
+ 
+-                r = coredump_make_stack_trace(coredump_fd, context[CONTEXT_EXE], &stacktrace);
++                r = coredump_make_stack_trace(coredump_fd, context->meta[CONTEXT_EXE], &stacktrace);
+                 if (r >= 0)
+-                        core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
+-                                               " (", context[CONTEXT_COMM], ") of user ",
+-                                               context[CONTEXT_UID], " dumped core.",
++                        core_message = strjoin("MESSAGE=Process ", context->meta[CONTEXT_PID],
++                                               " (", context->meta[CONTEXT_COMM], ") of user ",
++                                               context->meta[CONTEXT_UID], " dumped core.",
+                                                journald_crash ? "\nCoredump diverted to " : "",
+                                                journald_crash ? filename : "",
+                                                "\n\n", stacktrace);
+@@ -779,9 +783,9 @@ static int submit_coredump(
+         if (!core_message)
+ #endif
+ log:
+-        core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
+-                               " (", context[CONTEXT_COMM], ") of user ",
+-                               context[CONTEXT_UID], " dumped core.",
++        core_message = strjoin("MESSAGE=Process ", context->meta[CONTEXT_PID],
++                               " (", context->meta[CONTEXT_COMM], ") of user ",
++                               context->meta[CONTEXT_UID], " dumped core.",
+                                journald_crash && filename ? "\nCoredump diverted to " : NULL,
+                                journald_crash && filename ? filename : NULL);
+         if (!core_message)
+@@ -826,7 +830,7 @@ log:
+         return 0;
+ }
+ 
+-static void map_context_fields(const struct iovec *iovec, const char* context[]) {
++static void map_context_fields(const struct iovec *iovec, Context *context) {
+ 
+         static const char * const context_field_names[] = {
+                 [CONTEXT_PID] = "COREDUMP_PID=",
+@@ -857,7 +861,7 @@ static void map_context_fields(const struct iovec *iovec, const char* context[])
+ 
+                 /* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the
+                  * buffer, though not included in the iov_len count. (see below) */
+-                context[i] = p;
++                context->meta[i] = p;
+                 break;
+         }
+ }
+@@ -866,7 +870,7 @@ static int process_socket(int fd) {
+         _cleanup_close_ int coredump_fd = -1;
+         struct iovec *iovec = NULL;
+         size_t n_iovec = 0, n_allocated = 0, i, k;
+-        const char *context[_CONTEXT_MAX] = {};
++        Context context = {};
+         int r;
+ 
+         assert(fd >= 0);
+@@ -950,7 +954,7 @@ static int process_socket(int fd) {
+                 iovec[n_iovec].iov_len = (size_t) n;
+ 
+                 cmsg_close_all(&mh);
+-                map_context_fields(iovec + n_iovec, context);
++                map_context_fields(iovec + n_iovec, &context);
+                 n_iovec++;
+         }
+ 
+@@ -960,24 +964,24 @@ static int process_socket(int fd) {
+         }
+ 
+         /* Make sure we got all data we really need */
+-        assert(context[CONTEXT_PID]);
+-        assert(context[CONTEXT_UID]);
+-        assert(context[CONTEXT_GID]);
+-        assert(context[CONTEXT_SIGNAL]);
+-        assert(context[CONTEXT_TIMESTAMP]);
+-        assert(context[CONTEXT_RLIMIT]);
+-        assert(context[CONTEXT_HOSTNAME]);
+-        assert(context[CONTEXT_COMM]);
++        assert(context.meta[CONTEXT_PID]);
++        assert(context.meta[CONTEXT_UID]);
++        assert(context.meta[CONTEXT_GID]);
++        assert(context.meta[CONTEXT_SIGNAL]);
++        assert(context.meta[CONTEXT_TIMESTAMP]);
++        assert(context.meta[CONTEXT_RLIMIT]);
++        assert(context.meta[CONTEXT_HOSTNAME]);
++        assert(context.meta[CONTEXT_COMM]);
+         assert(coredump_fd >= 0);
+ 
+         /* Small quirk: the journal fields contain the timestamp padded with six zeroes, so that the kernel-supplied 1s
+          * granularity timestamps becomes 1µs granularity, i.e. the granularity systemd usually operates in. Since we
+          * are reconstructing the original kernel context, we chop this off again, here. */
+-        k = strlen(context[CONTEXT_TIMESTAMP]);
++        k = strlen(context.meta[CONTEXT_TIMESTAMP]);
+         if (k > 6)
+-                context[CONTEXT_TIMESTAMP] = strndupa(context[CONTEXT_TIMESTAMP], k - 6);
++                context.meta[CONTEXT_TIMESTAMP] = strndupa(context.meta[CONTEXT_TIMESTAMP], k - 6);
+ 
+-        r = submit_coredump(context, iovec, n_allocated, n_iovec, coredump_fd);
++        r = submit_coredump(&context, iovec, n_allocated, n_iovec, coredump_fd);
+ 
+ finish:
+         for (i = 0; i < n_iovec; i++)
+@@ -1062,7 +1066,7 @@ static char* set_iovec_field_free(struct iovec *iovec, size_t *n_iovec, const ch
+ }
+ 
+ static int gather_pid_metadata(
+-                char* context[_CONTEXT_MAX],
++                Context *context,
+                 char **comm_fallback,
+                 struct iovec *iovec, size_t *n_iovec) {
+ 
+@@ -1077,65 +1081,69 @@ static int gather_pid_metadata(
+         const char *p;
+         int r, signo;
+ 
+-        r = parse_pid(context[CONTEXT_PID], &pid);
++        r = parse_pid(context->meta[CONTEXT_PID], &pid);
+         if (r < 0)
+-                return log_error_errno(r, "Failed to parse PID \"%s\": %m", context[CONTEXT_PID]);
++                return log_error_errno(r, "Failed to parse PID \"%s\": %m", context->meta[CONTEXT_PID]);
+ 
+-        r = get_process_comm(pid, &context[CONTEXT_COMM]);
++        r = get_process_comm(pid, &t);
+         if (r < 0) {
+                 log_warning_errno(r, "Failed to get COMM, falling back to the command line: %m");
+-                context[CONTEXT_COMM] = strv_join(comm_fallback, " ");
+-                if (!context[CONTEXT_COMM])
++                context->meta[CONTEXT_COMM] = strv_join(comm_fallback, " ");
++                if (!context->meta[CONTEXT_COMM])
+                         return log_oom();
+-        }
++        } else
++                context->meta[CONTEXT_COMM] = t;
+ 
+-        r = get_process_exe(pid, &context[CONTEXT_EXE]);
++        r = get_process_exe(pid, &t);
+         if (r < 0)
+                 log_warning_errno(r, "Failed to get EXE, ignoring: %m");
++        else
++                context->meta[CONTEXT_EXE] = t;
+ 
+-        if (cg_pid_get_unit(pid, &context[CONTEXT_UNIT]) >= 0) {
+-                if (!is_journald_crash((const char**) context)) {
++        if (cg_pid_get_unit(pid, &t) >= 0) {
++                if (!is_journald_crash(context)) {
+                         /* OK, now we know it's not the journal, hence we can make use of it now. */
+                         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
+                         log_open();
+                 }
+ 
+                 /* If this is PID 1 disable coredump collection, we'll unlikely be able to process it later on. */
+-                if (is_pid1_crash((const char**) context)) {
++                if (is_pid1_crash(context)) {
+                         log_notice("Due to PID 1 having crashed coredump collection will now be turned off.");
+                         disable_coredumps();
+                 }
+ 
+-                set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]);
+-        }
++                set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context->meta[CONTEXT_UNIT]);
++        } else
++                context->meta[CONTEXT_UNIT] = t;
+ 
+         if (cg_pid_get_user_unit(pid, &t) >= 0)
+                 set_iovec_field_free(iovec, n_iovec, "COREDUMP_USER_UNIT=", t);
+ 
+         /* The next few are mandatory */
+-        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID]))
++        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context->meta[CONTEXT_PID]))
+                 return log_oom();
+ 
+-        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID]))
++        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context->meta[CONTEXT_UID]))
+                 return log_oom();
+ 
+-        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID]))
++        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context->meta[CONTEXT_GID]))
+                 return log_oom();
+ 
+-        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL]))
++        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context->meta[CONTEXT_SIGNAL]))
+                 return log_oom();
+ 
+-        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT]))
++        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context->meta[CONTEXT_RLIMIT]))
+                 return log_oom();
+ 
+-        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME]))
++        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context->meta[CONTEXT_HOSTNAME]))
+                 return log_oom();
+ 
+-        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM]))
++        if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context->meta[CONTEXT_COMM]))
+                 return log_oom();
+ 
+-        if (context[CONTEXT_EXE] &&
+-            !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE]))
++        if (context->meta[CONTEXT_EXE] &&
++            !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context->meta[CONTEXT_EXE]))
+                 return log_oom();
+ 
+         if (sd_pid_get_session(pid, &t) >= 0)
+@@ -1198,11 +1206,11 @@ static int gather_pid_metadata(
+         if (get_process_environ(pid, &t) >= 0)
+                 set_iovec_field_free(iovec, n_iovec, "COREDUMP_ENVIRON=", t);
+ 
+-        t = strjoin("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000");
++        t = strjoin("COREDUMP_TIMESTAMP=", context->meta[CONTEXT_TIMESTAMP], "000000");
+         if (t)
+                 iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t);
+ 
+-        if (safe_atoi(context[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo))
++        if (safe_atoi(context->meta[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo))
+                 set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo));
+ 
+         return 0; /* we successfully acquired all metadata */
+@@ -1210,7 +1218,7 @@ static int gather_pid_metadata(
+ 
+ static int process_kernel(int argc, char* argv[]) {
+ 
+-        char* context[_CONTEXT_MAX] = {};
++        Context context = {};
+         struct iovec iovec[29 + SUBMIT_COREDUMP_FIELDS];
+         size_t i, n_iovec, n_to_free = 0;
+         int r;
+@@ -1222,15 +1230,15 @@ static int process_kernel(int argc, char* argv[]) {
+                 return -EINVAL;
+         }
+ 
+-        context[CONTEXT_PID]       = argv[1 + CONTEXT_PID];
+-        context[CONTEXT_UID]       = argv[1 + CONTEXT_UID];
+-        context[CONTEXT_GID]       = argv[1 + CONTEXT_GID];
+-        context[CONTEXT_SIGNAL]    = argv[1 + CONTEXT_SIGNAL];
+-        context[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP];
+-        context[CONTEXT_RLIMIT]    = argv[1 + CONTEXT_RLIMIT];
+-        context[CONTEXT_HOSTNAME]  = argv[1 + CONTEXT_HOSTNAME];
++        context.meta[CONTEXT_PID]       = argv[1 + CONTEXT_PID];
++        context.meta[CONTEXT_UID]       = argv[1 + CONTEXT_UID];
++        context.meta[CONTEXT_GID]       = argv[1 + CONTEXT_GID];
++        context.meta[CONTEXT_SIGNAL]    = argv[1 + CONTEXT_SIGNAL];
++        context.meta[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP];
++        context.meta[CONTEXT_RLIMIT]    = argv[1 + CONTEXT_RLIMIT];
++        context.meta[CONTEXT_HOSTNAME]  = argv[1 + CONTEXT_HOSTNAME];
+ 
+-        r = gather_pid_metadata(context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free);
++        r = gather_pid_metadata(&context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free);
+         if (r < 0)
+                 goto finish;
+ 
+@@ -1243,8 +1251,8 @@ static int process_kernel(int argc, char* argv[]) {
+ 
+         assert(n_iovec <= ELEMENTSOF(iovec));
+ 
+-        if (is_journald_crash((const char**) context) || is_pid1_crash((const char**) context))
+-                r = submit_coredump((const char**) context,
++        if (is_journald_crash(&context) || is_pid1_crash(&context))
++                r = submit_coredump(&context,
+                                     iovec, ELEMENTSOF(iovec), n_iovec,
+                                     STDIN_FILENO);
+         else
+@@ -1255,15 +1263,15 @@ static int process_kernel(int argc, char* argv[]) {
+                 free(iovec[i].iov_base);
+ 
+         /* Those fields are allocated by gather_pid_metadata */
+-        free(context[CONTEXT_COMM]);
+-        free(context[CONTEXT_EXE]);
+-        free(context[CONTEXT_UNIT]);
++        free((char *) context.meta[CONTEXT_COMM]);
++        free((char *) context.meta[CONTEXT_EXE]);
++        free((char *) context.meta[CONTEXT_UNIT]);
+ 
+         return r;
+ }
+ 
+ static int process_backtrace(int argc, char *argv[]) {
+-        char *context[_CONTEXT_MAX] = {};
++        Context context = {};
+         _cleanup_free_ char *message = NULL;
+         _cleanup_free_ struct iovec *iovec = NULL;
+         size_t n_iovec, n_allocated, n_to_free = 0, i;
+@@ -1279,13 +1287,13 @@ static int process_backtrace(int argc, char *argv[]) {
+                 return -EINVAL;
+         }
+ 
+-        context[CONTEXT_PID]       = argv[2 + CONTEXT_PID];
+-        context[CONTEXT_UID]       = argv[2 + CONTEXT_UID];
+-        context[CONTEXT_GID]       = argv[2 + CONTEXT_GID];
+-        context[CONTEXT_SIGNAL]    = argv[2 + CONTEXT_SIGNAL];
+-        context[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP];
+-        context[CONTEXT_RLIMIT]    = argv[2 + CONTEXT_RLIMIT];
+-        context[CONTEXT_HOSTNAME]  = argv[2 + CONTEXT_HOSTNAME];
++        context.meta[CONTEXT_PID]       = argv[2 + CONTEXT_PID];
++        context.meta[CONTEXT_UID]       = argv[2 + CONTEXT_UID];
++        context.meta[CONTEXT_GID]       = argv[2 + CONTEXT_GID];
++        context.meta[CONTEXT_SIGNAL]    = argv[2 + CONTEXT_SIGNAL];
++        context.meta[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP];
++        context.meta[CONTEXT_RLIMIT]    = argv[2 + CONTEXT_RLIMIT];
++        context.meta[CONTEXT_HOSTNAME]  = argv[2 + CONTEXT_HOSTNAME];
+ 
+         n_allocated = 34 + COREDUMP_STORAGE_EXTERNAL;
+         /* 26 metadata, 2 static, +unknown input, 4 storage, rounded up */
+@@ -1293,7 +1301,7 @@ static int process_backtrace(int argc, char *argv[]) {
+         if (!iovec)
+                 return log_oom();
+ 
+-        r = gather_pid_metadata(context, argv + 2 + CONTEXT_COMM, iovec, &n_to_free);
++        r = gather_pid_metadata(&context, argv + 2 + CONTEXT_COMM, iovec, &n_to_free);
+         if (r < 0)
+                 goto finish;
+         if (r > 0) {
+@@ -1320,10 +1328,10 @@ static int process_backtrace(int argc, char *argv[]) {
+         if (journal_importer_eof(&importer)) {
+                 log_warning("Did not receive a full journal entry on stdin, ignoring message sent by reporter");
+ 
+-                message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
+-                                  " (", context[CONTEXT_COMM], ")"
+-                                  " of user ", context[CONTEXT_UID],
+-                                  " failed with ", context[CONTEXT_SIGNAL]);
++                message = strjoin("MESSAGE=Process ", context.meta[CONTEXT_PID],
++                                  " (", context.meta[CONTEXT_COMM], ")"
++                                  " of user ", context.meta[CONTEXT_UID],
++                                  " failed with ", context.meta[CONTEXT_SIGNAL]);
+                 if (!message) {
+                         r = log_oom();
+                         goto finish;
+@@ -1349,9 +1357,9 @@ static int process_backtrace(int argc, char *argv[]) {
+                 free(iovec[i].iov_base);
+ 
+         /* Those fields are allocated by gather_pid_metadata */
+-        free(context[CONTEXT_COMM]);
+-        free(context[CONTEXT_EXE]);
+-        free(context[CONTEXT_UNIT]);
++        free((char *) context.meta[CONTEXT_COMM]);
++        free((char *) context.meta[CONTEXT_EXE]);
++        free((char *) context.meta[CONTEXT_UNIT]);
+ 
+         return r;
+ }
diff --git a/SOURCES/0862-coredump-do-not-allow-user-to-access-coredumps-with-.patch b/SOURCES/0862-coredump-do-not-allow-user-to-access-coredumps-with-.patch
new file mode 100644
index 0000000..707bdda
--- /dev/null
+++ b/SOURCES/0862-coredump-do-not-allow-user-to-access-coredumps-with-.patch
@@ -0,0 +1,354 @@
+From d178865d3d9940423f4d99360e3dc2fcaf0b2c96 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Mon, 28 Nov 2022 12:12:55 +0100
+Subject: [PATCH] coredump: do not allow user to access coredumps with changed
+ uid/gid/capabilities
+
+When the user starts a program which elevates its permissions via setuid,
+setgid, or capabilities set on the file, it may access additional information
+which would then be visible in the coredump. We shouldn't make the the coredump
+visible to the user in such cases.
+
+Reported-by: Matthias Gerstner <mgerstner@suse.de>
+
+This reads the /proc/<pid>/auxv file and attaches it to the process metadata as
+PROC_AUXV. Before the coredump is submitted, it is parsed and if either
+at_secure was set (which the kernel will do for processes that are setuid,
+setgid, or setcap), or if the effective uid/gid don't match uid/gid, the file
+is not made accessible to the user. If we can't access this data, we assume the
+file should not be made accessible either. In principle we could also access
+the auxv data from a note in the core file, but that is much more complex and
+it seems better to use the stand-alone file that is provided by the kernel.
+
+Attaching auxv is both convient for this patch (because this way it's passed
+between the stages along with other fields), but I think it makes sense to save
+it in general.
+
+We use the information early in the core file to figure out if the program was
+32-bit or 64-bit and its endianness. This way we don't need heuristics to guess
+whether the format of the auxv structure. This test might reject some cases on
+fringe architecutes. But the impact would be limited: we just won't grant the
+user permissions to view the coredump file. If people report that we're missing
+some cases, we can always enhance this to support more architectures.
+
+I tested auxv parsing on amd64, 32-bit program on amd64, arm64, arm32, and
+ppc64el, but not the whole coredump handling.
+
+(cherry picked from commit 3e4d0f6cf99f8677edd6a237382a65bfe758de03)
+
+Resolves: #2155520
+---
+ src/coredump/coredump.c | 190 ++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 182 insertions(+), 8 deletions(-)
+
+diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
+index ebc56d8342..d8acd2d3a7 100644
+--- a/src/coredump/coredump.c
++++ b/src/coredump/coredump.c
+@@ -4,6 +4,7 @@
+ #include <stdio.h>
+ #include <stdio_ext.h>
+ #include <sys/prctl.h>
++#include <sys/auxv.h>
+ #include <sys/xattr.h>
+ #include <unistd.h>
+ 
+@@ -88,11 +89,13 @@ enum {
+         CONTEXT_COMM,
+         CONTEXT_EXE,
+         CONTEXT_UNIT,
++        CONTEXT_PROC_AUXV,
+         _CONTEXT_MAX
+ };
+ 
+ typedef struct Context {
+         const char *meta[_CONTEXT_MAX];
++        size_t meta_size[_CONTEXT_MAX];
+ } Context;
+ 
+ typedef enum CoredumpStorage {
+@@ -148,8 +151,7 @@ static inline uint64_t storage_size_max(void) {
+         return 0;
+ }
+ 
+-static int fix_acl(int fd, uid_t uid) {
+-
++static int fix_acl(int fd, uid_t uid, bool allow_user) {
+ #if HAVE_ACL
+         _cleanup_(acl_freep) acl_t acl = NULL;
+         acl_entry_t entry;
+@@ -157,6 +159,11 @@ static int fix_acl(int fd, uid_t uid) {
+         int r;
+ 
+         assert(fd >= 0);
++        assert(uid_is_valid(uid));
++
++        /* We don't allow users to read coredumps if the uid or capabilities were changed. */
++        if (!allow_user)
++                return 0;
+ 
+         if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY)
+                 return 0;
+@@ -235,7 +242,8 @@ static int fix_permissions(
+                 const char *filename,
+                 const char *target,
+                 const Context *context,
+-                uid_t uid) {
++                uid_t uid,
++                bool allow_user) {
+ 
+         int r;
+ 
+@@ -245,7 +253,7 @@ static int fix_permissions(
+ 
+         /* Ignore errors on these */
+         (void) fchmod(fd, 0640);
+-        (void) fix_acl(fd, uid);
++        (void) fix_acl(fd, uid, allow_user);
+         (void) fix_xattr(fd, context);
+ 
+         if (fsync(fd) < 0)
+@@ -316,6 +324,154 @@ static int make_filename(const Context *context, char **ret) {
+         return 0;
+ }
+ 
++static int parse_auxv64(
++                const uint64_t *auxv,
++                size_t size_bytes,
++                int *at_secure,
++                uid_t *uid,
++                uid_t *euid,
++                gid_t *gid,
++                gid_t *egid) {
++
++        assert(auxv || size_bytes == 0);
++
++        if (size_bytes % (2 * sizeof(uint64_t)) != 0)
++                return log_warning_errno(-EIO, "Incomplete auxv structure (%zu bytes).", size_bytes);
++
++        size_t words = size_bytes / sizeof(uint64_t);
++
++        /* Note that we set output variables even on error. */
++
++        for (size_t i = 0; i + 1 < words; i += 2)
++                switch (auxv[i]) {
++                case AT_SECURE:
++                        *at_secure = auxv[i + 1] != 0;
++                        break;
++                case AT_UID:
++                        *uid = auxv[i + 1];
++                        break;
++                case AT_EUID:
++                        *euid = auxv[i + 1];
++                        break;
++                case AT_GID:
++                        *gid = auxv[i + 1];
++                        break;
++                case AT_EGID:
++                        *egid = auxv[i + 1];
++                        break;
++                case AT_NULL:
++                        if (auxv[i + 1] != 0)
++                                goto error;
++                        return 0;
++                }
++ error:
++        return log_warning_errno(-ENODATA,
++                                 "AT_NULL terminator not found, cannot parse auxv structure.");
++}
++
++static int parse_auxv32(
++                const uint32_t *auxv,
++                size_t size_bytes,
++                int *at_secure,
++                uid_t *uid,
++                uid_t *euid,
++                gid_t *gid,
++                gid_t *egid) {
++
++        assert(auxv || size_bytes == 0);
++
++        size_t words = size_bytes / sizeof(uint32_t);
++
++        if (size_bytes % (2 * sizeof(uint32_t)) != 0)
++                return log_warning_errno(-EIO, "Incomplete auxv structure (%zu bytes).", size_bytes);
++
++        /* Note that we set output variables even on error. */
++
++        for (size_t i = 0; i + 1 < words; i += 2)
++                switch (auxv[i]) {
++                case AT_SECURE:
++                        *at_secure = auxv[i + 1] != 0;
++                        break;
++                case AT_UID:
++                        *uid = auxv[i + 1];
++                        break;
++                case AT_EUID:
++                        *euid = auxv[i + 1];
++                        break;
++                case AT_GID:
++                        *gid = auxv[i + 1];
++                        break;
++                case AT_EGID:
++                        *egid = auxv[i + 1];
++                        break;
++                case AT_NULL:
++                        if (auxv[i + 1] != 0)
++                                goto error;
++                        return 0;
++                }
++ error:
++        return log_warning_errno(-ENODATA,
++                                 "AT_NULL terminator not found, cannot parse auxv structure.");
++}
++
++static int grant_user_access(int core_fd, const Context *context) {
++        int at_secure = -1;
++        uid_t uid = UID_INVALID, euid = UID_INVALID;
++        uid_t gid = GID_INVALID, egid = GID_INVALID;
++        int r;
++
++        assert(core_fd >= 0);
++        assert(context);
++
++        if (!context->meta[CONTEXT_PROC_AUXV])
++                return log_warning_errno(-ENODATA, "No auxv data, not adjusting permissions.");
++
++        uint8_t elf[EI_NIDENT];
++        errno = 0;
++        if (pread(core_fd, &elf, sizeof(elf), 0) != sizeof(elf))
++                return log_warning_errno(errno > 0 ? -errno : -EIO,
++                                         "Failed to pread from coredump fd: %s",
++                                         errno > 0 ? STRERROR(errno) : "Unexpected EOF");
++
++        if (elf[EI_MAG0] != ELFMAG0 ||
++            elf[EI_MAG1] != ELFMAG1 ||
++            elf[EI_MAG2] != ELFMAG2 ||
++            elf[EI_MAG3] != ELFMAG3 ||
++            elf[EI_VERSION] != EV_CURRENT)
++                return log_info_errno(-EUCLEAN,
++                                      "Core file does not have ELF header, not adjusting permissions.");
++        if (!IN_SET(elf[EI_CLASS], ELFCLASS32, ELFCLASS64) ||
++            !IN_SET(elf[EI_DATA], ELFDATA2LSB, ELFDATA2MSB))
++                return log_info_errno(-EUCLEAN,
++                                      "Core file has strange ELF class, not adjusting permissions.");
++
++        if ((elf[EI_DATA] == ELFDATA2LSB) != (__BYTE_ORDER == __LITTLE_ENDIAN))
++                return log_info_errno(-EUCLEAN,
++                                      "Core file has non-native endianness, not adjusting permissions.");
++
++        if (elf[EI_CLASS] == ELFCLASS64)
++                r = parse_auxv64((const uint64_t*) context->meta[CONTEXT_PROC_AUXV],
++                                 context->meta_size[CONTEXT_PROC_AUXV],
++                                 &at_secure, &uid, &euid, &gid, &egid);
++        else
++                r = parse_auxv32((const uint32_t*) context->meta[CONTEXT_PROC_AUXV],
++                                 context->meta_size[CONTEXT_PROC_AUXV],
++                                 &at_secure, &uid, &euid, &gid, &egid);
++        if (r < 0)
++                return r;
++
++        /* We allow access if we got all the data and at_secure is not set and
++         * the uid/gid matches euid/egid. */
++        bool ret =
++                at_secure == 0 &&
++                uid != UID_INVALID && euid != UID_INVALID && uid == euid &&
++                gid != GID_INVALID && egid != GID_INVALID && gid == egid;
++        log_debug("Will %s access (uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)",
++                  ret ? "permit" : "restrict",
++                  uid, euid, gid, egid, yes_no(at_secure));
++        return ret;
++}
++
+ static int save_external_coredump(
+                 const Context *context,
+                 int input_fd,
+@@ -395,6 +551,8 @@ static int save_external_coredump(
+                 goto fail;
+         }
+ 
++        bool allow_user = grant_user_access(fd, context) > 0;
++
+ #if HAVE_XZ || HAVE_LZ4
+         /* If we will remove the coredump anyway, do not compress. */
+         if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) {
+@@ -420,7 +578,7 @@ static int save_external_coredump(
+                         goto fail_compressed;
+                 }
+ 
+-                r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid);
++                r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid, allow_user);
+                 if (r < 0)
+                         goto fail_compressed;
+ 
+@@ -443,7 +601,7 @@ static int save_external_coredump(
+ uncompressed:
+ #endif
+ 
+-        r = fix_permissions(fd, tmp, fn, context, uid);
++        r = fix_permissions(fd, tmp, fn, context, uid, allow_user);
+         if (r < 0)
+                 goto fail;
+ 
+@@ -842,6 +1000,7 @@ static void map_context_fields(const struct iovec *iovec, Context *context) {
+                 [CONTEXT_HOSTNAME] = "COREDUMP_HOSTNAME=",
+                 [CONTEXT_COMM] = "COREDUMP_COMM=",
+                 [CONTEXT_EXE] = "COREDUMP_EXE=",
++                [CONTEXT_PROC_AUXV] = "COREDUMP_PROC_AUXV=",
+         };
+ 
+         unsigned i;
+@@ -862,6 +1021,7 @@ static void map_context_fields(const struct iovec *iovec, Context *context) {
+                 /* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the
+                  * buffer, though not included in the iov_len count. (see below) */
+                 context->meta[i] = p;
++                context->meta_size[i] = iovec->iov_len - strlen(context_field_names[i]);
+                 break;
+         }
+ }
+@@ -1070,7 +1230,7 @@ static int gather_pid_metadata(
+                 char **comm_fallback,
+                 struct iovec *iovec, size_t *n_iovec) {
+ 
+-        /* We need 27 empty slots in iovec!
++        /* We need 28 empty slots in iovec!
+          *
+          * Note that if we fail on oom later on, we do not roll-back changes to the iovec structure. (It remains valid,
+          * with the first n_iovec fields initialized.) */
+@@ -1078,6 +1238,7 @@ static int gather_pid_metadata(
+         uid_t owner_uid;
+         pid_t pid;
+         char *t;
++        size_t size;
+         const char *p;
+         int r, signo;
+ 
+@@ -1187,6 +1348,19 @@ static int gather_pid_metadata(
+         if (read_full_file(p, &t, NULL) >=0)
+                 set_iovec_field_free(iovec, n_iovec, "COREDUMP_PROC_MOUNTINFO=", t);
+ 
++        /* We attach /proc/auxv here. ELF coredumps also contain a note for this (NT_AUXV), see elf(5). */
++        p = procfs_file_alloca(pid, "auxv");
++        if (read_full_file(p, &t, &size) >= 0) {
++                char *buf = malloc(strlen("COREDUMP_PROC_AUXV=") + size + 1);
++                if (buf) {
++                        /* Add a dummy terminator to make save_context() happy. */
++                        *((uint8_t*) mempcpy(stpcpy(buf, "COREDUMP_PROC_AUXV="), t, size)) = '\0';
++                        iovec[(*n_iovec)++] = IOVEC_MAKE(buf, size + strlen("COREDUMP_PROC_AUXV="));
++                }
++
++                free(t);
++        }
++
+         if (get_process_cwd(pid, &t) >= 0)
+                 set_iovec_field_free(iovec, n_iovec, "COREDUMP_CWD=", t);
+ 
+@@ -1219,7 +1393,7 @@ static int gather_pid_metadata(
+ static int process_kernel(int argc, char* argv[]) {
+ 
+         Context context = {};
+-        struct iovec iovec[29 + SUBMIT_COREDUMP_FIELDS];
++        struct iovec iovec[30 + SUBMIT_COREDUMP_FIELDS];
+         size_t i, n_iovec, n_to_free = 0;
+         int r;
+ 
diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec
index 6079af7..d00e99d 100644
--- a/SPECS/systemd.spec
+++ b/SPECS/systemd.spec
@@ -13,7 +13,7 @@
 Name:           systemd
 Url:            http://www.freedesktop.org/wiki/Software/systemd
 Version:        239
-Release:        70%{?dist}
+Release:        71%{?dist}
 # For a breakdown of the licensing, see README
 License:        LGPLv2+ and MIT and GPLv2+
 Summary:        System and Service Manager
@@ -903,6 +903,15 @@ Patch0850: 0850-virt-use-string-table-to-detect-VM-or-container.patch
 Patch0851: 0851-fileio-introduce-read_full_virtual_file-for-reading-.patch
 Patch0852: 0852-Use-BIOS-characteristics-to-distinguish-EC2-bare-met.patch
 Patch0853: 0853-device-drop-refuse_after.patch
+Patch0854: 0854-manager-limit-access-to-private-dbus-socket.patch
+Patch0855: 0855-journalctl-do-not-treat-EINTR-as-an-error-when-waiti.patch
+Patch0856: 0856-core-bring-manager_startup-and-manager_reload-more-i.patch
+Patch0857: 0857-pam-add-a-call-to-pam_namespace.patch
+Patch0858: 0858-virt-Support-detection-for-ARM64-Hyper-V-guests.patch
+Patch0859: 0859-virt-Fix-the-detection-for-Hyper-V-VMs.patch
+Patch0860: 0860-basic-add-STRERROR-wrapper-for-strerror_r.patch
+Patch0861: 0861-coredump-put-context-array-into-a-struct.patch
+Patch0862: 0862-coredump-do-not-allow-user-to-access-coredumps-with-.patch
 
 %ifarch %{ix86} x86_64 aarch64
 %global have_gnu_efi 1
@@ -1532,6 +1541,17 @@ fi
 %files tests -f .file-list-tests
 
 %changelog
+* Tue Jan 31 2023 systemd maintenance team <systemd-maint@redhat.com> - 239-71
+- manager: limit access to private dbus socket (#2119405)
+- journalctl: do not treat EINTR as an error when waiting for events (#2161683)
+- core: bring manager_startup() and manager_reload() more inline (#2059633)
+- pam: add a call to pam_namespace (#1861836)
+- virt: Support detection for ARM64 Hyper-V guests (#2158307)
+- virt: Fix the detection for Hyper-V VMs (#2158307)
+- basic: add STRERROR() wrapper for strerror_r() (#2155520)
+- coredump: put context array into a struct (#2155520)
+- coredump: do not allow user to access coredumps with changed uid/gid/capabilities (#2155520)
+
 * Mon Jan 16 2023 systemd maintenance team <systemd-maint@redhat.com> - 239-70
 - basic: recognize pdfs filesystem as a network filesystem (#2094661)
 - core: move reset_arguments() to the end of main's finish (#2127131)