fix CVE-2022-4415

This commit is contained in:
h30032433 2022-12-28 09:50:39 +08:00
parent 859f9b610a
commit 37cc3c3e20
11 changed files with 1093 additions and 1 deletions

View File

@ -0,0 +1,102 @@
From 2c5d05b3cd986568105d67891e4010b868dea24f 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()
Conflict:Modify the content in meson.build.
Reference:https://github.com/systemd/systemd/commit/2c5d05b3cd986568105d67891e4010b868dea24f
---
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 a71864ca60..f0d24d95cb 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 31ac149b96..86fc1d4fc0 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -615,6 +615,8 @@ tests += [
[['src/test/test-arphrd-list.c',
generated_gperf_headers]],
+ [['src/test/test-errno-util.c']],
+
[['src/test/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);
--
2.33.0

View File

@ -0,0 +1,83 @@
From 510a146634f3e095b34e2a26023b1b1f99dcb8c0 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
Conflict:Delete the modification of parse_config.
Reference:https://github.com/systemd/systemd/commit/510a146634f3e095b34e2a26023b1b1f99dcb8c0
---
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 50220c5ec7..9ce2b92ded 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -111,16 +111,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 {
@@ -139,9 +139,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);
@@ -209,15 +209,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;
--
2.33.0

View File

@ -0,0 +1,386 @@
From 3e4d0f6cf99f8677edd6a237382a65bfe758de03 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.
Conflict:Change 'r = fsync_full(fd);' to 'if (fsync(fd) < 0)'.
Reference:https://github.com/systemd/systemd/commit/3e4d0f6cf99f8677edd6a237382a65bfe758de03
---
src/basic/io-util.h | 9 ++
src/coredump/coredump.c | 196 +++++++++++++++++++++++++++++++++++++---
2 files changed, 192 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 9ce2b92ded..b6f3a2f256 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>
@@ -107,6 +108,7 @@ enum {
META_EXE = _META_MANDATORY_MAX,
META_UNIT,
+ META_PROC_AUXV,
_META_MAX
};
@@ -121,10 +123,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;
@@ -186,13 +190,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;
@@ -252,7 +259,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;
@@ -262,7 +270,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)
@@ -332,6 +340,153 @@ 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_or_else(EIO),
+ "Failed to pread from coredump fd: %s", STRERROR_OR_EOF(errno));
+
+ 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,
@@ -454,6 +609,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;
@@ -491,7 +648,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;
@@ -518,7 +675,7 @@ static int save_external_coredump(
"SIZE_LIMIT=%"PRIu64, 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);
@@ -766,7 +923,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) {
@@ -945,16 +1102,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]);
break;
}
}
@@ -1191,6 +1347,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;
@@ -1255,13 +1412,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);
--
2.33.0

View File

