Merge patch series "pidfds: add coredump_code field to pidfd_info"

Emanuele Rocca <emanuele.rocca@arm.com> says:

This patchs series adds a new field called coredump_code to struct
pidfd_info, as well as the relevant selftests. Note that the coredump
selftests are currently not passing.

* patches from https://patch.msgid.link/acE5fYOgyVUYahIn@NH27D9T0LF:
  selftests: check pidfd_info->coredump_code correctness
  pidfds: add coredump_code field to pidfd_info

Link: https://patch.msgid.link/acE5fYOgyVUYahIn@NH27D9T0LF
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Christian Brauner 2026-03-23 16:29:22 +01:00
commit d29eb5f0ce
No known key found for this signature in database
GPG key ID: 91C61BC06578DCA2
7 changed files with 78 additions and 6 deletions

View file

@ -57,6 +57,7 @@ struct pidfs_attr {
}; };
__u32 coredump_mask; __u32 coredump_mask;
__u32 coredump_signal; __u32 coredump_signal;
__u32 coredump_code;
}; };
static struct rhashtable pidfs_ino_ht; static struct rhashtable pidfs_ino_ht;
@ -333,7 +334,8 @@ static __u32 pidfs_coredump_mask(unsigned long mm_flags)
PIDFD_INFO_EXIT | \ PIDFD_INFO_EXIT | \
PIDFD_INFO_COREDUMP | \ PIDFD_INFO_COREDUMP | \
PIDFD_INFO_SUPPORTED_MASK | \ PIDFD_INFO_SUPPORTED_MASK | \
PIDFD_INFO_COREDUMP_SIGNAL) PIDFD_INFO_COREDUMP_SIGNAL | \
PIDFD_INFO_COREDUMP_CODE)
static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg) static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
{ {
@ -347,7 +349,7 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
const struct cred *c; const struct cred *c;
__u64 mask; __u64 mask;
BUILD_BUG_ON(sizeof(struct pidfd_info) != PIDFD_INFO_SIZE_VER2); BUILD_BUG_ON(sizeof(struct pidfd_info) != PIDFD_INFO_SIZE_VER3);
if (!uinfo) if (!uinfo)
return -EINVAL; return -EINVAL;
@ -380,9 +382,10 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
if (mask & PIDFD_INFO_COREDUMP) { if (mask & PIDFD_INFO_COREDUMP) {
if (test_bit(PIDFS_ATTR_BIT_COREDUMP, &attr->attr_mask)) { if (test_bit(PIDFS_ATTR_BIT_COREDUMP, &attr->attr_mask)) {
smp_rmb(); smp_rmb();
kinfo.mask |= PIDFD_INFO_COREDUMP | PIDFD_INFO_COREDUMP_SIGNAL; kinfo.mask |= PIDFD_INFO_COREDUMP | PIDFD_INFO_COREDUMP_SIGNAL | PIDFD_INFO_COREDUMP_CODE;
kinfo.coredump_mask = attr->coredump_mask; kinfo.coredump_mask = attr->coredump_mask;
kinfo.coredump_signal = attr->coredump_signal; kinfo.coredump_signal = attr->coredump_signal;
kinfo.coredump_code = attr->coredump_code;
} }
} }
@ -755,8 +758,9 @@ void pidfs_coredump(const struct coredump_params *cprm)
PIDFD_COREDUMPED; PIDFD_COREDUMPED;
/* If coredumping is set to skip we should never end up here. */ /* If coredumping is set to skip we should never end up here. */
VFS_WARN_ON_ONCE(attr->coredump_mask & PIDFD_COREDUMP_SKIP); VFS_WARN_ON_ONCE(attr->coredump_mask & PIDFD_COREDUMP_SKIP);
/* Expose the signal number that caused the coredump. */ /* Expose the signal number and code that caused the coredump. */
attr->coredump_signal = cprm->siginfo->si_signo; attr->coredump_signal = cprm->siginfo->si_signo;
attr->coredump_code = cprm->siginfo->si_code;
smp_wmb(); smp_wmb();
set_bit(PIDFS_ATTR_BIT_COREDUMP, &attr->attr_mask); set_bit(PIDFS_ATTR_BIT_COREDUMP, &attr->attr_mask);
} }

View file

@ -29,10 +29,12 @@
#define PIDFD_INFO_COREDUMP (1UL << 4) /* 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_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_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_VER0 64 /* sizeof first published struct */
#define PIDFD_INFO_SIZE_VER1 72 /* sizeof second 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_VER2 80 /* sizeof third published struct */
#define PIDFD_INFO_SIZE_VER3 88 /* sizeof fourth published struct */
/* /*
* Values for @coredump_mask in pidfd_info. * Values for @coredump_mask in pidfd_info.
@ -99,6 +101,8 @@ struct pidfd_info {
struct /* coredump info */ { struct /* coredump info */ {
__u32 coredump_mask; __u32 coredump_mask;
__u32 coredump_signal; __u32 coredump_signal;
__u32 coredump_code;
__u32 coredump_pad; /* align supported_mask to 8 bytes */
}; };
__u64 supported_mask; /* Mask flags that this kernel supports */ __u64 supported_mask; /* Mask flags that this kernel supports */
}; };

