diff --git a/backport-basic-add-STRERROR-wrapper-for-strerror_r.patch b/backport-basic-add-STRERROR-wrapper-for-strerror_r.patch new file mode 100644 index 0000000000000000000000000000000000000000..11968cfa26696f80c69fc14518cc54eddfbe457d --- /dev/null +++ b/backport-basic-add-STRERROR-wrapper-for-strerror_r.patch @@ -0,0 +1,102 @@ +From 2c5d05b3cd986568105d67891e4010b868dea24f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +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 + diff --git a/backport-coredump-adjust-whitespace.patch b/backport-coredump-adjust-whitespace.patch new file mode 100644 index 0000000000000000000000000000000000000000..044b773f9b8998aca297330fb8846aab820398b7 --- /dev/null +++ b/backport-coredump-adjust-whitespace.patch @@ -0,0 +1,83 @@ +From 510a146634f3e095b34e2a26023b1b1f99dcb8c0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +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 + diff --git a/backport-coredump-do-not-allow-user-to-access-coredumps-with-.patch b/backport-coredump-do-not-allow-user-to-access-coredumps-with-.patch new file mode 100644 index 0000000000000000000000000000000000000000..183d339ef34f024470c4274edadbd291c42b5b37 --- /dev/null +++ b/backport-coredump-do-not-allow-user-to-access-coredumps-with-.patch @@ -0,0 +1,386 @@ +From 3e4d0f6cf99f8677edd6a237382a65bfe758de03 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +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 + +This reads the /proc//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 '"SIZE_LIMIT=%"PRIu64, max_size,' to '"SIZE_LIMIT=%zu", max_size,'. +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 + #include + #include ++#include + #include + #include + +@@ -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=%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); + +@@ -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]); + count++; + 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 + diff --git a/backport-test-Add-TEST_RET-macro.patch b/backport-test-Add-TEST_RET-macro.patch new file mode 100644 index 0000000000000000000000000000000000000000..5a1e5d29773e10c395a54af030f9f176d334c593 --- /dev/null +++ b/backport-test-Add-TEST_RET-macro.patch @@ -0,0 +1,107 @@ +From 4c0acc0761aae0370e20e118b9db3b704e9045cd Mon Sep 17 00:00:00 2001 +From: Jan Janssen +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 + diff --git a/backport-test-Add-sd_booted-condition-test-to-TEST-macro.patch b/backport-test-Add-sd_booted-condition-test-to-TEST-macro.patch new file mode 100644 index 0000000000000000000000000000000000000000..147955022802a1d5347ba2a60843763dda31c68e --- /dev/null +++ b/backport-test-Add-sd_booted-condition-test-to-TEST-macro.patch @@ -0,0 +1,102 @@ +From 0578dfe3eb2ceb8571b62a904dec0ddf410f6352 Mon Sep 17 00:00:00 2001 +From: Jan Janssen +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 + diff --git a/backport-test-Create-convenience-macros-to-declare-tests.patch b/backport-test-Create-convenience-macros-to-declare-tests.patch new file mode 100644 index 0000000000000000000000000000000000000000..e5af4bf1e590ef924164ca78c3b7e9c66848eb18 --- /dev/null +++ b/backport-test-Create-convenience-macros-to-declare-tests.patch @@ -0,0 +1,70 @@ +From 9cc615460830afdb51ad23e594906bbe60a3b25a Mon Sep 17 00:00:00 2001 +From: Jan Janssen +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 + diff --git a/backport-test-Slightly-rework-DEFINE_TEST_MAIN-macros.patch b/backport-test-Slightly-rework-DEFINE_TEST_MAIN-macros.patch new file mode 100644 index 0000000000000000000000000000000000000000..a32be710b9bc784051c06657e84435c11ab18329 --- /dev/null +++ b/backport-test-Slightly-rework-DEFINE_TEST_MAIN-macros.patch @@ -0,0 +1,57 @@ +From a40b728e1172cc07a09e12dd56089ab37c8c5924 Mon Sep 17 00:00:00 2001 +From: Jan Janssen +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 + diff --git a/backport-tree-wide-define-and-use-STRERROR_OR_EOF.patch b/backport-tree-wide-define-and-use-STRERROR_OR_EOF.patch new file mode 100644 index 0000000000000000000000000000000000000000..e1f7a7250a69aede7a0c1be8bcdb320f9c6028bd --- /dev/null +++ b/backport-tree-wide-define-and-use-STRERROR_OR_EOF.patch @@ -0,0 +1,105 @@ +From f69ae8585f5ce6cd8d1e6f3ccd6c9c2cf153e846 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +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 + diff --git a/systemd.spec b/systemd.spec index f34fe8e86f4fbe93f8054df259bf4e5b2f9fb07a..0061b67a11023081d8320e2c7dfc6206ab3694ce 100644 --- a/systemd.spec +++ b/systemd.spec @@ -21,7 +21,7 @@ Name: systemd Url: https://www.freedesktop.org/wiki/Software/systemd Version: 249 -Release: 43 +Release: 44 License: MIT and LGPLv2+ and GPLv2+ Summary: System and Service Manager @@ -412,6 +412,15 @@ 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 Patch6365: backport-revert-units-add-ProtectClock-yes.patch Patch6366: backport-fix-CVE-2022-3821.patch +Patch6367: backport-test-Create-convenience-macros-to-declare-tests.patch +Patch6368: backport-test-Slightly-rework-DEFINE_TEST_MAIN-macros.patch +Patch6369: backport-test-Add-TEST_RET-macro.patch +Patch6370: backport-test-Add-sd_booted-condition-test-to-TEST-macro.patch +Patch6371: backport-basic-add-STRERROR-wrapper-for-strerror_r.patch +Patch6372: backport-tree-wide-define-and-use-STRERROR_OR_EOF.patch +Patch6373: backport-coredump-adjust-whitespace.patch +Patch6374: backport-coredump-do-not-allow-user-to-access-coredumps-with-.patch + Patch9001: update-rtc-with-system-clock-when-shutdown.patch Patch9002: udev-add-actions-while-rename-netif-failed.patch @@ -1864,6 +1873,9 @@ fi %{_libdir}/security/pam_systemd.so %changelog +* Wed Dec 28 2022 huyubiao - 249-44 +- fix CVE-2022-4415 + * Mon Dec 12 2022 huajingyun - 249-43 - Add loongarch for missing_syscall_def.h