@ -0,0 +1,107 @@
From 4c0acc0761aae0370e20e118b9db3b704e9045cd Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Thu, 25 Nov 2021 10:27:51 +0100
Subject: [PATCH] test: Add TEST_RET macro
This declares a test function whose return code will be passed from
main(). The first test that does not return EXIT_SUCCESS wins.
Conflict:NA
Reference:https://github.com/systemd/systemd/commit/4c0acc0761aae0370e20e118b9db3b704e9045cd
---
src/shared/tests.h | 54 ++++++++++++++++++++++++++++++++--------------
1 file changed, 38 insertions(+), 16 deletions(-)
diff --git a/src/shared/tests.h b/src/shared/tests.h
index 872b9b2d6c..d1c96ef35b 100644
--- a/src/shared/tests.h
+++ b/src/shared/tests.h
@@ -46,46 +46,68 @@ bool can_memlock(void);
const char *ci_environment(void);
typedef struct TestFunc {
- void (*f)(void);
- const char * const n;
+ union f {
+ void (*void_func)(void);
+ int (*int_func)(void);
+ } f;
+ const char * const name;
+ bool has_ret;
} TestFunc;
/* See static-destruct.h for an explanation of how this works. */
-#define REGISTER_TEST(func) \
- static void func(void); \
- _section_("SYSTEMD_TEST_TABLE") _alignptr_ _used_ _variable_no_sanitize_address_ \
- static const TestFunc UNIQ_T(static_test_table_entry, UNIQ) = { \
- .f = &(func), \
- .n = STRINGIFY(func), \
+#define REGISTER_TEST(func) \
+ _section_("SYSTEMD_TEST_TABLE") _alignptr_ _used_ _variable_no_sanitize_address_ \
+ static const TestFunc UNIQ_T(static_test_table_entry, UNIQ) = { \
+ .f = (union f) &(func), \
+ .name = STRINGIFY(func), \
+ .has_ret = __builtin_types_compatible_p(typeof((union f){}.int_func), typeof(&(func))), \
}
extern const TestFunc _weak_ __start_SYSTEMD_TEST_TABLE[];
extern const TestFunc _weak_ __stop_SYSTEMD_TEST_TABLE[];
-#define TEST(name) \
- REGISTER_TEST(test_##name); \
+#define TEST(name) \
+ static void test_##name(void); \
+ REGISTER_TEST(test_##name); \
static void test_##name(void)
-static inline void run_test_table(void) {
+#define TEST_RET(name) \
+ static int test_##name(void); \
+ REGISTER_TEST(test_##name); \
+ static int test_##name(void)
+
+static inline int run_test_table(void) {
+ int r = EXIT_SUCCESS;
+
if (!__start_SYSTEMD_TEST_TABLE)
- return;
+ return r;
const TestFunc *t = ALIGN_TO_PTR(__start_SYSTEMD_TEST_TABLE, sizeof(TestFunc*));
while (t < __stop_SYSTEMD_TEST_TABLE) {
- log_info("/* %s */", t->n);
- t->f();
+ log_info("/* %s */", t->name);
+
+ if (t->has_ret) {
+ int r2 = t->f.int_func();
+ if (r == EXIT_SUCCESS)
+ r = r2;
+ } else
+ t->f.void_func();
+
t = ALIGN_TO_PTR(t + 1, sizeof(TestFunc*));
}
+
+ return r;
}
#define DEFINE_CUSTOM_TEST_MAIN(log_level, intro, outro) \
int main(int argc, char *argv[]) { \
+ int _r = EXIT_SUCCESS; \
test_setup_logging(log_level); \
save_argc_argv(argc, argv); \
intro; \
- run_test_table(); \
+ _r = run_test_table(); \
outro; \
- return EXIT_SUCCESS; \
+ return _r; \
}
#define DEFINE_TEST_MAIN(log_level) DEFINE_CUSTOM_TEST_MAIN(log_level, , )
--
2.33.0

View File

@ -0,0 +1,102 @@
From 0578dfe3eb2ceb8571b62a904dec0ddf410f6352 Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Thu, 25 Nov 2021 10:45:15 +0100
Subject: [PATCH] test: Add sd_booted condition test to TEST macro
Note that this will only report test skips if they use TEST_RET macro.
Regular TEST macros can still be skipped, but this will not be reported
back to main();
Conflict:NA
Reference:https://github.com/systemd/systemd/commit/0578dfe3eb2ceb8571b62a904dec0ddf410f6352
---
src/shared/tests.h | 43 ++++++++++++++++++++++++++-----------------
1 file changed, 26 insertions(+), 17 deletions(-)
diff --git a/src/shared/tests.h b/src/shared/tests.h
index d1c96ef35b..95283e2829 100644
--- a/src/shared/tests.h
+++ b/src/shared/tests.h
@@ -39,7 +39,7 @@ bool can_memlock(void);
if (sd_booted() > 0) { \
x; \
} else { \
- printf("systemd not booted skipping '%s'\n", #x); \
+ printf("systemd not booted, skipping '%s'\n", #x); \
}
/* Provide a convenient way to check if we're running in CI. */
@@ -51,29 +51,31 @@ typedef struct TestFunc {
int (*int_func)(void);
} f;
const char * const name;
- bool has_ret;
+ bool has_ret:1;
+ bool sd_booted:1;
} TestFunc;
/* See static-destruct.h for an explanation of how this works. */
-#define REGISTER_TEST(func) \
+#define REGISTER_TEST(func, ...) \
_section_("SYSTEMD_TEST_TABLE") _alignptr_ _used_ _variable_no_sanitize_address_ \
static const TestFunc UNIQ_T(static_test_table_entry, UNIQ) = { \
.f = (union f) &(func), \
.name = STRINGIFY(func), \
.has_ret = __builtin_types_compatible_p(typeof((union f){}.int_func), typeof(&(func))), \
+ ##__VA_ARGS__ \
}
extern const TestFunc _weak_ __start_SYSTEMD_TEST_TABLE[];
extern const TestFunc _weak_ __stop_SYSTEMD_TEST_TABLE[];
-#define TEST(name) \
- static void test_##name(void); \
- REGISTER_TEST(test_##name); \
+#define TEST(name, ...) \
+ static void test_##name(void); \
+ REGISTER_TEST(test_##name, ##__VA_ARGS__); \
static void test_##name(void)
-#define TEST_RET(name) \
- static int test_##name(void); \
- REGISTER_TEST(test_##name); \
+#define TEST_RET(name, ...) \
+ static int test_##name(void); \
+ REGISTER_TEST(test_##name, ##__VA_ARGS__); \
static int test_##name(void)
static inline int run_test_table(void) {
@@ -84,14 +86,21 @@ static inline int run_test_table(void) {
const TestFunc *t = ALIGN_TO_PTR(__start_SYSTEMD_TEST_TABLE, sizeof(TestFunc*));
while (t < __stop_SYSTEMD_TEST_TABLE) {
- log_info("/* %s */", t->name);
-
- if (t->has_ret) {
- int r2 = t->f.int_func();
- if (r == EXIT_SUCCESS)
- r = r2;
- } else
- t->f.void_func();
+
+ if (t->sd_booted && sd_booted() <= 0) {
+ log_info("/* systemd not booted, skipping %s */", t->name);
+ if (t->has_ret && r == EXIT_SUCCESS)
+ r = EXIT_TEST_SKIP;
+ } else {
+ log_info("/* %s */", t->name);
+
+ if (t->has_ret) {
+ int r2 = t->f.int_func();
+ if (r == EXIT_SUCCESS)
+ r = r2;
+ } else
+ t->f.void_func();
+ }
t = ALIGN_TO_PTR(t + 1, sizeof(TestFunc*));
}
--
2.33.0

View File

@ -0,0 +1,70 @@
From 9cc615460830afdb51ad23e594906bbe60a3b25a Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Fri, 12 Nov 2021 10:54:44 +0100
Subject: [PATCH] test: Create convenience macros to declare tests
Conflict:Delete all contents in test-macro.c.
Reference:https://github.com/systemd/systemd/commit/9cc615460830afdb51ad23e594906bbe60a3b25a
---
src/shared/tests.h | 47 ++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/src/shared/tests.h b/src/shared/tests.h
index c1350763ad..f333ebd842 100644
--- a/src/shared/tests.h
+++ b/src/shared/tests.h
@@ -43,3 +43,50 @@ bool can_memlock(void);
/* Provide a convenient way to check if we're running in CI. */
const char *ci_environment(void);
+
+typedef struct TestFunc {
+ void (*f)(void);
+ const char * const n;
+} TestFunc;
+
+/* See static-destruct.h for an explanation of how this works. */
+#define REGISTER_TEST(func) \
+ static void func(void); \
+ _section_("SYSTEMD_TEST_TABLE") _alignptr_ _used_ _variable_no_sanitize_address_ \
+ static const TestFunc UNIQ_T(static_test_table_entry, UNIQ) = { \
+ .f = &(func), \
+ .n = STRINGIFY(func), \
+ }
+
+extern const TestFunc _weak_ __start_SYSTEMD_TEST_TABLE[];
+extern const TestFunc _weak_ __stop_SYSTEMD_TEST_TABLE[];
+
+#define TEST(name) \
+ REGISTER_TEST(test_##name); \
+ static void test_##name(void)
+
+static inline void run_test_table(void) {
+ if (!__start_SYSTEMD_TEST_TABLE)
+ return;
+
+ const TestFunc *t = ALIGN_TO_PTR(__start_SYSTEMD_TEST_TABLE, sizeof(TestFunc*));
+ while (t < __stop_SYSTEMD_TEST_TABLE) {
+ log_info("/* %s */", t->n);
+ t->f();
+ t = ALIGN_TO_PTR(t + 1, sizeof(TestFunc*));
+ }
+}
+
+#define DEFINE_TEST_MAIN \
+ int main(int argc, char *argv[]) { \
+ test_setup_logging(LOG_INFO); \
+ run_test_table(); \
+ return EXIT_SUCCESS; \
+ }
+
+#define DEFINE_CUSTOM_TEST_MAIN(impl) \
+ int main(int argc, char *argv[]) { \
+ test_setup_logging(LOG_INFO); \
+ run_test_table(); \
+ return impl(); \
+ }
--
2.33.0

View File

@ -0,0 +1,57 @@
From a40b728e1172cc07a09e12dd56089ab37c8c5924 Mon Sep 17 00:00:00 2001
From: Jan Janssen <medhefgo@web.de>
Date: Tue, 23 Nov 2021 13:40:27 +0100
Subject: [PATCH] test: Slightly rework DEFINE_TEST_MAIN macros
- A lot of tests want a different log level
- Provides saved_argc/saved_argv to tests
- Separate intro/outro is more flexible
Conflict:Delete content in test-macro.c.
Reference:https://github.com/systemd/systemd/commit/a40b728e1172cc07a09e12dd56089ab37c8c5924
---
src/shared/tests.h | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/src/shared/tests.h b/src/shared/tests.h
index f333ebd842..872b9b2d6c 100644
--- a/src/shared/tests.h
+++ b/src/shared/tests.h
@@ -6,6 +6,7 @@
#include "sd-daemon.h"
#include "macro.h"
+#include "util.h"
static inline bool manager_errno_skip_test(int r) {
return IN_SET(abs(r),
@@ -77,16 +78,14 @@ static inline void run_test_table(void) {
}
}
-#define DEFINE_TEST_MAIN \
- int main(int argc, char *argv[]) { \
- test_setup_logging(LOG_INFO); \
- run_test_table(); \
- return EXIT_SUCCESS; \
+#define DEFINE_CUSTOM_TEST_MAIN(log_level, intro, outro) \
+ int main(int argc, char *argv[]) { \
+ test_setup_logging(log_level); \
+ save_argc_argv(argc, argv); \
+ intro; \
+ run_test_table(); \
+ outro; \
+ return EXIT_SUCCESS; \
}
-#define DEFINE_CUSTOM_TEST_MAIN(impl) \
- int main(int argc, char *argv[]) { \
- test_setup_logging(LOG_INFO); \
- run_test_table(); \
- return impl(); \
- }
+#define DEFINE_TEST_MAIN(log_level) DEFINE_CUSTOM_TEST_MAIN(log_level, , )
--
2.33.0

View File

@ -0,0 +1,105 @@
From f69ae8585f5ce6cd8d1e6f3ccd6c9c2cf153e846 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Mon, 10 Oct 2022 21:19:43 +0200
Subject: [PATCH] tree-wide: define and use STRERROR_OR_EOF()
Conflict:NA
Reference:https://github.com/systemd/systemd/commit/f69ae8585f5ce6cd8d1e6f3ccd6c9c2cf153e846
---
src/basic/errno-util.h | 5 +++++
src/journal-remote/journal-gatewayd.c | 4 ++--
src/libsystemd/sd-bus/test-bus-chat.c | 2 +-
src/login/logind-seat.c | 8 ++++----
src/test/test-errno-util.c | 6 ++++++
5 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/src/basic/errno-util.h b/src/basic/errno-util.h
index f0d24d95cb..1e2e5b9f15 100644
--- a/src/basic/errno-util.h
+++ b/src/basic/errno-util.h
@@ -16,6 +16,11 @@
* 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)
+/* A helper to print an error message or message for functions that return 0 on EOF.
+ * Note that we can't use ({ … }) to define a temporary variable, so errnum is
+ * evaluated twice. */
+#define STRERROR_OR_EOF(errnum) ((errnum) != 0 ? STRERROR(errnum) : "Unexpected EOF")
+
static inline void _reset_errno_(int *saved_errno) {
if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */
return;
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index 3e2a85ce29..34def4670e 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -256,7 +256,7 @@ static ssize_t request_reader_entries(
errno = 0;
k = fread(buf, 1, n, m->tmp);
if (k != n) {
- log_error("Failed to read from file: %s", errno != 0 ? strerror_safe(errno) : "Premature EOF");
+ log_error("Failed to read from file: %s", STRERROR_OR_EOF(errno));
return MHD_CONTENT_READER_END_WITH_ERROR;
}
@@ -600,7 +600,7 @@ static ssize_t request_reader_fields(
errno = 0;
k = fread(buf, 1, n, m->tmp);
if (k != n) {
- log_error("Failed to read from file: %s", errno != 0 ? strerror_safe(errno) : "Premature EOF");
+ log_error("Failed to read from file: %s", STRERROR_OR_EOF(errno));
return MHD_CONTENT_READER_END_WITH_ERROR;
}
diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c
index df6dd62151..93e8ebfb1b 100644
--- a/src/libsystemd/sd-bus/test-bus-chat.c
+++ b/src/libsystemd/sd-bus/test-bus-chat.c
@@ -308,7 +308,7 @@ static void* client1(void *p) {
errno = 0;
if (read(pp[0], &x, 1) <= 0) {
- log_error("Failed to read from pipe: %s", errno != 0 ? strerror_safe(errno) : "early read");
+ log_error("Failed to read from pipe: %s", STRERROR_OR_EOF(errno));
goto finish;
}
diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c
index 43c72da11f..d8ad424bfe 100644
--- a/src/login/logind-seat.c
+++ b/src/login/logind-seat.c
@@ -389,11 +389,11 @@ int seat_read_active_vt(Seat *s) {
if (lseek(s->manager->console_active_fd, SEEK_SET, 0) < 0)
return log_error_errno(errno, "lseek on console_active_fd failed: %m");
+ errno = 0;
k = read(s->manager->console_active_fd, t, sizeof(t)-1);
- if (k <= 0) {
- log_error("Failed to read current console: %s", k < 0 ? strerror_safe(errno) : "EOF");
- return k < 0 ? -errno : -EIO;
- }
+ if (k <= 0)
+ return log_error_errno(errno ?: EIO,
+ "Failed to read current console: %s", STRERROR_OR_EOF(errno));
t[k] = 0;
truncate_nl(t);
diff --git a/src/test/test-errno-util.c b/src/test/test-errno-util.c
index 284f451002..f858927c92 100644
--- a/src/test/test-errno-util.c
+++ b/src/test/test-errno-util.c
@@ -41,4 +41,10 @@ TEST(STRERROR) {
assert_se(strstr(c, buf));
}
+TEST(STRERROR_OR_ELSE) {
+ log_info("STRERROR_OR_ELSE(0, \"EOF\") → %s", STRERROR_OR_EOF(0));
+ log_info("STRERROR_OR_ELSE(EPERM, \"EOF\") → %s", STRERROR_OR_EOF(EPERM));
+ log_info("STRERROR_OR_ELSE(-EPERM, \"EOF\") → %s", STRERROR_OR_EOF(-EPERM));
+}
+
DEFINE_TEST_MAIN(LOG_INFO);
--
2.33.0

View File

@ -0,0 +1,32 @@
From 08e86b15fc22a8e9f1ee0a791dfd35b2fc25e4c4 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Sun, 22 May 2022 14:36:07 +0200
Subject: [PATCH] coredump: Fix format string type mismatch
Fixes #23471
Conflict:NA
Reference:https://github.com/systemd/systemd/commit/08e86b15fc22a8e9f1ee0a791dfd35b2fc25e4c4
---
src/coredump/coredump.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index c9747416ad..994d968d87 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -512,8 +512,8 @@ static int save_external_coredump(
if (truncated)
log_struct(LOG_INFO,
- LOG_MESSAGE("Core file was truncated to %zu bytes.", max_size),
- "SIZE_LIMIT=%zu", max_size,
+ LOG_MESSAGE("Core file was truncated to %"PRIu64" bytes.", max_size),
+ "SIZE_LIMIT=%"PRIu64, max_size,
"MESSAGE_ID=" SD_MESSAGE_TRUNCATED_CORE_STR);
r = fix_permissions(fd, tmp, fn, context, uid);
--
2.33.0

View File

@ -0,0 +1,35 @@
From 9abe4cfc39579037937c63602ce8fe4f51746d38 Mon Sep 17 00:00:00 2001
From: Frantisek Sumsal <frantisek@sumsal.cz>
Date: Sat, 20 Aug 2022 21:04:24 +0200
Subject: [PATCH] coredump: drop an unused variable
Conflict:NA
Reference:https://github.com/systemd/systemd/commit/9abe4cfc39579037937c63602ce8fe4f51746d38
---
src/coredump/coredump.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 3ec41a32c3..98e7492811 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -931,7 +931,6 @@ log:
}
static int save_context(Context *context, const struct iovec_wrapper *iovw) {
- unsigned count = 0;
const char *unit;
int r;
@@ -955,7 +954,6 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
p = startswith(iovec->iov_base, meta_field_names[i]);
if (p) {
context->meta[i] = p;
- count++;
break;
}
}
--
2.33.0

View File

@ -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: 249 Version: 249
Release: 43 Release: 44
License: MIT and LGPLv2+ and GPLv2+ License: MIT and LGPLv2+ and GPLv2+
Summary: System and Service Manager Summary: System and Service Manager
@ -412,6 +412,16 @@ Patch6363: backport-core-replace-slice-dependencies-as-they-get-added.patch
Patch6364: backport-scsi_id-retry-inquiry-ioctl-if-host_byte-is-DID_TRAN.patch Patch6364: backport-scsi_id-retry-inquiry-ioctl-if-host_byte-is-DID_TRAN.patch
Patch6365: backport-revert-units-add-ProtectClock-yes.patch Patch6365: backport-revert-units-add-ProtectClock-yes.patch
Patch6366: backport-fix-CVE-2022-3821.patch Patch6366: backport-fix-CVE-2022-3821.patch
Patch6367: backport-CVE-2022-4415-test-Create-convenience-macros-to-declare-tests.patch
Patch6368: backport-CVE-2022-4415-test-Slightly-rework-DEFINE_TEST_MAIN-macros.patch
Patch6369: backport-CVE-2022-4415-test-Add-TEST_RET-macro.patch
Patch6370: backport-CVE-2022-4415-test-Add-sd_booted-condition-test-to-TEST-macro.patch
Patch6371: backport-CVE-2022-4415-basic-add-STRERROR-wrapper-for-strerror_r.patch
Patch6372: backport-CVE-2022-4415-tree-wide-define-and-use-STRERROR_OR_EOF.patch
Patch6373: backport-coredump-Fix-format-string-type-mismatch.patch
Patch6374: backport-coredump-drop-an-unused-variable.patch
Patch6375: backport-CVE-2022-4415-coredump-adjust-whitespace.patch
Patch6376: backport-CVE-2022-4415-dont-allow-user-access-coredumps-with-changed-uid.patch
Patch9001: update-rtc-with-system-clock-when-shutdown.patch Patch9001: update-rtc-with-system-clock-when-shutdown.patch
Patch9002: udev-add-actions-while-rename-netif-failed.patch Patch9002: udev-add-actions-while-rename-netif-failed.patch
@ -1864,6 +1874,9 @@ fi
%{_libdir}/security/pam_systemd.so %{_libdir}/security/pam_systemd.so
%changelog %changelog
* Wed Dec 28 2022 huyubiao<huyubiao@huawei.com> - 249-44
- fix CVE-2022-4415
* Mon Dec 12 2022 huajingyun<huajingyun@loongson.cn> - 249-43 * Mon Dec 12 2022 huajingyun<huajingyun@loongson.cn> - 249-43
- Add loongarch for missing_syscall_def.h - Add loongarch for missing_syscall_def.h