View file

@ -1004,6 +1004,8 @@ out:
* *
* Verify that when using socket-based coredump protocol, * Verify that when using socket-based coredump protocol,
* the coredump_signal field is correctly exposed as SIGSEGV. * the coredump_signal field is correctly exposed as SIGSEGV.
* Also check that the coredump_code field is correctly exposed
* as SEGV_MAPERR.
*/ */
TEST_F(coredump, socket_coredump_signal_sigsegv) TEST_F(coredump, socket_coredump_signal_sigsegv)
{ {
@ -1079,6 +1081,18 @@ TEST_F(coredump, socket_coredump_signal_sigsegv)
goto out; goto out;
} }
/* Verify coredump_code is available and correct */
if (!(info.mask & PIDFD_INFO_COREDUMP_CODE)) {
fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP_CODE not set in mask\n");
goto out;
}
if (info.coredump_code != SEGV_MAPERR) {
fprintf(stderr, "socket_coredump_signal_sigsegv: coredump_code=%d, expected SEGV_MAPERR=%d\n",
info.coredump_code, SEGV_MAPERR);
goto out;
}
if (!read_coredump_req(fd_coredump, &req)) { if (!read_coredump_req(fd_coredump, &req)) {
fprintf(stderr, "socket_coredump_signal_sigsegv: read_coredump_req failed\n"); fprintf(stderr, "socket_coredump_signal_sigsegv: read_coredump_req failed\n");
goto out; goto out;
@ -1128,6 +1142,8 @@ out:
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP)); ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)); ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
ASSERT_EQ(info.coredump_signal, SIGSEGV); ASSERT_EQ(info.coredump_signal, SIGSEGV);
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_CODE));
ASSERT_EQ(info.coredump_code, SEGV_MAPERR);
wait_and_check_coredump_server(pid_coredump_server, _metadata, self); wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
} }
@ -1137,6 +1153,8 @@ out:
* *
* Verify that when using socket-based coredump protocol, * Verify that when using socket-based coredump protocol,
* the coredump_signal field is correctly exposed as SIGABRT. * the coredump_signal field is correctly exposed as SIGABRT.
* Also check that the coredump_code field is correctly exposed
* as SI_TKILL.
*/ */
TEST_F(coredump, socket_coredump_signal_sigabrt) TEST_F(coredump, socket_coredump_signal_sigabrt)
{ {
@ -1212,6 +1230,12 @@ TEST_F(coredump, socket_coredump_signal_sigabrt)
goto out; goto out;
} }
if (info.coredump_code != SI_TKILL) {
fprintf(stderr, "socket_coredump_signal_sigabrt: coredump_code=%d, expected SI_TKILL=%d\n",
info.coredump_code, SI_TKILL);
goto out;
}
if (!read_coredump_req(fd_coredump, &req)) { if (!read_coredump_req(fd_coredump, &req)) {
fprintf(stderr, "socket_coredump_signal_sigabrt: read_coredump_req failed\n"); fprintf(stderr, "socket_coredump_signal_sigabrt: read_coredump_req failed\n");
goto out; goto out;
@ -1261,6 +1285,8 @@ out:
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP)); ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)); ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
ASSERT_EQ(info.coredump_signal, SIGABRT); ASSERT_EQ(info.coredump_signal, SIGABRT);
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_CODE));
ASSERT_EQ(info.coredump_code, SI_TKILL);
wait_and_check_coredump_server(pid_coredump_server, _metadata, self); wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
} }

View file

