* [PATCH v1] pidfs: do not report fields that do not fit into the caller's struct
@ 2026-10-17 2:06 Nickolai Zeldovich
2026-10-21 10:42 ` Christian Brauner
2026-10-24 4:13 ` [PATCH v2 0/2] " Nickolai Zeldovich
0 siblings, 2 replies; 6+ messages in thread
From: Nickolai Zeldovich @ 2026-10-17 2:06 UTC (permalink / raw)
To: Christian Brauner
Cc: Alexander Viro, Jan Kara, Shuah Khan, Jann Horn,
Alexander Mikhalitsyn, Luca Boccassi, linux-fsdevel,
linux-kselftest, linux-kernel, Nickolai Zeldovich
The documentation of struct pidfd_info promises that "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", and asks
userspace to trust the returned mask when deciding which fields hold
valid data.
pidfd_info() does not keep that promise. It builds kinfo.mask without
looking at the size encoded in the ioctl command, and
copy_struct_to_user() then truncates the copy to that size. A caller
that passes a 64-byte struct (PIDFD_INFO_SIZE_VER0) and requests
PIDFD_INFO_COREDUMP or PIDFD_INFO_SUPPORTED_MASK gets a mask with
PIDFD_INFO_COREDUMP, PIDFD_INFO_COREDUMP_SIGNAL, PIDFD_INFO_COREDUMP_CODE
and PIDFD_INFO_SUPPORTED_MASK set, while the coredump_* and
supported_mask fields behind the 64 bytes were never written. Trusting
the mask as documented, userspace then reads whatever its own buffer
held at those offsets. The same happens for a 72- or 80-byte struct
and the fields added after it.
Clear the bits of the fields that lie beyond the caller's size before
the copy, in the one place that knows both the final mask and the size.
A request for a field that cannot be returned is thereby answered the
way the header describes: the field is simply absent from the mask.
The added selftest issues PIDFD_GET_INFO with the first published size
over a full-size, poisoned struct and checks that the mask names none
of the fields beyond that size and that the poison is intact. It fails
on an unpatched kernel and passes with this change.
Found by formal verification of fs/pidfs.c against the kernel binary.
Fixes: 1d8db6fd698d ("pidfs, coredump: add PIDFD_INFO_COREDUMP")
Assisted-by: LLM
Signed-off-by: Nickolai Zeldovich <nickolai@csail.mit.edu>
---
Notes:
The three size thresholds follow the field layout: coredump_mask and
coredump_signal end at PIDFD_INFO_SIZE_VER1 (72), coredump_code at
PIDFD_INFO_SIZE_VER2 (80), supported_mask at PIDFD_INFO_SIZE_VER3 (88).
Masking the request bits early instead (before the coredump and
supported_mask blocks run) would save a little work for such callers
but leaves the bits set in the task->mm fallback path; clearing the
result once before copy_struct_to_user() covers every way a bit can be
set. No stable tag: the only callers affected pass a struct size
smaller than the fields they request, and the consequence is a wrong
mask bit, not a crash or corruption.
fs/pidfs.c | 8 ++++
tools/testing/selftests/pidfd/pidfd.h | 16 +++++++
.../testing/selftests/pidfd/pidfd_info_test.c | 48 +++++++++++++++++++
3 files changed, 72 insertions(+)
diff --git a/fs/pidfs.c b/fs/pidfs.c
index a6a643f15d08..b20f507c6bdf 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -485,6 +485,14 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
kinfo.supported_mask = PIDFD_INFO_SUPPORTED;
}
+ /* Only report fields that fit into the caller's struct. */
+ if (usize < PIDFD_INFO_SIZE_VER1)
+ kinfo.mask &= ~(PIDFD_INFO_COREDUMP | PIDFD_INFO_COREDUMP_SIGNAL);
+ if (usize < PIDFD_INFO_SIZE_VER2)
+ kinfo.mask &= ~PIDFD_INFO_COREDUMP_CODE;
+ if (usize < PIDFD_INFO_SIZE_VER3)
+ kinfo.mask &= ~PIDFD_INFO_SUPPORTED_MASK;
+
/* Are there bits in the return mask not present in PIDFD_INFO_SUPPORTED? */
WARN_ON_ONCE(~PIDFD_INFO_SUPPORTED & kinfo.mask);
/*
diff --git a/tools/testing/selftests/pidfd/pidfd.h b/tools/testing/selftests/pidfd/pidfd.h
index 5a4e78c10f43..cf146d327334 100644
--- a/tools/testing/selftests/pidfd/pidfd.h
+++ b/tools/testing/selftests/pidfd/pidfd.h
@@ -160,6 +160,22 @@
#define PIDFD_INFO_COREDUMP_CODE (1UL << 7)
#endif
+#ifndef PIDFD_INFO_SIZE_VER0
+#define PIDFD_INFO_SIZE_VER0 64 /* sizeof first published struct */
+#endif
+
+#ifndef PIDFD_INFO_SIZE_VER1
+#define PIDFD_INFO_SIZE_VER1 72 /* sizeof second published struct */
+#endif
+
+#ifndef PIDFD_INFO_SIZE_VER2
+#define PIDFD_INFO_SIZE_VER2 80 /* sizeof third published struct */
+#endif
+
+#ifndef PIDFD_INFO_SIZE_VER3
+#define PIDFD_INFO_SIZE_VER3 88 /* sizeof fourth published struct */
+#endif
+
#ifndef PIDFD_COREDUMPED
#define PIDFD_COREDUMPED (1U << 0) /* Did crash and... */
#endif
diff --git a/tools/testing/selftests/pidfd/pidfd_info_test.c b/tools/testing/selftests/pidfd/pidfd_info_test.c
index 597012ed195f..ee08df3dc3d2 100644
--- a/tools/testing/selftests/pidfd/pidfd_info_test.c
+++ b/tools/testing/selftests/pidfd/pidfd_info_test.c
@@ -764,4 +764,52 @@ TEST(supported_mask_with_other_fields)
close(pidfd);
}
+/*
+ * Test: fields beyond the caller's struct size are not reported
+ *
+ * Request the coredump and supported_mask fields with a struct of the
+ * first published size. None of those fields fit, so the returned mask
+ * must not name them and the memory behind the struct must be untouched.
+ */
+TEST(info_size_ver0_mask)
+{
+ struct pidfd_info info = {
+ .mask = PIDFD_INFO_COREDUMP | PIDFD_INFO_SUPPORTED_MASK,
+ .coredump_mask = 0xdeadbeef,
+ .coredump_signal = 0xdeadbeef,
+ .coredump_code = 0xdeadbeef,
+ .supported_mask = 0xdeadbeefdeadbeefULL,
+ };
+ unsigned int cmd = _IOC(_IOC_READ | _IOC_WRITE, PIDFS_IOCTL_MAGIC, 11,
+ PIDFD_INFO_SIZE_VER0);
+ int pidfd;
+ pid_t pid;
+
+ pid = create_child(&pidfd, 0);
+ ASSERT_GE(pid, 0);
+
+ if (pid == 0)
+ pause();
+
+ ASSERT_EQ(ioctl(pidfd, cmd, &info), 0);
+
+ /* The fields that fit are reported as usual. */
+ ASSERT_TRUE(!!(info.mask & PIDFD_INFO_PID));
+ ASSERT_TRUE(!!(info.mask & PIDFD_INFO_CREDS));
+
+ /* The fields that do not fit are neither reported nor written. */
+ ASSERT_FALSE(!!(info.mask & (PIDFD_INFO_COREDUMP |
+ PIDFD_INFO_COREDUMP_SIGNAL |
+ PIDFD_INFO_COREDUMP_CODE |
+ PIDFD_INFO_SUPPORTED_MASK)));
+ ASSERT_EQ(info.coredump_mask, 0xdeadbeef);
+ ASSERT_EQ(info.coredump_signal, 0xdeadbeef);
+ ASSERT_EQ(info.coredump_code, 0xdeadbeef);
+ ASSERT_EQ(info.supported_mask, 0xdeadbeefdeadbeefULL);
+
+ sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0);
+ sys_waitid(P_PIDFD, pidfd, NULL, WEXITED);
+ close(pidfd);
+}
+
TEST_HARNESS_MAIN
base-commit: 70dd4ee72eb2d5793c62e71c14e3aba78e5a4e56
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v1] pidfs: do not report fields that do not fit into the caller's struct
2026-10-17 2:06 [PATCH v1] pidfs: do not report fields that do not fit into the caller's struct Nickolai Zeldovich
@ 2026-10-21 10:42 ` Christian Brauner
2026-10-24 4:13 ` [PATCH v2 0/2] " Nickolai Zeldovich
1 sibling, 0 replies; 6+ messages in thread
From: Christian Brauner @ 2026-10-21 10:42 UTC (permalink / raw)
To: Nickolai Zeldovich
Cc: Christian Brauner, Alexander Viro, Jan Kara, Shuah Khan,
Jann Horn, Alexander Mikhalitsyn, Luca Boccassi, linux-fsdevel,
linux-kselftest, linux-kernel
> The documentation of struct pidfd_info promises that "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", and asks
> userspace to trust the returned mask when deciding which fields hold
> valid data.
>
> pidfd_info() does not keep that promise. It builds kinfo.mask without
> looking at the size encoded in the ioctl command, and
> copy_struct_to_user() then truncates the copy to that size. A caller
> that passes a 64-byte struct (PIDFD_INFO_SIZE_VER0) and requests
> PIDFD_INFO_COREDUMP or PIDFD_INFO_SUPPORTED_MASK gets a mask with
> PIDFD_INFO_COREDUMP, PIDFD_INFO_COREDUMP_SIGNAL, PIDFD_INFO_COREDUMP_CODE
> and PIDFD_INFO_SUPPORTED_MASK set, while the coredump_* and
> supported_mask fields behind the 64 bytes were never written. Trusting
> the mask as documented, userspace then reads whatever its own buffer
> held at those offsets. The same happens for a 72- or 80-byte struct
> and the fields added after it.
>
> Clear the bits of the fields that lie beyond the caller's size before
> the copy, in the one place that knows both the final mask and the size.
> A request for a field that cannot be returned is thereby answered the
> way the header describes: the field is simply absent from the mask.
>
> The added selftest issues PIDFD_GET_INFO with the first published size
> over a full-size, poisoned struct and checks that the mask names none
> of the fields beyond that size and that the poison is intact. It fails
> on an unpatched kernel and passes with this change.
>
> Found by formal verification of fs/pidfs.c against the kernel binary.
>
> Fixes: 1d8db6fd698d ("pidfs, coredump: add PIDFD_INFO_COREDUMP")
> Signed-off-by: Nickolai Zeldovich <nickolai@csail.mit.edu>
> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
> ---
> Notes:
> The three size thresholds follow the field layout: coredump_mask and
> coredump_signal end at PIDFD_INFO_SIZE_VER1 (72), coredump_code at
> PIDFD_INFO_SIZE_VER2 (80), supported_mask at PIDFD_INFO_SIZE_VER3 (88).
> Masking the request bits early instead (before the coredump and
> supported_mask blocks run) would save a little work for such callers
> but leaves the bits set in the task->mm fallback path; clearing the
> result once before copy_struct_to_user() covers every way a bit can be
> set. No stable tag: the only callers affected pass a struct size
> smaller than the fields they request, and the consequence is a wrong
> mask bit, not a crash or corruption.
>
> fs/pidfs.c | 8 ++++
> tools/testing/selftests/pidfd/pidfd.h | 16 +++++++
> .../testing/selftests/pidfd/pidfd_info_test.c | 48 +++++++++++++++++++
Semantic changes and selftest changes in separate patches, please.
--
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 0/2] pidfs: do not report fields that do not fit into the caller's struct
2026-10-17 2:06 [PATCH v1] pidfs: do not report fields that do not fit into the caller's struct Nickolai Zeldovich
2026-10-21 10:42 ` Christian Brauner
@ 2026-10-24 4:13 ` Nickolai Zeldovich
2026-10-24 4:13 ` [PATCH v2 1/2] " Nickolai Zeldovich
2026-10-24 4:13 ` [PATCH v2 2/2] selftests/pidfd: test that fields beyond the struct size are not reported Nickolai Zeldovich
1 sibling, 2 replies; 6+ messages in thread
From: Nickolai Zeldovich @ 2026-10-24 4:13 UTC (permalink / raw)
To: Christian Brauner
Cc: Alexander Viro, Jan Kara, Shuah Khan, Jann Horn,
Alexander Mikhalitsyn, Luca Boccassi, linux-fsdevel,
linux-kselftest, linux-kernel, Nickolai Zeldovich
PIDFD_GET_INFO sets the mask bits of fields that lie beyond the struct
size the caller passed, although the uapi header promises that the mask
names no such field and tells userspace to rely on the mask. Patch 1
clears those bits before the copy. Patch 2 adds a selftest for it.
Tested in a QEMU x86_64 guest: the new test fails without patch 1 and
passes with it, and the other pidfd selftests give the same results with
and without patch 1. Built with W=1 for x86_64.
The bug was found and fixed with the assistance of an AI agent.
Changes in v2:
- Split the selftest into its own patch (Christian Brauner).
- Rebased onto current mainline. struct pidfd_info has no new fields
since v1, so the size checks are unchanged.
v1: https://lore.kernel.org/all/20261017020634.792390-1-nickolai@csail.mit.edu/
Nickolai Zeldovich (2):
pidfs: do not report fields that do not fit into the caller's struct
selftests/pidfd: test that fields beyond the struct size are not
reported
fs/pidfs.c | 8 ++++
tools/testing/selftests/pidfd/pidfd.h | 16 +++++++
.../testing/selftests/pidfd/pidfd_info_test.c | 48 +++++++++++++++++++
3 files changed, 72 insertions(+)
base-commit: 17bb0e2f6c8043f70a693a5f3797471cbed354c8
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/2] pidfs: do not report fields that do not fit into the caller's struct
2026-10-24 4:13 ` [PATCH v2 0/2] " Nickolai Zeldovich
@ 2026-10-24 4:13 ` Nickolai Zeldovich
2026-10-24 9:06 ` Luca Boccassi
2026-10-24 4:13 ` [PATCH v2 2/2] selftests/pidfd: test that fields beyond the struct size are not reported Nickolai Zeldovich
1 sibling, 1 reply; 6+ messages in thread
From: Nickolai Zeldovich @ 2026-10-24 4:13 UTC (permalink / raw)
To: Christian Brauner
Cc: Alexander Viro, Jan Kara, Shuah Khan, Jann Horn,
Alexander Mikhalitsyn, Luca Boccassi, linux-fsdevel,
linux-kselftest, linux-kernel, Nickolai Zeldovich
The documentation of struct pidfd_info promises that "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", and asks
userspace to trust the returned mask when deciding which fields hold
valid data.
pidfd_info() does not keep that promise. It builds kinfo.mask without
looking at the size encoded in the ioctl command, and
copy_struct_to_user() then truncates the copy to that size. A caller
that passes a 64-byte struct (PIDFD_INFO_SIZE_VER0) and requests
PIDFD_INFO_COREDUMP or PIDFD_INFO_SUPPORTED_MASK gets a mask with
PIDFD_INFO_COREDUMP, PIDFD_INFO_COREDUMP_SIGNAL, PIDFD_INFO_COREDUMP_CODE
and PIDFD_INFO_SUPPORTED_MASK set, while the coredump_* and
supported_mask fields behind the 64 bytes were never written. Trusting
the mask as documented, userspace then reads whatever its own buffer
held at those offsets. The same happens for a 72- or 80-byte struct
and the fields added after it.
Clear the bits of the fields that lie beyond the caller's size before
the copy, in the one place that knows both the final mask and the size.
A request for a field that cannot be returned is thereby answered the
way the header describes: the field is simply absent from the mask.
Fixes: 1d8db6fd698d ("pidfs, coredump: add PIDFD_INFO_COREDUMP")
Signed-off-by: Nickolai Zeldovich <nickolai@csail.mit.edu>
---
Notes:
The three size thresholds follow the field layout: coredump_mask and
coredump_signal end at PIDFD_INFO_SIZE_VER1 (72), coredump_code at
PIDFD_INFO_SIZE_VER2 (80), supported_mask at PIDFD_INFO_SIZE_VER3 (88).
Masking the request bits early instead (before the coredump and
supported_mask blocks run) would save a little work for such callers
but leaves PIDFD_INFO_COREDUMP set by the dumpable-state fallback for a
live task; clearing the result once before copy_struct_to_user() covers
every way a bit can be set.
fs/pidfs.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/fs/pidfs.c b/fs/pidfs.c
index 7f8c323ce6cb8..cdb0916eae71b 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -485,6 +485,14 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
kinfo.supported_mask = PIDFD_INFO_SUPPORTED;
}
+ /* Only report fields that fit into the caller's struct. */
+ if (usize < PIDFD_INFO_SIZE_VER1)
+ kinfo.mask &= ~(PIDFD_INFO_COREDUMP | PIDFD_INFO_COREDUMP_SIGNAL);
+ if (usize < PIDFD_INFO_SIZE_VER2)
+ kinfo.mask &= ~PIDFD_INFO_COREDUMP_CODE;
+ if (usize < PIDFD_INFO_SIZE_VER3)
+ kinfo.mask &= ~PIDFD_INFO_SUPPORTED_MASK;
+
/* Are there bits in the return mask not present in PIDFD_INFO_SUPPORTED? */
WARN_ON_ONCE(~PIDFD_INFO_SUPPORTED & kinfo.mask);
/*
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 2/2] selftests/pidfd: test that fields beyond the struct size are not reported
2026-10-24 4:13 ` [PATCH v2 0/2] " Nickolai Zeldovich
2026-10-24 4:13 ` [PATCH v2 1/2] " Nickolai Zeldovich
@ 2026-10-24 4:13 ` Nickolai Zeldovich
1 sibling, 0 replies; 6+ messages in thread
From: Nickolai Zeldovich @ 2026-10-24 4:13 UTC (permalink / raw)
To: Christian Brauner
Cc: Alexander Viro, Jan Kara, Shuah Khan, Jann Horn,
Alexander Mikhalitsyn, Luca Boccassi, linux-fsdevel,
linux-kselftest, linux-kernel, Nickolai Zeldovich
PIDFD_GET_INFO must not set the mask bit of a field that lies beyond
the struct size encoded in the ioctl command. Add a test that requests
the coredump fields and the supported mask with PIDFD_INFO_SIZE_VER0
over a full-size, poisoned struct, and checks that the mask names none
of those fields and that the poison behind the first 64 bytes is
intact.
Add fallback definitions of PIDFD_INFO_SIZE_VER0 to VER3 to pidfd.h,
like the other uapi constants there.
Signed-off-by: Nickolai Zeldovich <nickolai@csail.mit.edu>
---
Notes:
Result in a QEMU x86_64 guest on mainline 17bb0e2f6c80, without
patch 1:
# pidfd_info_test.c:801:info_size_ver0_mask:Expected 0 (0) == !!(info.mask & (PIDFD_INFO_COREDUMP | ...)) (1)
not ok 3 global.info_size_ver0_mask
With patch 1:
ok 3 global.info_size_ver0_mask
tools/testing/selftests/pidfd/pidfd.h | 16 +++++++
.../testing/selftests/pidfd/pidfd_info_test.c | 48 +++++++++++++++++++
2 files changed, 64 insertions(+)
diff --git a/tools/testing/selftests/pidfd/pidfd.h b/tools/testing/selftests/pidfd/pidfd.h
index 5a4e78c10f434..cf146d3273348 100644
--- a/tools/testing/selftests/pidfd/pidfd.h
+++ b/tools/testing/selftests/pidfd/pidfd.h
@@ -160,6 +160,22 @@
#define PIDFD_INFO_COREDUMP_CODE (1UL << 7)
#endif
+#ifndef PIDFD_INFO_SIZE_VER0
+#define PIDFD_INFO_SIZE_VER0 64 /* sizeof first published struct */
+#endif
+
+#ifndef PIDFD_INFO_SIZE_VER1
+#define PIDFD_INFO_SIZE_VER1 72 /* sizeof second published struct */
+#endif
+
+#ifndef PIDFD_INFO_SIZE_VER2
+#define PIDFD_INFO_SIZE_VER2 80 /* sizeof third published struct */
+#endif
+
+#ifndef PIDFD_INFO_SIZE_VER3
+#define PIDFD_INFO_SIZE_VER3 88 /* sizeof fourth published struct */
+#endif
+
#ifndef PIDFD_COREDUMPED
#define PIDFD_COREDUMPED (1U << 0) /* Did crash and... */
#endif
diff --git a/tools/testing/selftests/pidfd/pidfd_info_test.c b/tools/testing/selftests/pidfd/pidfd_info_test.c
index 597012ed195f0..ee08df3dc3d2b 100644
--- a/tools/testing/selftests/pidfd/pidfd_info_test.c
+++ b/tools/testing/selftests/pidfd/pidfd_info_test.c
@@ -764,4 +764,52 @@ TEST(supported_mask_with_other_fields)
close(pidfd);
}
+/*
+ * Test: fields beyond the caller's struct size are not reported
+ *
+ * Request the coredump and supported_mask fields with a struct of the
+ * first published size. None of those fields fit, so the returned mask
+ * must not name them and the memory behind the struct must be untouched.
+ */
+TEST(info_size_ver0_mask)
+{
+ struct pidfd_info info = {
+ .mask = PIDFD_INFO_COREDUMP | PIDFD_INFO_SUPPORTED_MASK,
+ .coredump_mask = 0xdeadbeef,
+ .coredump_signal = 0xdeadbeef,
+ .coredump_code = 0xdeadbeef,
+ .supported_mask = 0xdeadbeefdeadbeefULL,
+ };
+ unsigned int cmd = _IOC(_IOC_READ | _IOC_WRITE, PIDFS_IOCTL_MAGIC, 11,
+ PIDFD_INFO_SIZE_VER0);
+ int pidfd;
+ pid_t pid;
+
+ pid = create_child(&pidfd, 0);
+ ASSERT_GE(pid, 0);
+
+ if (pid == 0)
+ pause();
+
+ ASSERT_EQ(ioctl(pidfd, cmd, &info), 0);
+
+ /* The fields that fit are reported as usual. */
+ ASSERT_TRUE(!!(info.mask & PIDFD_INFO_PID));
+ ASSERT_TRUE(!!(info.mask & PIDFD_INFO_CREDS));
+
+ /* The fields that do not fit are neither reported nor written. */
+ ASSERT_FALSE(!!(info.mask & (PIDFD_INFO_COREDUMP |
+ PIDFD_INFO_COREDUMP_SIGNAL |
+ PIDFD_INFO_COREDUMP_CODE |
+ PIDFD_INFO_SUPPORTED_MASK)));
+ ASSERT_EQ(info.coredump_mask, 0xdeadbeef);
+ ASSERT_EQ(info.coredump_signal, 0xdeadbeef);
+ ASSERT_EQ(info.coredump_code, 0xdeadbeef);
+ ASSERT_EQ(info.supported_mask, 0xdeadbeefdeadbeefULL);
+
+ sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0);
+ sys_waitid(P_PIDFD, pidfd, NULL, WEXITED);
+ close(pidfd);
+}
+
TEST_HARNESS_MAIN
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] pidfs: do not report fields that do not fit into the caller's struct
2026-10-24 4:13 ` [PATCH v2 1/2] " Nickolai Zeldovich
@ 2026-10-24 9:06 ` Luca Boccassi
0 siblings, 0 replies; 6+ messages in thread
From: Luca Boccassi @ 2026-10-24 9:06 UTC (permalink / raw)
To: Nickolai Zeldovich; +Cc: linux-fsdevel, linux-kselftest, linux-kernel
On Sat, 24 Oct 2026 at 05:13, Nickolai Zeldovich <nickolai@csail.mit.edu> wrote:
>
> The documentation of struct pidfd_info promises that "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", and asks
> userspace to trust the returned mask when deciding which fields hold
> valid data.
>
> pidfd_info() does not keep that promise. It builds kinfo.mask without
> looking at the size encoded in the ioctl command, and
> copy_struct_to_user() then truncates the copy to that size. A caller
> that passes a 64-byte struct (PIDFD_INFO_SIZE_VER0) and requests
> PIDFD_INFO_COREDUMP or PIDFD_INFO_SUPPORTED_MASK gets a mask with
> PIDFD_INFO_COREDUMP, PIDFD_INFO_COREDUMP_SIGNAL, PIDFD_INFO_COREDUMP_CODE
> and PIDFD_INFO_SUPPORTED_MASK set, while the coredump_* and
> supported_mask fields behind the 64 bytes were never written. Trusting
> the mask as documented, userspace then reads whatever its own buffer
> held at those offsets. The same happens for a 72- or 80-byte struct
> and the fields added after it.
>
> Clear the bits of the fields that lie beyond the caller's size before
> the copy, in the one place that knows both the final mask and the size.
> A request for a field that cannot be returned is thereby answered the
> way the header describes: the field is simply absent from the mask.
>
> Fixes: 1d8db6fd698d ("pidfs, coredump: add PIDFD_INFO_COREDUMP")
> Signed-off-by: Nickolai Zeldovich <nickolai@csail.mit.edu>
> ---
>
> Notes:
> The three size thresholds follow the field layout: coredump_mask and
> coredump_signal end at PIDFD_INFO_SIZE_VER1 (72), coredump_code at
> PIDFD_INFO_SIZE_VER2 (80), supported_mask at PIDFD_INFO_SIZE_VER3 (88).
> Masking the request bits early instead (before the coredump and
> supported_mask blocks run) would save a little work for such callers
> but leaves PIDFD_INFO_COREDUMP set by the dumpable-state fallback for a
> live task; clearing the result once before copy_struct_to_user() covers
> every way a bit can be set.
>
> fs/pidfs.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
Acked-by: Luca Boccassi <luca.boccassi@gmail.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-24 9:06 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-17 2:06 [PATCH v1] pidfs: do not report fields that do not fit into the caller's struct Nickolai Zeldovich
2026-10-21 10:42 ` Christian Brauner
2026-10-24 4:13 ` [PATCH v2 0/2] " Nickolai Zeldovich
2026-10-24 4:13 ` [PATCH v2 1/2] " Nickolai Zeldovich
2026-10-24 9:06 ` Luca Boccassi
2026-10-24 4:13 ` [PATCH v2 2/2] selftests/pidfd: test that fields beyond the struct size are not reported Nickolai Zeldovich
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®