diff --git a/backport-coredump-use-unaligned_read_ne-32-64-to-parse-auxv.patch b/backport-coredump-use-unaligned_read_ne-32-64-to-parse-auxv.patch new file mode 100644 index 0000000000000000000000000000000000000000..ed672d80be1b117a360ab12825f89f1f5ba45d14 --- /dev/null +++ b/backport-coredump-use-unaligned_read_ne-32-64-to-parse-auxv.patch @@ -0,0 +1,205 @@ +From d4ffe5c6c7a808a437fcdcd96c21f80f468a6201 Mon Sep 17 00:00:00 2001 +From: "Jin, Yu" +Date: Thu, 26 Jun 2025 09:09:36 +0800 +Subject: [PATCH 2/4] coredump: use unaligned_read_ne{32,64}() to parse auxv + +Fixes a bug introduced by 3e4d0f6cf99f8677edd6a237382a65bfe758de03. + +The auxv metadata is unaligned, as the length of the prefix +"COREDUMP_PROC_AUXV=" is 19. Hence, parse_auxv{32,64}() may triger +an undefined behavior (or at least cause slow down), which can be +detected when running on an undefined behavior sanitizer. + +This also introduces a macro to define `parse_auxv{32,64}()`. + +Fixes #26912. + +(picked 9b032f932c4172fac379234d9d42cf2b266ccaea) + +Signed-off-by: Tian, Chunsheng +--- + src/coredump/coredump.c | 149 ++++++++++++++++------------------------ + 1 file changed, 60 insertions(+), 89 deletions(-) + +diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c +index 884f269..27fc7e9 100644 +--- a/src/coredump/coredump.c ++++ b/src/coredump/coredump.c +@@ -48,6 +48,7 @@ + #include "string-util.h" + #include "strv.h" + #include "tmpfile-util.h" ++#include "unaligned.h" + #include "user-util.h" + + /* The maximum size up to which we process coredumps */ +@@ -349,95 +350,65 @@ 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); ++#define _DEFINE_PARSE_AUXV(size, type, unaligned_read) \ ++ static int parse_auxv##size( \ ++ const void *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(type)) != 0) \ ++ return log_warning_errno(SYNTHETIC_ERRNO(EIO), \ ++ "Incomplete auxv structure (%zu bytes).", \ ++ size_bytes); \ ++ \ ++ size_t words = size_bytes / sizeof(type); \ ++ \ ++ /* Note that we set output variables even on error. */ \ ++ \ ++ for (size_t i = 0; i + 1 < words; i += 2) { \ ++ type key, val; \ ++ \ ++ key = unaligned_read((uint8_t*) auxv + i * sizeof(type)); \ ++ val = unaligned_read((uint8_t*) auxv + (i + 1) * sizeof(type)); \ ++ \ ++ switch (key) { \ ++ case AT_SECURE: \ ++ *at_secure = val != 0; \ ++ break; \ ++ case AT_UID: \ ++ *uid = val; \ ++ break; \ ++ case AT_EUID: \ ++ *euid = val; \ ++ break; \ ++ case AT_GID: \ ++ *gid = val; \ ++ break; \ ++ case AT_EGID: \ ++ *egid = val; \ ++ break; \ ++ case AT_NULL: \ ++ if (val != 0) \ ++ goto error; \ ++ return 0; \ ++ } \ ++ } \ ++ error: \ ++ return log_warning_errno(SYNTHETIC_ERRNO(ENODATA), \ ++ "AT_NULL terminator not found, cannot parse auxv structure."); \ ++ } + +- /* Note that we set output variables even on error. */ ++#define DEFINE_PARSE_AUXV(size)\ ++ _DEFINE_PARSE_AUXV(size, uint##size##_t, unaligned_read_ne##size) + +- 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."); +-} ++DEFINE_PARSE_AUXV(32); ++DEFINE_PARSE_AUXV(64); + + static int grant_user_access(int core_fd, const Context *context) { + int at_secure = -1; +@@ -474,11 +445,11 @@ static int grant_user_access(int core_fd, const Context *context) { + "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], ++ r = parse_auxv64(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], ++ r = parse_auxv32(context->meta[META_PROC_AUXV], + context->meta_size[META_PROC_AUXV], + &at_secure, &uid, &euid, &gid, &egid); + if (r < 0) +-- +2.20.1 + diff --git a/backport-fix-CVE-2022-4415-coredump-do-not-allow-user-to-access-coredumps-with-.patch b/backport-fix-CVE-2022-4415-coredump-do-not-allow-user-to-access-coredumps-with-.patch new file mode 100644 index 0000000000000000000000000000000000000000..0de33d8ec23c5323256f1a81050b421c1f00b728 --- /dev/null +++ b/backport-fix-CVE-2022-4415-coredump-do-not-allow-user-to-access-coredumps-with-.patch @@ -0,0 +1,376 @@ +From 32e7d750a9611a2d40a5f50b5fb948722d2e6513 Mon Sep 17 00:00:00 2001 +From: Jin, Yu" +Date: Wed, 25 Jun 2025 17:31:30 +0800 +Subject: [PATCH 1/4] coredump: do not allow user to access coredumps with + changed uid/gid/capabilities + +From 3e4d0f6cf99f8677edd6a237382a65bfe758de03 + +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. + +Signed-off-by: Tian, Chunsheng +--- + src/basic/io-util.h | 7 ++ + src/coredump/coredump.c | 190 ++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 188 insertions(+), 9 deletions(-) + +diff --git a/src/basic/io-util.h b/src/basic/io-util.h +index 719e19e..d111172 100644 +--- a/src/basic/io-util.h ++++ b/src/basic/io-util.h +@@ -86,6 +86,13 @@ 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 2888071..884f269 100644 +--- a/src/coredump/coredump.c ++++ b/src/coredump/coredump.c +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -96,6 +97,7 @@ enum { + + META_EXE = _META_MANDATORY_MAX, + META_UNIT, ++ META_PROC_AUXV, + _META_MAX + }; + +@@ -110,10 +112,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; +@@ -172,7 +176,9 @@ 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 + _cleanup_(acl_freep) acl_t acl = NULL; +@@ -180,7 +186,9 @@ static int fix_acl(int fd, uid_t uid) { + acl_permset_t permset; + int r; + +- assert(fd >= 0); ++ /* 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; +@@ -259,7 +267,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; + +@@ -269,7 +278,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) +@@ -340,6 +349,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_or_else(EIO), ++ "Failed to pread from coredump fd: %s", strerror(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, +@@ -421,6 +578,7 @@ static int save_external_coredump( + goto fail; + } + ++ bool allow_user = grant_user_access(fd, context) > 0; + #if HAVE_XZ || HAVE_LZ4 + /* If we will remove the coredump anyway, do not compress. */ + if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) { +@@ -446,7 +604,7 @@ static int save_external_coredump( + goto fail_compressed; + } + +- r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid); ++ r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid, allow_user); + if (r < 0) + goto fail_compressed; + +@@ -469,7 +627,7 @@ static int save_external_coredump( + uncompressed: + #endif + +- r = fix_permissions(fd, tmp, fn, context, uid); ++ r = fix_permissions(fd, tmp, fn, context, uid, allow_user); + if (r < 0) + goto fail; + +@@ -720,7 +878,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) { + +@@ -842,16 +1000,16 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) { + struct iovec *iovec = iovw->iovec + n; + + for (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; + } +@@ -1099,6 +1257,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; + +@@ -1171,6 +1330,19 @@ static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) { + if (read_full_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_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.20.1 + diff --git a/backport-fix-CVE-2025-4598-coredump-use-d-in-kernel-core-pattern.patch b/backport-fix-CVE-2025-4598-coredump-use-d-in-kernel-core-pattern.patch new file mode 100644 index 0000000000000000000000000000000000000000..9632ec6d1952ecf781367e2016f36c6ee476a772 --- /dev/null +++ b/backport-fix-CVE-2025-4598-coredump-use-d-in-kernel-core-pattern.patch @@ -0,0 +1,188 @@ +From efd618fb569ca30f18bf55553cfc855c8f0e222c Mon Sep 17 00:00:00 2001 +From: "Jin, Yu" +Date: Thu, 17 Jul 2025 20:49:08 +0800 +Subject: [PATCH] coredump: use %d in kernel core pattern +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The kernel provides %d which is documented as +"dump mode—same as value returned by prctl(2) PR_GET_DUMPABLE". + +We already query /proc/pid/auxv for this information, but unfortunately this +check is subject to a race, because the crashed process may be replaced by an +attacker before we read this data, for example replacing a SUID process that +was killed by a signal with another process that is not SUID, tricking us into +making the coredump of the original process readable by the attacker. + +With this patch, we effectively add one more check to the list of conditions +that need be satisfied if we are to make the coredump accessible to the user. + +Reportedy-by: Qualys Security Advisory + +In principle, %d might return a value other than 0, 1, or 2 in the future. +Thus, we accept those, but emit a notice. + +(picked 0c49e0049b7665bb7769a13ef346fef92e1ad4d6) + +Signed-off-by: Jin, Yu +--- + src/coredump/coredump.c | 24 +++++++++++-- + src/coredump/coredump.c.rej | 66 ++++++++++++++++++++++++++++++++++++ + sysctl.d/50-coredump.conf.in | 2 +- + 3 files changed, 88 insertions(+), 4 deletions(-) + create mode 100644 src/coredump/coredump.c.rej + +diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c +index 27fc7e9..740c9ae 100644 +--- a/src/coredump/coredump.c ++++ b/src/coredump/coredump.c +@@ -83,6 +83,7 @@ enum { + META_ARGV_TIMESTAMP, /* %t: time of dump, expressed as seconds since the Epoch */ + META_ARGV_RLIMIT, /* %c: core file size soft resource limit */ + META_ARGV_HOSTNAME, /* %h: hostname */ ++ META_ARGV_DUMPABLE, /* %d: as set by the kernel */ + _META_ARGV_MAX, + + /* The following indexes are cached for a couple of special fields we use (and +@@ -110,6 +111,7 @@ static const char * const meta_field_names[_META_MAX] = { + [META_ARGV_TIMESTAMP] = "COREDUMP_TIMESTAMP=", + [META_ARGV_RLIMIT] = "COREDUMP_RLIMIT=", + [META_ARGV_HOSTNAME] = "COREDUMP_HOSTNAME=", ++ [META_ARGV_DUMPABLE] = "COREDUMP_DUMPABLE=", + [META_COMM] = "COREDUMP_COMM=", + [META_EXE] = "COREDUMP_EXE=", + [META_UNIT] = "COREDUMP_UNIT=", +@@ -120,6 +122,7 @@ typedef struct Context { + const char *meta[_META_MAX]; + size_t meta_size[_META_MAX]; + pid_t pid; ++ unsigned dumpable; + bool is_pid1; + bool is_journald; + } Context; +@@ -455,14 +458,16 @@ static int grant_user_access(int core_fd, const Context *context) { + 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. */ ++ /* We allow access if %d/dumpable on the command line was exactly 1, we got all the data, ++ * at_secure is not set, and the uid/gid match euid/egid. */ + bool ret = ++ context->dumpable == 1 && + 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)", ++ log_debug("Will %s access (dumpable=%u uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)", + ret ? "permit" : "restrict", ++ context->dumpable, + uid, euid, gid, egid, yes_no(at_secure)); + return ret; + } +@@ -987,6 +992,19 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) { + } + } + ++ /* The value is set to contents of /proc/sys/fs/suid_dumpable, which we set to 2, ++ * if the process is marked as not dumpable, see PR_SET_DUMPABLE(2const). */ ++ if (context->meta[META_ARGV_DUMPABLE]) { ++ r = safe_atou(context->meta[META_ARGV_DUMPABLE], &context->dumpable); ++ if (r < 0) ++ return log_error_errno(r, "Failed to parse dumpable field \"%s\": %m", context->meta[META_ARGV_DUMPABLE]); ++ if (context->dumpable > 2) ++ log_notice("Got unexpected %%d/dumpable value %u.", context->dumpable); ++ }else{ ++ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), ++ "Failed to got the dumpable value."); ++ } ++ + if (!context->meta[META_ARGV_PID]) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Failed to find the PID of crashing process"); +diff --git a/src/coredump/coredump.c.rej b/src/coredump/coredump.c.rej +new file mode 100644 +index 0000000..31e3895 +--- /dev/null ++++ b/src/coredump/coredump.c.rej +@@ -0,0 +1,66 @@ ++--- src/coredump/coredump.c +++++ src/coredump/coredump.c ++@@ -83,6 +83,7 @@ enum { ++ META_ARGV_TIMESTAMP, /* %t: time of dump, expressed as seconds since the Epoch */ ++ META_ARGV_RLIMIT, /* %c: core file size soft resource limit */ ++ META_ARGV_HOSTNAME, /* %h: hostname */ +++ META_ARGV_DUMPABLE, /* %d: as set by the kernel */ ++ _META_ARGV_MAX, ++ ++ /* The following indexes are cached for a couple of special fields we use (and ++@@ -110,6 +111,7 @@ static const char * const meta_field_names[_META_MAX] = { ++ [META_ARGV_TIMESTAMP] = "COREDUMP_TIMESTAMP=", ++ [META_ARGV_RLIMIT] = "COREDUMP_RLIMIT=", ++ [META_ARGV_HOSTNAME] = "COREDUMP_HOSTNAME=", +++ [META_ARGV_DUMPABLE] = "COREDUMP_DUMPABLE=", ++ [META_COMM] = "COREDUMP_COMM=", ++ [META_EXE] = "COREDUMP_EXE=", ++ [META_UNIT] = "COREDUMP_UNIT=", ++@@ -120,6 +122,7 @@ typedef struct Context { ++ const char *meta[_META_MAX]; ++ size_t meta_size[_META_MAX]; ++ pid_t pid; +++ unsigned dumpable; ++ bool is_pid1; ++ bool is_journald; ++ } Context; ++@@ -455,14 +458,16 @@ static int grant_user_access(int core_fd, const Context *context) { ++ 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. */ +++ /* We allow access if %d/dumpable on the command line was exactly 1, we got all the data, +++ * at_secure is not set, and the uid/gid match euid/egid. */ ++ bool ret = +++ context->dumpable == 1 && ++ 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)", +++ log_debug("Will %s access (dumpable=%u uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)", ++ ret ? "permit" : "restrict", +++ context->dumpable, ++ uid, euid, gid, egid, yes_no(at_secure)); ++ return ret; ++ } ++@@ -987,6 +992,19 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) { ++ } ++ } ++ +++ /* The value is set to contents of /proc/sys/fs/suid_dumpable, which we set to 2, +++ * if the process is marked as not dumpable, see PR_SET_DUMPABLE(2const). */ +++ if (context->meta[META_ARGV_DUMPABLE]) { +++ r = safe_atou(context->meta[META_ARGV_DUMPABLE], &context->dumpable); +++ if (r < 0) +++ return log_error_errno(r, "Failed to parse dumpable field \"%s\": %m", context->meta[META_ARGV_DUMPABLE]); +++ if (context->dumpable > 2) +++ log_notice("Got unexpected %%d/dumpable value %u.", context->dumpable); +++ }else{ +++ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), +++ "Failed to got the dumpable value."); +++ } +++ ++ if (!context->meta[META_ARGV_PID]) ++ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), ++ "Failed to find the PID of crashing process"); +diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in +index 47bf847..4613af6 100644 +--- a/sysctl.d/50-coredump.conf.in ++++ b/sysctl.d/50-coredump.conf.in +@@ -9,4 +9,4 @@ + # and systemd-coredump(8) and core(5) for the explanation of the + # setting below. + +-kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %c %h ++kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %c %h %d +-- +2.33.0 + diff --git a/set-kernel-core_pipe_limit-to-16.patch b/set-kernel-core_pipe_limit-to-16.patch index e2415049575bac09632e581a957aaa8e610c953f..cecdd6c8bc71a1628ceff5caaf672221c60e5917 100644 --- a/set-kernel-core_pipe_limit-to-16.patch +++ b/set-kernel-core_pipe_limit-to-16.patch @@ -1,22 +1,25 @@ -From 283ff70372cddb8b06ca3b2c5e7b8287f81207a9 Mon Sep 17 00:00:00 2001 +From b4af782f15dfabfde81485e611e110dc1bed72f1 Mon Sep 17 00:00:00 2001 From: rpm-build -Date: Fri, 30 Jul 2021 12:38:27 +0800 +Date: Thu, 17 Jul 2025 20:51:21 +0800 Subject: [PATCH] set kernel.core_pipe_limit=16 https://github.com/poettering/systemd/commit/8444f245b56d085cdcfa788e9b9c7799fc58a46b +The refactoring patch is used to resolve code conflicts --jinyu + +Signed-off-by: rpm-build --- sysctl.d/50-coredump.conf.in | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in -index 47bf847..327863d 100644 +index 4613af6..98452f8 100644 --- a/sysctl.d/50-coredump.conf.in +++ b/sysctl.d/50-coredump.conf.in @@ -10,3 +10,14 @@ # setting below. - kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %c %h + kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %c %h %d + +# Allow that 16 coredumps are dispatched in parallel by the kernel. We want to +# be able to collect process metadata from /proc/%P/ while processing @@ -29,5 +32,5 @@ index 47bf847..327863d 100644 +# systemd-coredump.socket's MaxConnections= value. +kernel.core_pipe_limit=16 -- -2.27.0 +2.33.0 diff --git a/systemd.spec b/systemd.spec index 7d695bf80e51ca10942f2426c8cd6b44ee629bcd..3bdaf25584b089b3a7d2fcb5eb55e35da9cfa906 100644 --- a/systemd.spec +++ b/systemd.spec @@ -16,7 +16,7 @@ Name: systemd Url: https://systemd.io/ Version: 243 -Release: 84 +Release: 85 License: MIT and LGPLv2+ and GPLv2+ Summary: System and Service Manager @@ -313,6 +313,9 @@ Patch0265: backport-pid1-lookup-owning-PID-of-BusName-name-of-services-a.pa Patch0266: backport-pid1-watch-bus-name-always-when-we-have-it.patch Patch0267: backport-mount-mark-an-existing-mounting-unit-from-proc-self-.patch Patch0268: backport-core-mount-adjust-deserialized-state-based-on-proc-s.patch +Patch0269: backport-fix-CVE-2022-4415-coredump-do-not-allow-user-to-access-coredumps-with-.patch +Patch0270: backport-coredump-use-unaligned_read_ne-32-64-to-parse-auxv.patch +Patch0271: backport-fix-CVE-2025-4598-coredump-use-d-in-kernel-core-pattern.patch #openEuler Patch9002: 1509-fix-journal-file-descriptors-leak-problems.patch @@ -1721,6 +1724,10 @@ fi %exclude /usr/share/man/man3/* %changelog +* Thu Jul 17 2025 Jin Yu - 243-85 +- Fix CVE-2022-4415 +- Fix CVE-2025-4598 + * Mon Jul 14 2025 Han Jinpeng - 243-84 - Fix mount units failed issue, which mount process finished, but there is no mount.