@ -435,6 +435,8 @@ out:
* *
* Verify that when using simple socket-based coredump (@ pattern), * Verify that when using simple socket-based coredump (@ pattern),
* the coredump_signal field is correctly exposed as SIGSEGV. * the coredump_signal field is correctly exposed as SIGSEGV.
* Also check that the coredump_code field is correctly exposed
* as SEGV_MAPERR.
*/ */
TEST_F(coredump, socket_coredump_signal_sigsegv) TEST_F(coredump, socket_coredump_signal_sigsegv)
{ {
@ -509,6 +511,18 @@ TEST_F(coredump, socket_coredump_signal_sigsegv)
goto out; goto out;
} }
/* Verify coredump_code is available and correct */
if (!(info.mask & PIDFD_INFO_COREDUMP_CODE)) {
fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP_CODE not set in mask\n");
goto out;
}
if (info.coredump_code != SEGV_MAPERR) {
fprintf(stderr, "socket_coredump_signal_sigsegv: coredump_code=%d, expected SEGV_MAPERR=%d\n",
info.coredump_code, SEGV_MAPERR);
goto out;
}
fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached); fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
if (fd_core_file < 0) { if (fd_core_file < 0) {
fprintf(stderr, "socket_coredump_signal_sigsegv: open_coredump_tmpfile failed: %m\n"); fprintf(stderr, "socket_coredump_signal_sigsegv: open_coredump_tmpfile failed: %m\n");
@ -572,6 +586,8 @@ out:
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP)); ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)); ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
ASSERT_EQ(info.coredump_signal, SIGSEGV); ASSERT_EQ(info.coredump_signal, SIGSEGV);
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_CODE));
ASSERT_EQ(info.coredump_code, SEGV_MAPERR);
wait_and_check_coredump_server(pid_coredump_server, _metadata, self); wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
} }
@ -581,6 +597,8 @@ out:
* *
* Verify that when using simple socket-based coredump (@ pattern), * Verify that when using simple socket-based coredump (@ pattern),
* the coredump_signal field is correctly exposed as SIGABRT. * the coredump_signal field is correctly exposed as SIGABRT.
* Also check that the coredump_code field is correctly exposed
* as SI_TKILL.
*/ */
TEST_F(coredump, socket_coredump_signal_sigabrt) TEST_F(coredump, socket_coredump_signal_sigabrt)
{ {
@ -655,6 +673,18 @@ TEST_F(coredump, socket_coredump_signal_sigabrt)
goto out; goto out;
} }
/* Verify coredump_code is available and correct */
if (!(info.mask & PIDFD_INFO_COREDUMP_CODE)) {
fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP_CODE not set in mask\n");
goto out;
}
if (info.coredump_code != SI_TKILL) {
fprintf(stderr, "socket_coredump_signal_sigabrt: coredump_code=%d, expected SI_TKILL=%d\n",
info.coredump_code, SI_TKILL);
goto out;
}
fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached); fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
if (fd_core_file < 0) { if (fd_core_file < 0) {
fprintf(stderr, "socket_coredump_signal_sigabrt: open_coredump_tmpfile failed: %m\n"); fprintf(stderr, "socket_coredump_signal_sigabrt: open_coredump_tmpfile failed: %m\n");
@ -718,6 +748,8 @@ out:
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP)); ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)); ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
ASSERT_EQ(info.coredump_signal, SIGABRT); ASSERT_EQ(info.coredump_signal, SIGABRT);
ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_CODE));
ASSERT_EQ(info.coredump_code, SI_TKILL);
wait_and_check_coredump_server(pid_coredump_server, _metadata, self); wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
} }

View file

@ -148,8 +148,8 @@ bool get_pidfd_info(int fd_peer_pidfd, struct pidfd_info *info)
fprintf(stderr, "get_pidfd_info: ioctl(PIDFD_GET_INFO) failed: %m\n"); fprintf(stderr, "get_pidfd_info: ioctl(PIDFD_GET_INFO) failed: %m\n");
return false; return false;
} }
fprintf(stderr, "get_pidfd_info: mask=0x%llx, coredump_mask=0x%x, coredump_signal=%d\n", fprintf(stderr, "get_pidfd_info: mask=0x%llx, coredump_mask=0x%x, coredump_signal=%d, coredump_code=%d\n",
(unsigned long long)info->mask, info->coredump_mask, info->coredump_signal); (unsigned long long)info->mask, info->coredump_mask, info->coredump_signal, info->coredump_code);
return true; return true;
} }

View file

@ -156,6 +156,10 @@
#define PIDFD_INFO_COREDUMP_SIGNAL (1UL << 6) #define PIDFD_INFO_COREDUMP_SIGNAL (1UL << 6)
#endif #endif
#ifndef PIDFD_INFO_COREDUMP_CODE
#define PIDFD_INFO_COREDUMP_CODE (1UL << 7)
#endif
#ifndef PIDFD_COREDUMPED #ifndef PIDFD_COREDUMPED
#define PIDFD_COREDUMPED (1U << 0) /* Did crash and... */ #define PIDFD_COREDUMPED (1U << 0) /* Did crash and... */
#endif #endif
@ -194,6 +198,7 @@ struct pidfd_info {
struct { struct {
__u32 coredump_mask; __u32 coredump_mask;
__u32 coredump_signal; __u32 coredump_signal;
__u32 coredump_code;
}; };
__u64 supported_mask; __u64 supported_mask;
}; };

View file

@ -724,6 +724,7 @@ TEST(supported_mask_field)
ASSERT_TRUE(!!(info.supported_mask & PIDFD_INFO_COREDUMP)); ASSERT_TRUE(!!(info.supported_mask & PIDFD_INFO_COREDUMP));
ASSERT_TRUE(!!(info.supported_mask & PIDFD_INFO_SUPPORTED_MASK)); ASSERT_TRUE(!!(info.supported_mask & PIDFD_INFO_SUPPORTED_MASK));
ASSERT_TRUE(!!(info.supported_mask & PIDFD_INFO_COREDUMP_SIGNAL)); ASSERT_TRUE(!!(info.supported_mask & PIDFD_INFO_COREDUMP_SIGNAL));
ASSERT_TRUE(!!(info.supported_mask & PIDFD_INFO_COREDUMP_CODE));
/* Clean up */ /* Clean up */
sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0); sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0);