import systemd-250-12.el9_1.3

c9 imports/c9/systemd-250-12.el9_1.3
CentOS Sources 2 years ago committed by MSVSphere Packaging Team
parent 0a38d41fa2
commit 9bb5664db2

@ -0,0 +1,101 @@
From 6415f270c3733d3c80e4d5bdc2e67f9ffb108308 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 29 Nov 2022 09:00:16 +0100
Subject: [PATCH] coredump: adjust whitespace
(cherry picked from commit 510a146634f3e095b34e2a26023b1b1f99dcb8c0)
Related: #2155516
---
src/coredump/coredump.c | 56 ++++++++++++++++++++---------------------
1 file changed, 28 insertions(+), 28 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index fd156370b2..5f315b9a79 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -109,16 +109,16 @@ enum {
};
static const char * const meta_field_names[_META_MAX] = {
- [META_ARGV_PID] = "COREDUMP_PID=",
- [META_ARGV_UID] = "COREDUMP_UID=",
- [META_ARGV_GID] = "COREDUMP_GID=",
- [META_ARGV_SIGNAL] = "COREDUMP_SIGNAL=",
- [META_ARGV_TIMESTAMP] = "COREDUMP_TIMESTAMP=",
- [META_ARGV_RLIMIT] = "COREDUMP_RLIMIT=",
- [META_ARGV_HOSTNAME] = "COREDUMP_HOSTNAME=",
- [META_COMM] = "COREDUMP_COMM=",
- [META_EXE] = "COREDUMP_EXE=",
- [META_UNIT] = "COREDUMP_UNIT=",
+ [META_ARGV_PID] = "COREDUMP_PID=",
+ [META_ARGV_UID] = "COREDUMP_UID=",
+ [META_ARGV_GID] = "COREDUMP_GID=",
+ [META_ARGV_SIGNAL] = "COREDUMP_SIGNAL=",
+ [META_ARGV_TIMESTAMP] = "COREDUMP_TIMESTAMP=",
+ [META_ARGV_RLIMIT] = "COREDUMP_RLIMIT=",
+ [META_ARGV_HOSTNAME] = "COREDUMP_HOSTNAME=",
+ [META_COMM] = "COREDUMP_COMM=",
+ [META_EXE] = "COREDUMP_EXE=",
+ [META_UNIT] = "COREDUMP_UNIT=",
};
typedef struct Context {
@@ -137,9 +137,9 @@ typedef enum CoredumpStorage {
} CoredumpStorage;
static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
- [COREDUMP_STORAGE_NONE] = "none",
+ [COREDUMP_STORAGE_NONE] = "none",
[COREDUMP_STORAGE_EXTERNAL] = "external",
- [COREDUMP_STORAGE_JOURNAL] = "journal",
+ [COREDUMP_STORAGE_JOURNAL] = "journal",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
@@ -155,13 +155,13 @@ static uint64_t arg_max_use = UINT64_MAX;
static int parse_config(void) {
static const ConfigTableItem items[] = {
- { "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
- { "Coredump", "Compress", config_parse_bool, 0, &arg_compress },
- { "Coredump", "ProcessSizeMax", config_parse_iec_uint64, 0, &arg_process_size_max },
- { "Coredump", "ExternalSizeMax", config_parse_iec_uint64_infinity, 0, &arg_external_size_max },
- { "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
- { "Coredump", "KeepFree", config_parse_iec_uint64, 0, &arg_keep_free },
- { "Coredump", "MaxUse", config_parse_iec_uint64, 0, &arg_max_use },
+ { "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
+ { "Coredump", "Compress", config_parse_bool, 0, &arg_compress },
+ { "Coredump", "ProcessSizeMax", config_parse_iec_uint64, 0, &arg_process_size_max },
+ { "Coredump", "ExternalSizeMax", config_parse_iec_uint64_infinity, 0, &arg_external_size_max },
+ { "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
+ { "Coredump", "KeepFree", config_parse_iec_uint64, 0, &arg_keep_free },
+ { "Coredump", "MaxUse", config_parse_iec_uint64, 0, &arg_max_use },
{}
};
@@ -207,15 +207,15 @@ static int fix_acl(int fd, uid_t uid) {
static int fix_xattr(int fd, const Context *context) {
static const char * const xattrs[_META_MAX] = {
- [META_ARGV_PID] = "user.coredump.pid",
- [META_ARGV_UID] = "user.coredump.uid",
- [META_ARGV_GID] = "user.coredump.gid",
- [META_ARGV_SIGNAL] = "user.coredump.signal",
- [META_ARGV_TIMESTAMP] = "user.coredump.timestamp",
- [META_ARGV_RLIMIT] = "user.coredump.rlimit",
- [META_ARGV_HOSTNAME] = "user.coredump.hostname",
- [META_COMM] = "user.coredump.comm",
- [META_EXE] = "user.coredump.exe",
+ [META_ARGV_PID] = "user.coredump.pid",
+ [META_ARGV_UID] = "user.coredump.uid",
+ [META_ARGV_GID] = "user.coredump.gid",
+ [META_ARGV_SIGNAL] = "user.coredump.signal",
+ [META_ARGV_TIMESTAMP] = "user.coredump.timestamp",
+ [META_ARGV_RLIMIT] = "user.coredump.rlimit",
+ [META_ARGV_HOSTNAME] = "user.coredump.hostname",
+ [META_COMM] = "user.coredump.comm",
+ [META_EXE] = "user.coredump.exe",
};
int r = 0;

@ -0,0 +1,99 @@
From f42e15fdfba61fe6dee0bfb0a6a7f44fd9ca9dd3 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: #2155516
---
src/basic/errno-util.h | 10 +++++++++
src/test/meson.build | 2 ++
src/test/test-errno-util.c | 44 ++++++++++++++++++++++++++++++++++++++
3 files changed, 56 insertions(+)
create mode 100644 src/test/test-errno-util.c
diff --git a/src/basic/errno-util.h b/src/basic/errno-util.h
index 09abf0b751..a2d9876c15 100644
--- a/src/basic/errno-util.h
+++ b/src/basic/errno-util.h
@@ -6,6 +6,16 @@
#include "macro.h"
+/* 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)
+
static inline void _reset_errno_(int *saved_errno) {
if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */
return;
diff --git a/src/test/meson.build b/src/test/meson.build
index 14b7939b1f..032800dd85 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -580,6 +580,8 @@ tests += [
[files('test-errno-list.c') +
generated_gperf_headers],
+ [files('test-errno-util.c')],
+
[files('test-ip-protocol-list.c') +
shared_generated_gperf_headers],
diff --git a/src/test/test-errno-util.c b/src/test/test-errno-util.c
new file mode 100644
index 0000000000..284f451002
--- /dev/null
+++ b/src/test/test-errno-util.c
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "errno-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "tests.h"
+
+TEST(strerror_not_threadsafe) {
+ /* 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));
+ */
+}
+
+TEST(STRERROR) {
+ /* 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));
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);

@ -0,0 +1,384 @@
From d133e7f71d4530a25971eb99cd1a108f3ede72b9 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: #2155516
---
src/basic/io-util.h | 9 ++
src/coredump/coredump.c | 197 +++++++++++++++++++++++++++++++++++++---
2 files changed, 193 insertions(+), 13 deletions(-)
diff --git a/src/basic/io-util.h b/src/basic/io-util.h
index 39728e06bc..3afb134266 100644
--- a/src/basic/io-util.h
+++ b/src/basic/io-util.h
@@ -91,7 +91,16 @@ struct iovec_wrapper *iovw_new(void);
struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw);
struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw);
void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors);
+
int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len);
+static inline int iovw_consume(struct iovec_wrapper *iovw, void *data, size_t len) {
+ /* Move data into iovw or free on error */
+ int r = iovw_put(iovw, data, len);
+ if (r < 0)
+ free(data);
+ return r;
+}
+
int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value);
int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value);
void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new);
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 5f315b9a79..48911522f2 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <sys/prctl.h>
#include <sys/statvfs.h>
+#include <sys/auxv.h>
#include <sys/xattr.h>
#include <unistd.h>
@@ -105,6 +106,7 @@ enum {
META_EXE = _META_MANDATORY_MAX,
META_UNIT,
+ META_PROC_AUXV,
_META_MAX
};
@@ -119,10 +121,12 @@ static const char * const meta_field_names[_META_MAX] = {
[META_COMM] = "COREDUMP_COMM=",
[META_EXE] = "COREDUMP_EXE=",
[META_UNIT] = "COREDUMP_UNIT=",
+ [META_PROC_AUXV] = "COREDUMP_PROC_AUXV=",
};
typedef struct Context {
const char *meta[_META_MAX];
+ size_t meta_size[_META_MAX];
pid_t pid;
bool is_pid1;
bool is_journald;
@@ -184,13 +188,16 @@ static 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) {
+ assert(fd >= 0);
+ assert(uid_is_valid(uid));
#if HAVE_ACL
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;
@@ -250,7 +257,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;
@@ -260,7 +268,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);
r = fsync_full(fd);
@@ -330,6 +338,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(SYNTHETIC_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(SYNTHETIC_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(SYNTHETIC_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(SYNTHETIC_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[META_PROC_AUXV])
+ return log_warning_errno(SYNTHETIC_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(SYNTHETIC_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(SYNTHETIC_ERRNO(EUCLEAN),
+ "Core file has strange ELF class, not adjusting permissions.");
+
+ if ((elf[EI_DATA] == ELFDATA2LSB) != (__BYTE_ORDER == __LITTLE_ENDIAN))
+ return log_info_errno(SYNTHETIC_ERRNO(EUCLEAN),
+ "Core file has non-native endianness, not adjusting permissions.");
+
+ if (elf[EI_CLASS] == ELFCLASS64)
+ r = parse_auxv64((const uint64_t*) context->meta[META_PROC_AUXV],
+ context->meta_size[META_PROC_AUXV],
+ &at_secure, &uid, &euid, &gid, &egid);
+ else
+ r = parse_auxv32((const uint32_t*) context->meta[META_PROC_AUXV],
+ context->meta_size[META_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,
@@ -452,6 +608,8 @@ static int save_external_coredump(
context->meta[META_ARGV_PID], context->meta[META_COMM]);
truncated = r == 1;
+ bool allow_user = grant_user_access(fd, context) > 0;
+
#if HAVE_COMPRESSION
if (arg_compress) {
_cleanup_(unlink_and_freep) char *tmp_compressed = NULL;
@@ -489,7 +647,7 @@ static int save_external_coredump(
uncompressed_size += partial_uncompressed_size;
}
- 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)
return r;
@@ -516,7 +674,7 @@ static int save_external_coredump(
"SIZE_LIMIT=%zu", max_size,
"MESSAGE_ID=" SD_MESSAGE_TRUNCATED_CORE_STR);
- r = fix_permissions(fd, tmp, fn, context, uid);
+ r = fix_permissions(fd, tmp, fn, context, uid, allow_user);
if (r < 0)
return log_error_errno(r, "Failed to fix permissions and finalize coredump %s into %s: %m", coredump_tmpfile_name(tmp), fn);
@@ -764,7 +922,7 @@ static int change_uid_gid(const Context *context) {
}
static int submit_coredump(
- Context *context,
+ const Context *context,
struct iovec_wrapper *iovw,
int input_fd) {
@@ -925,16 +1083,15 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
struct iovec *iovec = iovw->iovec + n;
for (size_t i = 0; i < ELEMENTSOF(meta_field_names); i++) {
- char *p;
-
/* 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 process_socket() and gather_pid_metadata_*()) */
assert(((char*) iovec->iov_base)[iovec->iov_len] == 0);
- p = startswith(iovec->iov_base, meta_field_names[i]);
+ const char *p = startswith(iovec->iov_base, meta_field_names[i]);
if (p) {
context->meta[i] = p;
+ context->meta_size[i] = iovec->iov_len - strlen(meta_field_names[i]);
count++;
break;
}
@@ -1176,6 +1333,7 @@ static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) {
uid_t owner_uid;
pid_t pid;
char *t;
+ size_t size;
const char *p;
int r;
@@ -1240,13 +1398,26 @@ static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) {
(void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_LIMITS=", t);
p = procfs_file_alloca(pid, "cgroup");
- if (read_full_virtual_file(p, &t, NULL) >=0)
+ if (read_full_virtual_file(p, &t, NULL) >= 0)
(void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_CGROUP=", t);
p = procfs_file_alloca(pid, "mountinfo");
- if (read_full_virtual_file(p, &t, NULL) >=0)
+ if (read_full_virtual_file(p, &t, NULL) >= 0)
(void) iovw_put_string_field_free(iovw, "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_virtual_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';
+ (void) iovw_consume(iovw, buf, size + strlen("COREDUMP_PROC_AUXV="));
+ }
+
+ free(t);
+ }
+
if (get_process_cwd(pid, &t) >= 0)
(void) iovw_put_string_field_free(iovw, "COREDUMP_CWD=", t);

@ -0,0 +1,27 @@
From 43ca4cb2cb81e4107710e8a8c48df31d022a1136 Mon Sep 17 00:00:00 2001
From: Laura Barcziova <lbarczio@redhat.com>
Date: Wed, 9 Mar 2022 07:50:29 +0100
Subject: [PATCH] Packit: build SRPMs in Copr
Add srpm_build_deps key to the Packit config to specify needed dependencies for SRPM build
and indicate to build SRPM in Copr.
(cherry picked from commit d15e1a29e3aab04ee79d5e3ec8e1e65fca78e165)
Related: #2155516
---
.packit.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.packit.yml b/.packit.yml
index ce8782aae2..e1cbea3b3a 100644
--- a/.packit.yml
+++ b/.packit.yml
@@ -13,6 +13,7 @@ downstream_package_name: systemd
# `git describe` returns in systemd's case 'v245-xxx' which breaks RPM version
# detection (that expects 245-xxxx'). Let's tweak the version string accordingly
upstream_tag_template: "v{version}"
+srpm_build_deps: []
actions:
post-upstream-clone:

@ -0,0 +1,27 @@
From 1e034561de36b0eda6356b15b5433bf8571d4067 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Sun, 30 Oct 2022 11:59:10 +0900
Subject: [PATCH] test: support non-summer time
Follow-up for 759ed0a2533da8840dea315d07f92e6bb0272cdd.
(cherry picked from commit 59ab79a73d030a49bfdffd85897b6b30a2b132c5)
Related: #2155516
---
test/units/testsuite-45.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/units/testsuite-45.sh b/test/units/testsuite-45.sh
index 75e07bc09a..38017a43ea 100755
--- a/test/units/testsuite-45.sh
+++ b/test/units/testsuite-45.sh
@@ -39,7 +39,7 @@ test_timezone() {
if [[ -f /etc/timezone ]]; then
assert_eq "$(cat /etc/timezone)" "Europe/Kiev"
fi
- assert_in "Time zone: Europe/Kiev \(EEST, \+0[0-9]00\)" "$(timedatectl)"
+ assert_in "Time zone: Europe/Kiev \(EES*T, \+0[0-9]00\)" "$(timedatectl)"
if [[ -n "$ORIG_TZ" ]]; then
echo 'reset timezone to original'

@ -0,0 +1,42 @@
From c518597dddb9b8a0b8d895b28ebb4792c8a32c6e Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Thu, 25 Aug 2022 14:52:30 +0200
Subject: [PATCH] test: bump the base VM memory to 768M
as with 512M some tests occasionally trip off OOM-killer (e.g.
TEST-64 + multipath).
(cherry picked from commit 6a9c4977683a30fcd36baf64e35255e9846028c6)
Related: #2155516
---
test/TEST-36-NUMAPOLICY/test.sh | 2 +-
test/test-functions | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/TEST-36-NUMAPOLICY/test.sh b/test/TEST-36-NUMAPOLICY/test.sh
index 7909b1dce3..a0bfd4079a 100755
--- a/test/TEST-36-NUMAPOLICY/test.sh
+++ b/test/TEST-36-NUMAPOLICY/test.sh
@@ -9,7 +9,7 @@ TEST_NO_NSPAWN=1
. "${TEST_BASE_DIR:?}/test-functions"
if qemu_min_version "5.2.0"; then
- QEMU_OPTIONS="-object memory-backend-ram,id=mem0,size=${QEMU_MEM:-512M} -numa node,memdev=mem0,nodeid=0"
+ QEMU_OPTIONS="-object memory-backend-ram,id=mem0,size=${QEMU_MEM:-768M} -numa node,memdev=mem0,nodeid=0"
else
QEMU_OPTIONS="-numa node,nodeid=0"
fi
diff --git a/test/test-functions b/test/test-functions
index 8ea2f97b71..f9a80884e8 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -450,7 +450,7 @@ run_qemu() {
qemu_options+=(
-smp "$QEMU_SMP"
-net none
- -m "${QEMU_MEM:-512M}"
+ -m "${QEMU_MEM:-768M}"
-nographic
-kernel "$KERNEL_BIN"
-drive "format=raw,cache=unsafe,file=$image"

@ -0,0 +1,42 @@
From 58b82abb17fd5c40b5c990a36c43ad558ef3cae1 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Tue, 20 Sep 2022 19:12:18 +0200
Subject: [PATCH] test: don't overwrite existing $QEMU_OPTIONS
(cherry picked from commit 761b1d83145a6f9f41ad9aafcb5f28d452582864)
Related: #2155516
---
test/TEST-36-NUMAPOLICY/test.sh | 4 ++--
test/TEST-53-ISSUE-16347/test.sh | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/test/TEST-36-NUMAPOLICY/test.sh b/test/TEST-36-NUMAPOLICY/test.sh
index a0bfd4079a..5c39b7c6d8 100755
--- a/test/TEST-36-NUMAPOLICY/test.sh
+++ b/test/TEST-36-NUMAPOLICY/test.sh
@@ -9,9 +9,9 @@ TEST_NO_NSPAWN=1
. "${TEST_BASE_DIR:?}/test-functions"
if qemu_min_version "5.2.0"; then
- QEMU_OPTIONS="-object memory-backend-ram,id=mem0,size=${QEMU_MEM:-768M} -numa node,memdev=mem0,nodeid=0"
+ QEMU_OPTIONS+=" -object memory-backend-ram,id=mem0,size=${QEMU_MEM:-768M} -numa node,memdev=mem0,nodeid=0"
else
- QEMU_OPTIONS="-numa node,nodeid=0"
+ QEMU_OPTIONS+=" -numa node,nodeid=0"
fi
do_test "$@"
diff --git a/test/TEST-53-ISSUE-16347/test.sh b/test/TEST-53-ISSUE-16347/test.sh
index 7f44c66bff..6d4821d2c1 100755
--- a/test/TEST-53-ISSUE-16347/test.sh
+++ b/test/TEST-53-ISSUE-16347/test.sh
@@ -5,7 +5,7 @@ set -e
TEST_DESCRIPTION="test timer units when initial clock is ahead"
TEST_NO_NSPAWN=1
-QEMU_OPTIONS="-rtc base=$(date -u +%Y-%m-%dT%H:%M:%S -d '+3 days')"
+QEMU_OPTIONS+=" -rtc base=$(date -u +%Y-%m-%dT%H:%M:%S -d '+3 days')"
# shellcheck source=test/test-functions
. "${TEST_BASE_DIR:?}/test-functions"

@ -0,0 +1,52 @@
From 022cb8bb2028571b9119fd4ae95c87c96f816d6c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 18 Oct 2022 18:09:06 +0200
Subject: [PATCH] shared/json: allow json_variant_dump() to return an error
(cherry picked from commit 7922ead507e0d83e4ec72a8cbd2b67194766e58c)
Related: #2149074
---
src/shared/json.c | 7 ++++---
src/shared/json.h | 2 +-
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/shared/json.c b/src/shared/json.c
index bcc109abc2..f91738227b 100644
--- a/src/shared/json.c
+++ b/src/shared/json.c
@@ -1768,9 +1768,9 @@ int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret) {
return (int) sz - 1;
}
-void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix) {
+int json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix) {
if (!v)
- return;
+ return 0;
if (!f)
f = stdout;
@@ -1796,7 +1796,8 @@ void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const cha
fputc('\n', f); /* In case of SSE add a second newline */
if (flags & JSON_FORMAT_FLUSH)
- fflush(f);
+ return fflush_and_check(f);
+ return 0;
}
int json_variant_filter(JsonVariant **v, char **to_remove) {
diff --git a/src/shared/json.h b/src/shared/json.h
index dd73c1e497..e4bfeae8f5 100644
--- a/src/shared/json.h
+++ b/src/shared/json.h
@@ -195,7 +195,7 @@ typedef enum JsonFormatFlags {
} JsonFormatFlags;
int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret);
-void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix);
+int json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix);
int json_variant_filter(JsonVariant **v, char **to_remove);

@ -0,0 +1,89 @@
From ffed186cce8e5a20187f6f652be94e3135b74eed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Wed, 19 Oct 2022 08:41:13 +0200
Subject: [PATCH] shared/json: use different return code for empty input
It is useful to distinguish if json_parse_file() got no input or invalid input.
Use different return codes for the two cases.
(cherry picked from commit 87a16eb8b54002a49f12944fc09ce45d0cbadf45)
Related: #2149074
---
src/shared/elf-util.c | 2 +-
src/shared/json.c | 6 ++++--
src/test/test-json.c | 18 ++++++++++++++++++
3 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/src/shared/elf-util.c b/src/shared/elf-util.c
index 6d9fcfbbf2..392ed9f31b 100644
--- a/src/shared/elf-util.c
+++ b/src/shared/elf-util.c
@@ -800,7 +800,7 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
return -errno;
r = json_parse_file(json_in, NULL, 0, &package_metadata, NULL, NULL);
- if (r < 0 && r != -EINVAL) /* EINVAL: json was empty, so we got nothing, but that's ok */
+ if (r < 0 && r != -ENODATA) /* ENODATA: json was empty, so we got nothing, but that's ok */
return r;
}
diff --git a/src/shared/json.c b/src/shared/json.c
index f91738227b..70e46fabb1 100644
--- a/src/shared/json.c
+++ b/src/shared/json.c
@@ -3170,7 +3170,6 @@ int json_parse_continue(const char **p, JsonParseFlags flags, JsonVariant **ret,
int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
_cleanup_(json_source_unrefp) JsonSource *source = NULL;
_cleanup_free_ char *text = NULL;
- const char *p;
int r;
if (f)
@@ -3182,13 +3181,16 @@ int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags fla
if (r < 0)
return r;
+ if (isempty(text))
+ return -ENODATA;
+
if (path) {
source = json_source_new(path);
if (!source)
return -ENOMEM;
}
- p = text;
+ const char *p = text;
return json_parse_internal(&p, source, flags, ret, ret_line, ret_column, false);
}
diff --git a/src/test/test-json.c b/src/test/test-json.c
index b385edc269..2256492fb2 100644
--- a/src/test/test-json.c
+++ b/src/test/test-json.c
@@ -346,6 +346,24 @@ TEST(build) {
assert_se(json_variant_equal(a, b));
}
+TEST(json_parse_file_empty) {
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+
+ assert_se(fopen_unlocked("/dev/null", "re", &f) >= 0);
+ assert_se(json_parse_file(f, "waldo", 0, &v, NULL, NULL) == -ENODATA);
+ assert_se(v == NULL);
+}
+
+TEST(json_parse_file_invalid) {
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+
+ assert_se(f = fmemopen_unlocked((void*) "kookoo", 6, "r"));
+ assert_se(json_parse_file(f, "waldo", 0, &v, NULL, NULL) == -EINVAL);
+ assert_se(v == NULL);
+}
+
TEST(source) {
static const char data[] =
"\n"

@ -0,0 +1,121 @@
From 35a233228ff0105892b3edc86a0cdda06282a9ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 18 Oct 2022 18:23:53 +0200
Subject: [PATCH] coredump: avoid deadlock when passing processed backtrace
data
We would deadlock when passing the data back from the forked-off process that
was doing backtrace generation back to the coredump parent. This is because we
fork the child and wait for it to exit. The child tries to write too much data
to the output pipe, and and after the first 64k blocks on the parent because
the pipe is full. The bug surfaced in Fedora because of a combination of four
factors:
- 87707784c70dc9894ec613df0a6e75e732a362a3 was backported to v251.5, which
allowed coredump processing to be successful.
- 1a0281a3ebf4f8c16d40aa9e63103f16cd23bb2a was NOT backported, so the output
was very verbose.
- Fedora has the ELF package metadata available, so a lot of output can be
generated. Most other distros just don't have the information.
- gnome-calendar crashes and has a bazillion modules and 69596 bytes of output
are generated for it.
Fixes https://bugzilla.redhat.com/show_bug.cgi?id=2135778.
The code is changed to try to write data opportunistically. If we get partial
information, that is still logged. In is generally better to log partial
backtrace information than nothing at all.
(cherry picked from commit 076b807be472630692c5348c60d0c2b7b28ad437)
Resolves: #2149074
---
src/shared/elf-util.c | 37 +++++++++++++++++++++++++++++++------
1 file changed, 31 insertions(+), 6 deletions(-)
diff --git a/src/shared/elf-util.c b/src/shared/elf-util.c
index 392ed9f31b..644fbae9ce 100644
--- a/src/shared/elf-util.c
+++ b/src/shared/elf-util.c
@@ -30,6 +30,9 @@
#define THREADS_MAX 64
#define ELF_PACKAGE_METADATA_ID 0xcafe1a7e
+/* The amount of data we're willing to write to each of the output pipes. */
+#define COREDUMP_PIPE_MAX (1024*1024U)
+
static void *dw_dl = NULL;
static void *elf_dl = NULL;
@@ -700,13 +703,13 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
return r;
if (ret) {
- r = RET_NERRNO(pipe2(return_pipe, O_CLOEXEC));
+ r = RET_NERRNO(pipe2(return_pipe, O_CLOEXEC|O_NONBLOCK));
if (r < 0)
return r;
}
if (ret_package_metadata) {
- r = RET_NERRNO(pipe2(json_pipe, O_CLOEXEC));
+ r = RET_NERRNO(pipe2(json_pipe, O_CLOEXEC|O_NONBLOCK));
if (r < 0)
return r;
}
@@ -750,8 +753,24 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
goto child_fail;
if (buf) {
- r = loop_write(return_pipe[1], buf, strlen(buf), false);
- if (r < 0)
+ size_t len = strlen(buf);
+
+ if (len > COREDUMP_PIPE_MAX) {
+ /* This is iffy. A backtrace can be a few hundred kilobytes, but too much is
+ * too much. Let's log a warning and ignore the rest. */
+ log_warning("Generated backtrace is %zu bytes (more than the limit of %u bytes), backtrace will be truncated.",
+ len, COREDUMP_PIPE_MAX);
+ len = COREDUMP_PIPE_MAX;
+ }
+
+ /* Bump the space for the returned string.
+ * Failure is ignored, because partial output is still useful. */
+ (void) fcntl(return_pipe[1], F_SETPIPE_SZ, len);
+
+ r = loop_write(return_pipe[1], buf, len, false);
+ if (r == -EAGAIN)
+ log_warning("Write failed, backtrace will be truncated.");
+ else if (r < 0)
goto child_fail;
return_pipe[1] = safe_close(return_pipe[1]);
@@ -760,13 +779,19 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
if (package_metadata) {
_cleanup_fclose_ FILE *json_out = NULL;
+ /* Bump the space for the returned string. We don't know how much space we'll need in
+ * advance, so we'll just try to write as much as possible and maybe fail later. */
+ (void) fcntl(json_pipe[1], F_SETPIPE_SZ, COREDUMP_PIPE_MAX);
+
json_out = take_fdopen(&json_pipe[1], "w");
if (!json_out) {
r = -errno;
goto child_fail;
}
- json_variant_dump(package_metadata, JSON_FORMAT_FLUSH, json_out, NULL);
+ r = json_variant_dump(package_metadata, JSON_FORMAT_FLUSH, json_out, NULL);
+ if (r < 0)
+ log_warning_errno(r, "Failed to write JSON package metadata, ignoring: %m");
}
_exit(EXIT_SUCCESS);
@@ -801,7 +826,7 @@ int parse_elf_object(int fd, const char *executable, bool fork_disable_dump, cha
r = json_parse_file(json_in, NULL, 0, &package_metadata, NULL, NULL);
if (r < 0 && r != -ENODATA) /* ENODATA: json was empty, so we got nothing, but that's ok */
- return r;
+ log_warning_errno(r, "Failed to read or parse json metadata, ignoring: %m");
}
if (ret)

@ -0,0 +1,34 @@
From a71653b20b889a71c6643171603e65b0ca945ea4 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <fsumsal@redhat.com>
Date: Wed, 30 Nov 2022 15:24:33 +0100
Subject: [PATCH] test: disable flaky subtests that require udevadm wait/lock
Certain TEST-64-UDEV-STORAGE tests require `udevadm wait` and `udevadm
lock` verbs to work reliably. Since we don't plan to backport the verbs
to RHEL 9.1 and older, let's skip the tests to make CIs a bit more
reliable when dealing with z-streams.
Necessary only on RHEL 9.1 and 9.0.
rhel-only
Related: #2149074
---
test/TEST-64-UDEV-STORAGE/test.sh | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/test/TEST-64-UDEV-STORAGE/test.sh b/test/TEST-64-UDEV-STORAGE/test.sh
index 2a5b5b2dd3..659b03e07b 100755
--- a/test/TEST-64-UDEV-STORAGE/test.sh
+++ b/test/TEST-64-UDEV-STORAGE/test.sh
@@ -310,6 +310,11 @@ EOF
# Test case for issue https://github.com/systemd/systemd/issues/19946
testcase_simultaneous_events() {
+ if ! "$BUILD_DIR/udevadm" lock --version >/dev/null; then
+ echo "This test is flaky without udevadm wait/lock, skipping the test..."
+ return 77
+ fi
+
local qemu_opts=("-device virtio-scsi-pci,id=scsi")
local partdisk="${TESTDIR:?}/simultaneousevents.img"

@ -21,7 +21,7 @@
Name: systemd Name: systemd
Url: https://www.freedesktop.org/wiki/Software/systemd Url: https://www.freedesktop.org/wiki/Software/systemd
Version: 250 Version: 250
Release: 12%{?dist}.1 Release: 12%{?dist}.3
# For a breakdown of the licensing, see README # For a breakdown of the licensing, see README
License: LGPLv2+ and MIT and GPLv2+ License: LGPLv2+ and MIT and GPLv2+
Summary: System and Service Manager Summary: System and Service Manager
@ -430,6 +430,17 @@ Patch0349: 0349-test-do-not-restart-getty-tty2-automatically.patch
Patch0350: 0350-tests-add-test-for-StopIdleSessionSec-option.patch Patch0350: 0350-tests-add-test-for-StopIdleSessionSec-option.patch
Patch0351: 0351-logind-schedule-idle-check-full-interval-from-now-if.patch Patch0351: 0351-logind-schedule-idle-check-full-interval-from-now-if.patch
Patch0352: 0352-time-util-fix-buffer-over-run.patch Patch0352: 0352-time-util-fix-buffer-over-run.patch
Patch0353: 0353-coredump-adjust-whitespace.patch
Patch0354: 0354-basic-add-STRERROR-wrapper-for-strerror_r.patch
Patch0355: 0355-coredump-do-not-allow-user-to-access-coredumps-with-.patch
Patch0356: 0356-Packit-build-SRPMs-in-Copr.patch
Patch0357: 0357-test-support-non-summer-time.patch
Patch0358: 0358-test-bump-the-base-VM-memory-to-768M.patch
Patch0359: 0359-test-don-t-overwrite-existing-QEMU_OPTIONS.patch
Patch0360: 0360-shared-json-allow-json_variant_dump-to-return-an-err.patch
Patch0361: 0361-shared-json-use-different-return-code-for-empty-inpu.patch
Patch0362: 0362-coredump-avoid-deadlock-when-passing-processed-backt.patch
Patch0363: 0363-test-disable-flaky-subtests-that-require-udevadm-wai.patch
# Downstream-only patches (90009999) # Downstream-only patches (90009999)
@ -1211,6 +1222,21 @@ getent passwd systemd-oom &>/dev/null || useradd -r -l -g systemd-oom -d / -s /s
%files standalone-sysusers -f .file-list-standalone-sysusers %files standalone-sysusers -f .file-list-standalone-sysusers
%changelog %changelog
* Mon Feb 13 2023 systemd maintenance team <systemd-maint@redhat.com> - 250-12.3
- shared/json: allow json_variant_dump() to return an error (#2149074)
- shared/json: use different return code for empty input (#2149074)
- coredump: avoid deadlock when passing processed backtrace data (#2149074)
- test: disable flaky subtests that require udevadm wait/lock (#2149074)
* Mon Jan 16 2023 systemd maintenance team <systemd-maint@redhat.com> - 250-12.2
- coredump: adjust whitespace (#2155516)
- basic: add STRERROR() wrapper for strerror_r() (#2155516)
- coredump: do not allow user to access coredumps with changed uid/gid/capabilities (#2155516)
- Packit: build SRPMs in Copr (#2155516)
- test: support non-summer time (#2155516)
- test: bump the base VM memory to 768M (#2155516)
- test: don't overwrite existing $QEMU_OPTIONS (#2155516)
* Mon Nov 07 2022 systemd maintenance team <systemd-maint@redhat.com> - 250-12.1 * Mon Nov 07 2022 systemd maintenance team <systemd-maint@redhat.com> - 250-12.1
- time-util: fix buffer-over-run (#2139388) - time-util: fix buffer-over-run (#2139388)

Loading…
Cancel
Save