From 0ce8c68f0224517c0ec2e749aaa4c84601676f4f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 6 Aug 2026 02:20:56 +0900 Subject: [PATCH 1/3] include: use linux/pidfd.h rather than sys/pidfd.h Since glibc-2.43, sys/pidfd.h defines struct pidfd_info, but its definition is slightly older compared with linux v6.19. See https://sourceware.org/git/?p=glibc.git;a=commit;h=c0c9524a11c56889ec5b1de2e0b78112f2ebc0b7 https://lore.kernel.org/all/20251028-work-coredump-signal-v1-0-ca449b7b7aa0@kernel.org/ This imports linux/pidfd.h (and linux/ioctl.h) from the kernel 7.2-rc6, and make our header that overrides sys/pidfd.h includes linux/pidfd.h. Then, we can always use uptodate definition of struct pidfd_info. Note, linux/pidfd.h includes linux/fcntl.h, but it conflicts glibc's fcntl.h. So, this also replaces linux/fcntl.h with glibc's fcntl.h. --- src/include/override/linux/fcntl.h | 10 +++ src/include/override/sys/pidfd.h | 103 +------------------------ src/include/uapi/linux/ioctl.h | 8 ++ src/include/uapi/linux/pidfd.h | 119 +++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 101 deletions(-) create mode 100644 src/include/override/linux/fcntl.h create mode 100644 src/include/uapi/linux/ioctl.h create mode 100644 src/include/uapi/linux/pidfd.h diff --git a/src/include/override/linux/fcntl.h b/src/include/override/linux/fcntl.h new file mode 100644 index 0000000000..c2afd9c99b --- /dev/null +++ b/src/include/override/linux/fcntl.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +/* We do not use linux/fcntl.h as it conflicts with glibc's fcntl.h. */ +#include + +/* The below are defined in linux/fcntl.h, but not defined in glibc's fcntl.h. + * They are necessary for linux/pidfd.h, hence define them here. */ +#define PIDFD_SELF_THREAD -10000 /* Current thread. */ +#define PIDFD_SELF_THREAD_GROUP -10001 /* Current thread group leader. */ diff --git a/src/include/override/sys/pidfd.h b/src/include/override/sys/pidfd.h index 28fb75698e..0f4d243d18 100644 --- a/src/include/override/sys/pidfd.h +++ b/src/include/override/sys/pidfd.h @@ -1,9 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include +/* Here, we do not use glibc's pidfd.h, as its definition of struct pidfd_info may be slightly older. */ +#include #include -#include /* Defined since glibc-2.36. * Supported since kernel v5.3 (7615d9e1780e26e0178c93c55b73309a5dc093d7). */ @@ -14,102 +14,3 @@ int pidfd_open_shim(pid_t pid, unsigned flags); * Supported since kernel v5.1 (3eb39f47934f9d5a3027fe00d906a45fe3a15fad). */ int pidfd_send_signal_shim(int fd, int sig, siginfo_t *info, unsigned flags); #define pidfd_send_signal pidfd_send_signal_shim - -/* since glibc-2.41 */ -#ifndef PIDFS_IOCTL_MAGIC -# define PIDFS_IOCTL_MAGIC 0xFF - -# define PIDFD_GET_CGROUP_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 1) -# define PIDFD_GET_IPC_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 2) -# define PIDFD_GET_MNT_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 3) -# define PIDFD_GET_NET_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 4) -# define PIDFD_GET_PID_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 5) -# define PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 6) -# define PIDFD_GET_TIME_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 7) -# define PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 8) -# define PIDFD_GET_USER_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 9) -# define PIDFD_GET_UTS_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 10) -#endif - -/* defined in linux/pidfd.h */ -#ifndef PIDFD_GET_INFO - -/* Flags for pidfd_info. */ -#define PIDFD_INFO_PID (1UL << 0) /* Always returned, even if not requested */ -#define PIDFD_INFO_CREDS (1UL << 1) /* Always returned, even if not requested */ -#define PIDFD_INFO_CGROUPID (1UL << 2) /* Always returned if available, even if not requested */ -#define PIDFD_INFO_EXIT (1UL << 3) /* Only returned if requested. */ -#define PIDFD_INFO_COREDUMP (1UL << 4) /* Only returned if requested. */ -#define PIDFD_INFO_SUPPORTED_MASK (1UL << 5) /* Want/got supported mask flags */ -#define PIDFD_INFO_COREDUMP_SIGNAL (1UL << 6) /* Always returned if PIDFD_INFO_COREDUMP is requested. */ -#define PIDFD_INFO_COREDUMP_CODE (1UL << 7) /* Always returned if PIDFD_INFO_COREDUMP is requested. */ - -#define PIDFD_INFO_SIZE_VER0 64 /* sizeof first published struct */ -#define PIDFD_INFO_SIZE_VER1 72 /* sizeof second published struct */ -#define PIDFD_INFO_SIZE_VER2 80 /* sizeof third published struct */ -#define PIDFD_INFO_SIZE_VER3 88 /* sizeof fourth published struct */ - -/* - * Values for @coredump_mask in pidfd_info. - * Only valid if PIDFD_INFO_COREDUMP is set in @mask. - * - * Note, the @PIDFD_COREDUMP_ROOT flag indicates that the generated - * coredump should be treated as sensitive and access should only be - * granted to privileged users. - */ -#define PIDFD_COREDUMPED (1U << 0) /* Did crash and... */ -#define PIDFD_COREDUMP_SKIP (1U << 1) /* coredumping generation was skipped. */ -#define PIDFD_COREDUMP_USER (1U << 2) /* coredump was done as the user. */ -#define PIDFD_COREDUMP_ROOT (1U << 3) /* coredump was done as root. */ - -struct pidfd_info { - /* - * This mask is similar to the request_mask in statx(2). - * - * Userspace indicates what extensions or expensive-to-calculate fields - * they want by setting the corresponding bits in mask. The kernel - * will ignore bits that it does not know about. - * - * When filling the structure, the kernel will only set bits - * corresponding to the fields that were actually filled by the kernel. - * This also includes any future extensions that might be automatically - * filled. If the structure size is too small to contain a field - * (requested or not), to avoid confusion the mask will not - * contain a bit for that field. - * - * As such, userspace MUST verify that mask contains the - * corresponding flags after the ioctl(2) returns to ensure that it is - * using valid data. - */ - __u64 mask; - /* - * The information contained in the following fields might be stale at the - * time it is received, as the target process might have exited as soon as - * the IOCTL was processed, and there is no way to avoid that. However, it - * is guaranteed that if the call was successful, then the information was - * correct and referred to the intended process at the time the work was - * performed. */ - __u64 cgroupid; - __u32 pid; - __u32 tgid; - __u32 ppid; - __u32 ruid; - __u32 rgid; - __u32 euid; - __u32 egid; - __u32 suid; - __u32 sgid; - __u32 fsuid; - __u32 fsgid; - __s32 exit_code; /* since kernel v6.15 (7477d7dce48a996ae4e4f0b5f7bd82de7ec9131b) */ - struct { /* coredump info */ - __u32 coredump_mask; /* since kernel v6.16 (1d8db6fd698de1f73b1a7d72aea578fdd18d9a87) */ - __u32 coredump_signal; /* since kernel v6.19 (036375522be8425874e9e0f907c7127e315c7a52) */ - __u32 coredump_code; /* since kernel v7.1 (701f7f4fbabbf4989ba6fbf033b160dd943221d5) */ - __u32 coredump_pad; /* since kernel v7.1 (701f7f4fbabbf4989ba6fbf033b160dd943221d5) */ - }; - __u64 supported_mask; /* Mask flags that this kernel supports */ -}; - -#define PIDFD_GET_INFO _IOWR(PIDFS_IOCTL_MAGIC, 11, struct pidfd_info) -#endif /* PIDFD_GET_INFO */ diff --git a/src/include/uapi/linux/ioctl.h b/src/include/uapi/linux/ioctl.h new file mode 100644 index 0000000000..b292e8093b --- /dev/null +++ b/src/include/uapi/linux/ioctl.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_IOCTL_H +#define _LINUX_IOCTL_H + +#include + +#endif /* _LINUX_IOCTL_H */ + diff --git a/src/include/uapi/linux/pidfd.h b/src/include/uapi/linux/pidfd.h new file mode 100644 index 0000000000..69873fffdf --- /dev/null +++ b/src/include/uapi/linux/pidfd.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +#ifndef _LINUX_PIDFD_H +#define _LINUX_PIDFD_H + +#include +#include +#include + +/* Flags for pidfd_open(). */ +#define PIDFD_NONBLOCK O_NONBLOCK +#define PIDFD_THREAD O_EXCL + +/* Flags for pidfd_send_signal(). */ +#define PIDFD_SIGNAL_THREAD (1UL << 0) +#define PIDFD_SIGNAL_THREAD_GROUP (1UL << 1) +#define PIDFD_SIGNAL_PROCESS_GROUP (1UL << 2) + +/* Flags for pidfd_info. */ +#define PIDFD_INFO_PID (1UL << 0) /* Always returned, even if not requested */ +#define PIDFD_INFO_CREDS (1UL << 1) /* Always returned, even if not requested */ +#define PIDFD_INFO_CGROUPID (1UL << 2) /* Always returned if available, even if not requested */ +#define PIDFD_INFO_EXIT (1UL << 3) /* Only returned if requested. */ +#define PIDFD_INFO_COREDUMP (1UL << 4) /* Only returned if requested. */ +#define PIDFD_INFO_SUPPORTED_MASK (1UL << 5) /* Want/got supported mask flags */ +#define PIDFD_INFO_COREDUMP_SIGNAL (1UL << 6) /* Always returned if PIDFD_INFO_COREDUMP is requested. */ +#define PIDFD_INFO_COREDUMP_CODE (1UL << 7) /* Always returned if PIDFD_INFO_COREDUMP is requested. */ + +#define PIDFD_INFO_SIZE_VER0 64 /* sizeof first published struct */ +#define PIDFD_INFO_SIZE_VER1 72 /* sizeof second published struct */ +#define PIDFD_INFO_SIZE_VER2 80 /* sizeof third published struct */ +#define PIDFD_INFO_SIZE_VER3 88 /* sizeof fourth published struct */ + +/* + * Values for @coredump_mask in pidfd_info. + * Only valid if PIDFD_INFO_COREDUMP is set in @mask. + * + * Note, the @PIDFD_COREDUMP_ROOT flag indicates that the generated + * coredump should be treated as sensitive and access should only be + * granted to privileged users. + */ +#define PIDFD_COREDUMPED (1U << 0) /* Did crash and... */ +#define PIDFD_COREDUMP_SKIP (1U << 1) /* coredumping generation was skipped. */ +#define PIDFD_COREDUMP_USER (1U << 2) /* coredump was done as the user. */ +#define PIDFD_COREDUMP_ROOT (1U << 3) /* coredump was done as root. */ + +/* + * ...and for userland we make life simpler - PIDFD_SELF refers to the current + * thread, PIDFD_SELF_PROCESS refers to the process thread group leader. + * + * For nearly all practical uses, a user will want to use PIDFD_SELF. + */ +#define PIDFD_SELF PIDFD_SELF_THREAD +#define PIDFD_SELF_PROCESS PIDFD_SELF_THREAD_GROUP + +struct pidfd_info { + /* + * This mask is similar to the request_mask in statx(2). + * + * Userspace indicates what extensions or expensive-to-calculate fields + * they want by setting the corresponding bits in mask. The kernel + * will ignore bits that it does not know about. + * + * When filling the structure, the kernel will only set bits + * corresponding to the fields that were actually filled by the kernel. + * This also includes any future extensions that might be automatically + * filled. If the structure size is too small to contain a field + * (requested or not), to avoid confusion the mask will not + * contain a bit for that field. + * + * As such, userspace MUST verify that mask contains the + * corresponding flags after the ioctl(2) returns to ensure that it is + * using valid data. + */ + __u64 mask; + /* + * The information contained in the following fields might be stale at the + * time it is received, as the target process might have exited as soon as + * the IOCTL was processed, and there is no way to avoid that. However, it + * is guaranteed that if the call was successful, then the information was + * correct and referred to the intended process at the time the work was + * performed. */ + __u64 cgroupid; + __u32 pid; + __u32 tgid; + __u32 ppid; + __u32 ruid; + __u32 rgid; + __u32 euid; + __u32 egid; + __u32 suid; + __u32 sgid; + __u32 fsuid; + __u32 fsgid; + __s32 exit_code; + struct /* coredump info */ { + __u32 coredump_mask; + __u32 coredump_signal; + __u32 coredump_code; + __u32 coredump_pad; /* align supported_mask to 8 bytes */ + }; + __u64 supported_mask; /* Mask flags that this kernel supports */ +}; + +#define PIDFS_IOCTL_MAGIC 0xFF + +#define PIDFD_GET_CGROUP_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 1) +#define PIDFD_GET_IPC_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 2) +#define PIDFD_GET_MNT_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 3) +#define PIDFD_GET_NET_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 4) +#define PIDFD_GET_PID_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 5) +#define PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 6) +#define PIDFD_GET_TIME_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 7) +#define PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 8) +#define PIDFD_GET_USER_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 9) +#define PIDFD_GET_UTS_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 10) +#define PIDFD_GET_INFO _IOWR(PIDFS_IOCTL_MAGIC, 11, struct pidfd_info) + +#endif /* _LINUX_PIDFD_H */ From 918f1462d773166ae51bebd002eec8829e3e7963 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 10 Aug 2026 23:58:59 +0900 Subject: [PATCH 2/3] pidref: introduce pidref_set_pid_full() and friends By passing the PIDFD_THREAD flag, we can get pidfd of a worker thread. The flag is supported since kernel v6.9. --- src/basic/pidref.c | 13 +++++++------ src/basic/pidref.h | 10 ++++++++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/basic/pidref.c b/src/basic/pidref.c index 649a207c1e..ff52ccc311 100644 --- a/src/basic/pidref.c +++ b/src/basic/pidref.c @@ -91,7 +91,7 @@ bool pidref_equal(PidRef *a, PidRef *b) { return a->fd_id == b->fd_id; } -int pidref_set_pid(PidRef *pidref, pid_t pid) { +int pidref_set_pid_full(PidRef *pidref, pid_t pid, unsigned flags) { uint64_t pidfdid = 0; int fd; @@ -104,10 +104,11 @@ int pidref_set_pid(PidRef *pidref, pid_t pid) { (void) pidfd_get_inode_id_self_cached(&pidfdid); } - fd = pidfd_open(pid, 0); + fd = pidfd_open(pid, flags); if (fd < 0) { - /* Graceful fallback in case the kernel is out of fds */ - if (!ERRNO_IS_RESOURCE(errno)) + /* Graceful fallback in case the kernel is out of fds. + * The PIDFD_THREAD flag is supported since kernel v6.9 (64bef697d33b75fc06c5789b3f8108680271529f). */ + if (!(ERRNO_IS_RESOURCE(errno) || (errno == EINVAL && FLAGS_SET(flags, PIDFD_THREAD)))) return log_debug_errno(errno, "Failed to open pidfd for pid " PID_FMT ": %m", pid); fd = -EBADF; @@ -149,7 +150,7 @@ int pidref_set_pid_and_pidfd_id( return 0; } -int pidref_set_pidstr(PidRef *pidref, const char *pid) { +int pidref_set_pidstr_full(PidRef *pidref, const char *pid, unsigned flags) { pid_t nr; int r; @@ -159,7 +160,7 @@ int pidref_set_pidstr(PidRef *pidref, const char *pid) { if (r < 0) return r; - return pidref_set_pid(pidref, nr); + return pidref_set_pid_full(pidref, nr, flags); } int pidref_set_pidfd(PidRef *pidref, int fd) { diff --git a/src/basic/pidref.h b/src/basic/pidref.h index a4c138c4bf..ceec126141 100644 --- a/src/basic/pidref.h +++ b/src/basic/pidref.h @@ -70,8 +70,14 @@ bool pidref_equal(PidRef *a, PidRef *b); /* This turns a pid_t into a PidRef structure, and acquires a pidfd for it, if possible. (As opposed to * PIDREF_MAKE_FROM_PID() above, which does not acquire a pidfd.) */ -int pidref_set_pid(PidRef *pidref, pid_t pid); -int pidref_set_pidstr(PidRef *pidref, const char *pid); +int pidref_set_pid_full(PidRef *pidref, pid_t pid, unsigned flags); +static inline int pidref_set_pid(PidRef *pidref, pid_t pid) { + return pidref_set_pid_full(pidref, pid, /* flags= */ 0); +} +int pidref_set_pidstr_full(PidRef *pidref, const char *pid, unsigned flags); +static inline int pidref_set_pidstr(PidRef *pidref, const char *pid) { + return pidref_set_pidstr_full(pidref, pid, /* flags= */ 0); +} int pidref_set_pid_and_pidfd_id(PidRef *pidref, pid_t pid, uint64_t pidfd_id); int pidref_set_pidfd(PidRef *pidref, int fd); int pidref_set_pidfd_take(PidRef *pidref, int fd); /* takes ownership of the passed pidfd on success */ From 534a73fd3ffe11e4eb9df05be83c61de651e4fb7 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 9 Aug 2026 06:47:31 +0900 Subject: [PATCH 3/3] coredump: do not leak TID in the host to container PID, UID, and GID are converted by sending struct ucred, however, TID was not converted. Let's convert TID if corresponding pidfd exists, and discards TID otherwise. Fixes 4c7af7d9d1cd40e2f36a87787ce2fab32400bf89. --- src/coredump/coredump-context.c | 13 +++++++------ src/coredump/coredump-context.h | 3 ++- src/coredump/coredump-send.c | 10 ++++++++++ src/coredump/coredump-submit.c | 4 ++-- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/coredump/coredump-context.c b/src/coredump/coredump-context.c index 24d273499a..f7e978bbfc 100644 --- a/src/coredump/coredump-context.c +++ b/src/coredump/coredump-context.c @@ -48,6 +48,7 @@ void coredump_context_done(CoredumpContext *context) { assert(context); pidref_done(&context->pidref); + pidref_done(&context->tidref); free(context->hostname); free(context->comm); free(context->exe); @@ -266,8 +267,8 @@ int coredump_context_build_iovw(CoredumpContext *context) { if (r < 0) return log_error_errno(r, "Failed to add COREDUMP_COMM= field: %m"); - if (context->tid > 0) - (void) iovw_put_string_fieldf(&context->iovw, "COREDUMP_TID=", PID_FMT, context->tid); + if (pidref_is_set(&context->tidref)) + (void) iovw_put_string_fieldf(&context->iovw, "COREDUMP_TID=", PID_FMT, context->tidref.pid); if (context->thread_name) (void) iovw_put_string_field(&context->iovw, "COREDUMP_THREAD_NAME=", context->thread_name); @@ -383,10 +384,10 @@ static int coredump_context_parse_from_procfs(CoredumpContext *context) { if (r < 0) return log_error_errno(r, "Failed to get COMM: %m"); - if (context->tid > 0) { - r = pid_get_comm(context->tid, &context->thread_name); + if (pidref_is_set(&context->tidref)) { + r = pidref_get_comm(&context->tidref, &context->thread_name); if (r < 0) - log_warning_errno(r, "Failed to get comm for thread "PID_FMT", ignoring: %m", context->tid); + log_warning_errno(r, "Failed to get comm for thread "PID_FMT", ignoring: %m", context->tidref.pid); } r = get_process_exe(pid, &context->exe); @@ -518,7 +519,7 @@ static int context_parse_one(CoredumpContext *context, MetadataField meta, bool return 0; } case META_ARGV_TID: - r = parse_pid(s, &context->tid); + r = pidref_set_pidstr_full(&context->tidref, s, PIDFD_THREAD); if (r < 0) log_warning_errno(r, "Failed to parse TID \"%s\", ignoring: %m", s); return 0; diff --git a/src/coredump/coredump-context.h b/src/coredump/coredump-context.h index a2ce16b853..ee4334dce2 100644 --- a/src/coredump/coredump-context.h +++ b/src/coredump/coredump-context.h @@ -57,7 +57,7 @@ struct CoredumpContext { uint64_t rlimit; /* META_ARGV_RLIMIT */ char *hostname; /* META_ARGV_HOSTNAME */ unsigned dumpable; /* META_ARGV_DUMPABLE */ - pid_t tid; /* META_ARGV_TID */ + PidRef tidref; /* META_ARGV_TID */ char *comm; /* META_COMM */ char *exe; /* META_EXE */ char *unit; /* META_UNIT */ @@ -78,6 +78,7 @@ struct CoredumpContext { .pidref = PIDREF_NULL, \ .uid = UID_INVALID, \ .gid = GID_INVALID, \ + .tidref = PIDREF_NULL, \ .mount_tree_fd = -EBADF, \ .input_fd = -EBADF, \ } diff --git a/src/coredump/coredump-send.c b/src/coredump/coredump-send.c index 4817d82611..5b77301206 100644 --- a/src/coredump/coredump-send.c +++ b/src/coredump/coredump-send.c @@ -301,6 +301,16 @@ int coredump_send_to_container(CoredumpContext *context) { context->uid = ucred.uid; context->gid = ucred.gid; + /* Do not leak the TID in the initial PID namespace. */ + int tidfd = TAKE_FD(context->tidref.fd); + pid_t tid = context->tidref.pid; + context->tidref = PIDREF_NULL; + if (tidfd >= 0) { + r = pidref_set_pidfd_consume(&context->tidref, tidfd); + if (r < 0) + log_warning_errno(r, "Failed to acquire PidRef of TID ["PID_FMT"], ignoring: %m", tid); + } + r = coredump_context_build_iovw(context); if (r < 0) _exit(EXIT_FAILURE); diff --git a/src/coredump/coredump-submit.c b/src/coredump/coredump-submit.c index fe1042ce4a..55f8b6e9e1 100644 --- a/src/coredump/coredump-submit.c +++ b/src/coredump/coredump-submit.c @@ -201,8 +201,8 @@ static int fix_xattr(int fd, const CoredumpContext *context) { RET_GATHER(r, fix_xattr_one(fd, "user.coredump.hostname", context->hostname)); RET_GATHER(r, fix_xattr_one(fd, "user.coredump.comm", context->comm)); RET_GATHER(r, fix_xattr_one(fd, "user.coredump.exe", context->exe)); - if (context->tid > 0) { - RET_GATHER(r, fix_xattr_format(fd, "user.coredump.tid", PID_FMT, context->tid)); + if (pidref_is_set(&context->tidref)) { + RET_GATHER(r, fix_xattr_format(fd, "user.coredump.tid", PID_FMT, context->tidref.pid)); RET_GATHER(r, fix_xattr_one(fd, "user.coredump.thread_name", context->thread_name)); }