[PATCH 02/13] Update PIDFD_* constants for Linux 6.17
Carlos O'Donell
carlos@redhat.com
Tue Nov 4 16:43:49 GMT 2025
On 10/3/25 3:38 PM, Adhemerval Zanella wrote:
> The pidfd interface was extended with:
LGTM.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
> * PIDFD_GET_INFO and pidfd_info (along with related extra flags) to
> allow get information about the process without the need to parse
> /proc (commit cdda1f26e74ba, Linux 6.13).
OK. Confirmed.
>
> * PIDFD_SELF_{THREAD,THREAD_GROUP,SELF,SELF_PROCESS} to allow
> pidfd_send_signal refer to the own process or thread lead groups
> without the need of allocating a file descriptor (commit f08d0c3a71114,
> Linux 6.15).
OK. Confirmed.
>
> * PIDFD_INFO_COREDUMP that extends PIDFD_GET_INFO to obtain coredump
> information.
OK. Confirmed.
>
> Linux uAPI header defines both PIDFD_SELF_THREAD and
> PIDFD_SELF_THREAD_GROUP on linux/fcntl.h (since they reserve part of the
> AT_* values), however for glibc I do not see any good reason to add pidfd
> definitions on fcntl-linux.h.
Agreed.
>
> The tst-pidfd.c is extended with some PIDFD_SELF_* tests and a new
> ‘tst-pidfd_getinfo.c’ test is added to check PIDFD_GET_INFO. The
> PIDFD_INFO_COREDUMP tests would require very large and complex tests
> that are already covered by kernel tests.
Agreed. Looks good.
>
> Checked on aarch64-linux-gnu and x86_64-linux-gnu on kernels 6.8 and
> 6.17.
> ---
> sysdeps/unix/sysv/linux/Makefile | 1 +
> sysdeps/unix/sysv/linux/sys/pidfd.h | 58 +++++++++++++++++
> sysdeps/unix/sysv/linux/tst-pidfd-consts.py | 2 +-
> sysdeps/unix/sysv/linux/tst-pidfd.c | 44 ++++++++++++-
> sysdeps/unix/sysv/linux/tst-pidfd_getinfo.c | 71 +++++++++++++++++++++
> 5 files changed, 172 insertions(+), 4 deletions(-)
> create mode 100644 sysdeps/unix/sysv/linux/tst-pidfd_getinfo.c
>
> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
> index 2c5bf42236..642bcc7d66 100644
> --- a/sysdeps/unix/sysv/linux/Makefile
> +++ b/sysdeps/unix/sysv/linux/Makefile
> @@ -211,6 +211,7 @@ tests += \
> tst-ofdlocks \
> tst-personality \
> tst-pidfd \
> + tst-pidfd_getinfo \
OK. New test. In the right place.
> tst-pidfd_getpid \
> tst-pkey \
> tst-ppoll \
> diff --git a/sysdeps/unix/sysv/linux/sys/pidfd.h b/sysdeps/unix/sysv/linux/sys/pidfd.h
> index e6fc024f96..1e6da6e553 100644
> --- a/sysdeps/unix/sysv/linux/sys/pidfd.h
> +++ b/sysdeps/unix/sysv/linux/sys/pidfd.h
> @@ -42,6 +42,64 @@
> #define PIDFD_GET_USER_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 9)
> #define PIDFD_GET_UTS_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 10)
>
> +/* Sentinels to avoid allocating a file descriptor to refer to own process. */
> +#define PIDFD_SELF_THREAD -10000
OK. Matches fcntl.h value.
> +#define PIDFD_SELF_THREAD_GROUP -10001
OK. Matches fcntl.h value.
> +#define PIDFD_SELF PIDFD_SELF_THREAD
OK. Matches pidfd.h value.
> +#define PIDFD_SELF_PROCESS PIDFD_SELF_THREAD_GROUP
OK. Matches pidfd.h value.
Makes sense to put this all in pidfd.h.
> +
> +
> +/* Flags for pidfd_info. */
> +
> +/* Always returned, even if not requested */
> +#define PIDFD_INFO_PID (1UL << 0)
> +/* Always returned, even if not requested */
> +#define PIDFD_INFO_CREDS (1UL << 1)
> +/* Always returned if available, even if not requested */
> +#define PIDFD_INFO_CGROUPID (1UL << 2)
> +/* Only returned if requested. */
> +#define PIDFD_INFO_EXIT (1UL << 3)
> +/* Only returned if requested. */
> +#define PIDFD_INFO_COREDUMP (1UL << 4)
> +
OK. All 4 constants match pidfd.h.
> +
> +/* Value for coredump_mask in pidfd_info. Only valid if PIDFD_INFO_COREDUMP
> + is set in mask. */
> +
> +/* Did crash and... */
> +#define PIDFD_COREDUMPED (1U << 0)
> +/* coredumping generation was skipped. */
> +#define PIDFD_COREDUMP_SKIP (1U << 1)
> +/* coredump was done as the user. */
> +#define PIDFD_COREDUMP_USER (1U << 2)
> +/* coredump was done as root. */
> +#define PIDFD_COREDUMP_ROOT (1U << 3)
OK. All 4 constants match pidfd.h.
> +
> +struct pidfd_info
> +{
> + __uint64_t mask;
> + __uint64_t cgroupid;
> + __uint32_t pid;
> + __uint32_t tgid;
> + __uint32_t ppid;
> + __uint32_t ruid;
> + __uint32_t rgid;
> + __uint32_t euid;
> + __uint32_t egid;
> + __uint32_t suid;
> + __uint32_t sgid;
> + __uint32_t fsuid;
> + __uint32_t fsgid;
> + __int32_t exit_code;
> + __uint32_t coredump_mask;
> + __uint32_t __spare1;
> +};
OK. Matches pidfd.h definition of struct pidfd_info.
> +
> +/* sizeof first published struct */
> +#define PIDFD_INFO_SIZE_VER0 64
OK. Matches.
> +
> +#define PIDFD_GET_INFO _IOWR(PIDFS_IOCTL_MAGIC, 11, struct pidfd_info)
OK. Matches.
> +
> /* Returns a file descriptor that refers to the process PID. The
> close-on-exec is set on the file descriptor. */
> extern int pidfd_open (__pid_t __pid, unsigned int __flags) __THROW;
> diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
> index 18010fe0e6..6dc678380c 100644
> --- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
> +++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py
> @@ -39,7 +39,7 @@ def main():
> sys.exit (77)
>
> linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
> - linux_version_glibc = (6, 12)
> + linux_version_glibc = (6, 17)
OK. Increase value.
> sys.exit(glibcextract.compare_macro_consts(
> '#include <sys/pidfd.h>\n',
> '#include <asm/fcntl.h>\n'
> diff --git a/sysdeps/unix/sysv/linux/tst-pidfd.c b/sysdeps/unix/sysv/linux/tst-pidfd.c
> index f7e0c5d9fa..4e4591f6c8 100644
> --- a/sysdeps/unix/sysv/linux/tst-pidfd.c
> +++ b/sysdeps/unix/sysv/linux/tst-pidfd.c
> @@ -16,6 +16,7 @@
> License along with the GNU C Library; if not, see
> <https://www.gnu.org/licenses/>. */
>
> +#include <array_length.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <limits.h>
> @@ -41,15 +42,23 @@ static pid_t ppid;
> static uid_t puid;
>
> static void
> -sighandler (int sig)
> +sighandler_subprocess (int sig)
> {
> }
>
> +static sig_atomic_t pidfd_self_flag;
> +
> +static void
> +sighandler_parent (int sig)
> +{
> + pidfd_self_flag = 1;
> +}
> +
> static void
> subprocess (void)
> {
> - xsignal (SIGUSR1, sighandler);
> - xsignal (SIGUSR2, sighandler);
> + xsignal (SIGUSR1, sighandler_subprocess);
> + xsignal (SIGUSR2, sighandler_subprocess);
>
> /* Check first pidfd_send_signal with default NULL siginfo_t argument. */
> {
> @@ -102,6 +111,7 @@ do_test (void)
> FAIL_UNSUPPORTED ("kernel does not support pidfd_getfd, skipping test");
> }
>
> +
> ppid = getpid ();
> puid = getuid ();
>
> @@ -115,6 +125,34 @@ do_test (void)
> TEST_COMPARE (errno, EBADF);
> }
>
> + xsignal (SIGUSR1, sighandler_parent);
> +
> + {
> + sigset_t mask, oldmask;
> + sigemptyset (&mask);
> + sigaddset (&mask, SIGUSR1);
> + TEST_COMPARE (sigprocmask (SIG_BLOCK, &mask, &oldmask), 0);
> +
> + /* PIDFD_SELF_{THREAD,THREAD_GROUP} were added on Linux 6.15. On older
> + kernels pidfd_send_signal should return -1/EBADF. */
> + const int pidfd_selfs[] = { PIDFD_SELF, PIDFD_SELF_PROCESS };
> + for (int i = 0; i < array_length (pidfd_selfs); i++)
> + {
> + pidfd_self_flag = 0;
> + int r = pidfd_send_signal (pidfd_selfs[i], SIGUSR1, NULL, 0);
> + if (r == -1)
> + TEST_COMPARE (errno, EBADF);
> + else
> + {
> + while (pidfd_self_flag == 0)
> + sigsuspend (&oldmask);
> + TEST_COMPARE (pidfd_self_flag, 1);
> + }
> + }
> +
> + TEST_COMPARE (sigprocmask (SIG_SETMASK, &oldmask, NULL), 0);
> + }
> +
> /* Check if pidfd_getpid returns ESRCH for exited subprocess. */
> {
> pid_t pidfork = xfork ();
> diff --git a/sysdeps/unix/sysv/linux/tst-pidfd_getinfo.c b/sysdeps/unix/sysv/linux/tst-pidfd_getinfo.c
> new file mode 100644
> index 0000000000..948a7cdb6b
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-pidfd_getinfo.c
> @@ -0,0 +1,71 @@
> +/* Basic tests for Linux PID_GET_INFO interfaces.
> + Copyright (C) 2022-2025 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <errno.h>
> +#include <stdint.h>
> +#include <sys/pidfd.h>
> +#include <support/check.h>
> +#include <support/xunistd.h>
> +
> +static int
> +do_test (void)
> +{
> + {
> + /* The pidfd_getfd syscall was the last in the set of pidfd related
> + syscalls added to the kernel. Use pidfd_getfd to decide if this
> + kernel has pidfd support that we can test. */
> + int r = pidfd_getfd (0, 0, 1);
> + TEST_VERIFY_EXIT (r == -1);
> + if (errno == ENOSYS)
> + FAIL_UNSUPPORTED ("kernel does not support pidfd_getfd, skipping test");
OK.
> + }
> +
> + int pidfd = pidfd_open (getpid(), 0);
> + TEST_VERIFY (pidfd >= 0);
> +
> + int pid = pidfd_getpid (pidfd);
> + TEST_VERIFY (pid >= 0);
> +
> + struct pidfd_info info = {
> + .mask = PIDFD_INFO_CGROUPID,
> + };
> + if (ioctl (pidfd, PIDFD_GET_INFO, &info) != 0)
> + {
> + if (errno == ENOTTY)
> + FAIL_UNSUPPORTED ("kernel does not support PIDFD_GET_INFO");
OK.
> + else
> + FAIL_EXIT1 ("ioctl (PIDFD_GET_INFO) failed: %m");
> + }
> +
> + TEST_COMPARE (info.pid, pid);
> + TEST_COMPARE (info.ppid, getppid ());
> + TEST_COMPARE (info.ruid, getuid ());
> + TEST_COMPARE (info.rgid, getgid ());
> + TEST_COMPARE (info.euid, geteuid ());
> + TEST_COMPARE (info.egid, getegid ());
> + TEST_COMPARE (info.suid, geteuid ());
> + TEST_COMPARE (info.sgid, getegid ());
OK.
> + if (info.mask & PIDFD_INFO_CGROUPID)
> + TEST_VERIFY (info.cgroupid != 0);
> +
> + xclose (pidfd);
OK.
> +
> + return 0;
> +}
> +
> +#include <support/test-driver.c>
--
Cheers,
Carlos.
More information about the Libc-alpha
mailing list