diff options
author | Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> | 2023-08-24 13:42:19 -0300 |
---|---|---|
committer | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2023-09-05 13:08:59 -0300 |
commit | e7190fc73dbc8a1f8f94f8ccacd9a190fa5e609c (patch) | |
tree | 0070895e116c7250463b90b643f8727466bfbb5b | |
parent | 0d6f9f626521678f330f8bfee89e1cdb7e2b1062 (diff) | |
download | glibc-e7190fc73dbc8a1f8f94f8ccacd9a190fa5e609c.tar.gz glibc-e7190fc73dbc8a1f8f94f8ccacd9a190fa5e609c.tar.xz glibc-e7190fc73dbc8a1f8f94f8ccacd9a190fa5e609c.zip |
linux: Add pidfd_getpid
This interface allows to obtain the associated process ID from the process file descriptor. It is done by parsing the procps fdinfo information. Its prototype is: pid_t pidfd_getpid (int fd) It returns the associated pid or -1 in case of an error and sets the errno accordingly. The possible errno values are those from open, read, and close (used on procps parsing), along with: - EBADF if the FD is negative, does not have a PID associated, or if the fdinfo fields contain a value larger than pid_t. - EREMOTE if the PID is in a separate namespace. - ESRCH if the process is already terminated. Checked on x86_64-linux-gnu on Linux 4.15 (no CLONE_PIDFD or waitid support), Linux 5.4 (full support), and Linux 6.2. Reviewed-by: Florian Weimer <fweimer@redhat.com>
44 files changed, 520 insertions, 0 deletions
diff --git a/NEWS b/NEWS index 97681e6796..60a0371be9 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,10 @@ Major new features: The pidfd functionality avoids the issue of PID reuse with the traditional posix_spawn interface. +* On Linux, the pidfd_getpid function has been added. It allows retrieving + the process ID associated with the process file descriptor created by + pid_spawn, fork_np, or pidfd_open. + Deprecated and removed features, and other changes affecting compatibility: [Add deprecations, removals and changes affecting compatibility here] diff --git a/manual/process.texi b/manual/process.texi index 68361c3f61..8254e5ee86 100644 --- a/manual/process.texi +++ b/manual/process.texi @@ -33,6 +33,7 @@ primitive functions to do each step individually instead. * Process Creation Concepts:: An overview of the hard way to do it. * Process Identification:: How to get the process ID of a process. * Creating a Process:: How to fork a child process. +* Querying a Process:: How to query a child process. * Executing a File:: How to make a process execute another program. * Process Completion:: How to tell when a child process has completed. * Process Completion Status:: How to interpret the status value @@ -362,6 +363,43 @@ the proper precautions for using @code{vfork}, your program will still work even if the system uses @code{fork} instead. @end deftypefun +@node Querying a Process +@section Querying a Process + +The file descriptor returned by the @code{pidfd_fork} function can be used to +query process extra information. + +@deftypefun pid_t pidfd_getpid (int @var{fd}) +@standards{GNU, sys/pidfd.h} +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + +The @code{pidfd_getpid} function retrieves the process ID associated with process +file descriptor created with @code{pid_spawn}, @code{pidfd_fork}, or +@code{pidfd_open}. + +If the operation fails, @code{pidfd_getpid} return @code{-1} and the following +@code{errno} error conditionas are defined: + +@table @code +@item EBADF +The input file descriptor is invalid, does not have a pidfd associated, or an +error has occurred parsing the kernel data. +@item EREMOTE +There is no process ID to denote the process in the current namespace. +@item ESRCH +The process for which the file descriptor refers to is terminated. +@item ENOENT +The procfs is not mounted. +@item ENFILE. +Too many open files in system (@code{pidfd_open} tries to open a procfs file and +read its contents). +@item ENOMEM +Insufficient kernel memory was available. +@end table + +This function is specific to Linux. +@end deftypefun + @node Executing a File @section Executing a File @cindex executing a file diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 3ecfa184d0..063719bae6 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -213,6 +213,7 @@ tests += \ tst-ofdlocks \ tst-personality \ tst-pidfd \ + tst-pidfd_getpid \ tst-pkey \ tst-ppoll \ tst-prctl \ @@ -493,8 +494,10 @@ sysdep_headers += \ sysdep_routines += \ getcpu \ oldglob \ + pidfd_getpid \ pidfd_spawn \ pidfd_spawnp \ + procutils \ sched_getcpu \ spawnattr_getcgroup_np \ spawnattr_setcgroup_np \ diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions index a8bae0c2a2..268ba1b6ac 100644 --- a/sysdeps/unix/sysv/linux/Versions +++ b/sysdeps/unix/sysv/linux/Versions @@ -322,6 +322,7 @@ libc { %endif } GLIBC_2.39 { + pidfd_getpid; pidfd_spawn; pidfd_spawnp; posix_spawnattr_getcgroup_np; diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index 6f23556067..b3484be555 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2673,6 +2673,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index 02c43beb13..09c03b0e3f 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -2782,6 +2782,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist index dd8e5912d8..63761315d0 100644 --- a/sysdeps/unix/sysv/linux/arc/libc.abilist +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist @@ -2434,6 +2434,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist index a751e5f5a9..d0860b25e0 100644 --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist @@ -554,6 +554,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist index 0eda3459ed..b93819cab4 100644 --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist @@ -551,6 +551,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist index 4f4e99427b..ca5db5cde5 100644 --- a/sysdeps/unix/sysv/linux/csky/libc.abilist +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist @@ -2710,6 +2710,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index abc471dd0b..e736477ce6 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -2659,6 +2659,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index 9f03c8a9a2..56263a5111 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -2843,6 +2843,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist index ce1d20b722..504b6a7fa7 100644 --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist @@ -2608,6 +2608,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist index 8c3640b004..3cdc2b9d85 100644 --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist @@ -2194,6 +2194,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index a594916319..1cbebfb162 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -555,6 +555,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index 7f61d4824d..8dd696a24e 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2786,6 +2786,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist index 83ebb84ff3..ddfab38be7 100644 --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist @@ -2759,6 +2759,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist index 89a0ff83bf..88fd2a735f 100644 --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist @@ -2756,6 +2756,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index e21c752057..880e4f8bfd 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -2751,6 +2751,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index 42f470d397..016f8fba79 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -2749,6 +2749,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index 6907f5f98b..0688873db5 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -2757,6 +2757,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index 4b1f017a98..0f0b10ccb1 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -2659,6 +2659,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist index 0d45902209..c39db78ea8 100644 --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist @@ -2798,6 +2798,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist index c59032ef14..31b02d2a1e 100644 --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist @@ -2180,6 +2180,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/pidfd_getpid.c b/sysdeps/unix/sysv/linux/pidfd_getpid.c new file mode 100644 index 0000000000..d03936e97f --- /dev/null +++ b/sysdeps/unix/sysv/linux/pidfd_getpid.c @@ -0,0 +1,126 @@ +/* pidfd_getpid - Get the associated pid from the pid file descriptor. + Copyright (C) 2023 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 <_itoa.h> +#include <errno.h> +#include <intprops.h> +#include <procutils.h> +#include <stdlib.h> +#include <string.h> +#include <sysdep.h> +#include <unistd.h> + +#define FDINFO_TO_FILENAME_PREFIX "/proc/self/fdinfo/" + +#define FDINFO_FILENAME_LEN \ + (sizeof (FDINFO_TO_FILENAME_PREFIX) + INT_STRLEN_BOUND (int)) + +struct parse_fdinfo_t +{ + bool found; + pid_t pid; +}; + +/* Parse the PID field in the fdinfo entry, if existent. Avoid strtol or + similar to not be locale dependent. */ +static int +parse_fdinfo (const char *l, void *arg) +{ + enum { fieldlen = sizeof ("Pid:") - 1 }; + if (strncmp (l, "Pid:", fieldlen) != 0) + return 0; + + l += fieldlen; + + /* Skip leading spaces. */ + while (*l == ' ' || (unsigned int) (*l) -'\t' < 5) + l++; + + bool neg = false; + switch (*l) + { + case '-': + neg = true; + l++; + break; + case '+': + return -1; + } + + if (*l == '\0') + return 0; + + int n = 0; + while (*l != '\0') + { + /* Check if '*l' is a digit. */ + if ('0' > *l || *l > '9') + return -1; + + /* Ignore invalid large values. */ + if (INT_MULTIPLY_WRAPV (10, n, &n) + || INT_ADD_WRAPV (n, *l++ - '0', &n)) + return -1; + } + + /* -1 indicates that the process is terminated. */ + if (neg && n != 1) + return -1; + + struct parse_fdinfo_t *fdinfo = arg; + fdinfo->pid = neg ? -n : n; + fdinfo->found = true; + + return 1; +} + +pid_t +pidfd_getpid (int fd) +{ + if (__glibc_unlikely (fd < 0)) + { + __set_errno (EBADF); + return -1; + } + + char fdinfoname[FDINFO_FILENAME_LEN]; + + char *p = mempcpy (fdinfoname, FDINFO_TO_FILENAME_PREFIX, + strlen (FDINFO_TO_FILENAME_PREFIX)); + *_fitoa_word (fd, p, 10, 0) = '\0'; + + struct parse_fdinfo_t fdinfo = { .found = false, .pid = -1 }; + if (!procutils_read_file (fdinfoname, parse_fdinfo, &fdinfo)) + /* The fdinfo contains an invalid 'Pid:' value. */ + return INLINE_SYSCALL_ERROR_RETURN_VALUE (EBADF); + + /* The FD does not have a 'Pid:' entry associated. */ + if (!fdinfo.found) + return INLINE_SYSCALL_ERROR_RETURN_VALUE (EBADF); + + /* The pidfd cannot be resolved because it is in a separate pid + namespace. */ + if (fdinfo.pid == 0) + return INLINE_SYSCALL_ERROR_RETURN_VALUE (EREMOTE); + + /* A negative value means the process is terminated. */ + if (fdinfo.pid < 0) + return INLINE_SYSCALL_ERROR_RETURN_VALUE (ESRCH); + + return fdinfo.pid; +} diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index e014314d3e..d23c6a0447 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -2825,6 +2825,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index ac05154915..6667852f18 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -2858,6 +2858,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist index e13ee6e72a..3fb527362e 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist @@ -2579,6 +2579,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist index 0e8c9ab3fe..2c975dcad6 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist @@ -2893,6 +2893,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/procutils.c b/sysdeps/unix/sysv/linux/procutils.c new file mode 100644 index 0000000000..30fc3a063a --- /dev/null +++ b/sysdeps/unix/sysv/linux/procutils.c @@ -0,0 +1,97 @@ +/* Utilities functions to read/parse Linux procfs and sysfs. + Copyright (C) 2023 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 <assert.h> +#include <not-cancel.h> +#include <procutils.h> +#include <string.h> + +static int +next_line (char **r, int fd, char *const buffer, char **cp, char **re, + char *const buffer_end) +{ + char *res = *cp; + char *nl = memchr (*cp, '\n', *re - *cp); + if (nl == NULL) + { + if (*cp != buffer) + { + if (*re == buffer_end) + { + memmove (buffer, *cp, *re - *cp); + *re = buffer + (*re - *cp); + *cp = buffer; + + ssize_t n = TEMP_FAILURE_RETRY ( + __read_nocancel (fd, *re, buffer_end - *re)); + if (n < 0) + return -1; + + *re += n; + + nl = memchr (*cp, '\n', *re - *cp); + if (nl == NULL) + /* Line too long. */ + return 0; + } + else + nl = memchr (*cp, '\n', *re - *cp); + + res = *cp; + } + + if (nl == NULL) + nl = *re - 1; + } + + *nl = '\0'; + *cp = nl + 1; + assert (*cp <= *re); + + if (res == *re) + return 0; + + *r = res; + return 1; +} + +bool +procutils_read_file (const char *filename, procutils_closure_t closure, + void *arg) +{ + enum { buffer_size = PROCUTILS_MAX_LINE_LEN }; + char buffer[buffer_size]; + char *buffer_end = buffer + buffer_size; + char *cp = buffer_end; + char *re = buffer_end; + + int fd = TEMP_FAILURE_RETRY ( + __open64_nocancel (filename, O_RDONLY | O_CLOEXEC)); + if (fd == -1) + return false; + + char *l; + int r; + while ((r = next_line (&l, fd, buffer, &cp, &re, buffer_end)) > 0) + if (closure (l, arg) != 0) + break; + + __close_nocancel_nostatus (fd); + + return r == 1; +} diff --git a/sysdeps/unix/sysv/linux/procutils.h b/sysdeps/unix/sysv/linux/procutils.h new file mode 100644 index 0000000000..b3c2f6fb55 --- /dev/null +++ b/sysdeps/unix/sysv/linux/procutils.h @@ -0,0 +1,43 @@ +/* Utilities functions to read/parse Linux procfs and sysfs. + Copyright (C) 2023 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/>. */ + +#ifndef _PROCUTILS_H +#define _PROCUTILS_H + +#include <stdbool.h> + +typedef int (*procutils_closure_t) (const char *line, void *arg); + +#define PROCUTILS_MAX_LINE_LEN 256 + +/* Open and read the path FILENAME, line per line, and call CLOSURE with + argument ARG on each line. The read is done with a static buffer, + with non-cancellable calls, and the line is null terminated. + + The CLOSURE should return 0 if the read should continue, otherwise the + the function should stop and return early. + + The '\n' is not included in the CLOSURE input argument and lines longer + than PROCUTILS_MAX_LINE_LEN characteres are ignored. + + It returns true in case the file is fully read or false if CLOSURE + returns a value diferent than 0. */ +bool procutils_read_file (const char *filename, procutils_closure_t closure, + void *arg) attribute_hidden; + +#endif diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist index b0559a5a64..a13c484582 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist @@ -2436,6 +2436,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index 5f79a84016..cf65d8d6d4 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2636,6 +2636,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index 498886ccb2..3d78db8445 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -2823,6 +2823,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index 51679c2990..030b26c376 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2616,6 +2616,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist index af7b6f5bc9..155b2c03ff 100644 --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist @@ -2666,6 +2666,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist index b766299f31..1042622943 100644 --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist @@ -2663,6 +2663,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index f5b9200a33..afa62cdbe6 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -2818,6 +2818,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index f6012e6e17..9e9df3876b 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2631,6 +2631,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/sys/pidfd.h b/sysdeps/unix/sysv/linux/sys/pidfd.h index 342e593288..5179e2e795 100644 --- a/sysdeps/unix/sysv/linux/sys/pidfd.h +++ b/sysdeps/unix/sysv/linux/sys/pidfd.h @@ -46,4 +46,8 @@ extern int pidfd_getfd (int __pidfd, int __targetfd, extern int pidfd_send_signal (int __pidfd, int __sig, siginfo_t *__info, unsigned int __flags) __THROW; +/* Query the process ID (PID) from process descriptor FD. Return the PID + or -1 in case of an error. */ +extern pid_t pidfd_getpid (int __fd) __THROW; + #endif /* _PIDFD_H */ diff --git a/sysdeps/unix/sysv/linux/tst-pidfd.c b/sysdeps/unix/sysv/linux/tst-pidfd.c index 64d8a2ef40..5f635a3fec 100644 --- a/sysdeps/unix/sysv/linux/tst-pidfd.c +++ b/sysdeps/unix/sysv/linux/tst-pidfd.c @@ -18,6 +18,7 @@ #include <errno.h> #include <fcntl.h> +#include <limits.h> #include <support/capture_subprocess.h> #include <support/check.h> #include <support/process_state.h> @@ -27,6 +28,8 @@ #include <support/xsocket.h> #include <sys/pidfd.h> #include <sys/wait.h> +#include <stdlib.h> +#include <unistd.h> #define REMOTE_PATH "/dev/null" @@ -102,6 +105,44 @@ do_test (void) ppid = getpid (); puid = getuid (); + /* Sanity check for invalid inputs. */ + TEST_COMPARE (pidfd_getpid (-1), -1); + TEST_COMPARE (errno, EBADF); + + { + pid_t pid = pidfd_getpid (STDOUT_FILENO); + TEST_COMPARE (pid, -1); + TEST_COMPARE (errno, EBADF); + } + + /* Check if pidfd_getpid returns ESRCH for exited subprocess. */ + { + pid_t pidfork = xfork (); + if (pidfork == 0) + _exit (EXIT_SUCCESS); + int pidfork_pidfd = pidfd_open (pidfork, 0); + + /* The process might be still running or already in zombie state, in + either case the PID is still allocated to the process. */ + pid_t pid = pidfd_getpid (pidfork_pidfd); + TEST_COMPARE (pidfork, pid); + if (pid > 0) + support_process_state_wait (pid, support_process_state_zombie); + + siginfo_t info; + TEST_COMPARE (waitid (P_PIDFD, pidfork_pidfd, &info, WEXITED), 0); + TEST_COMPARE (info.si_pid, pidfork); + TEST_COMPARE (info.si_status, 0); + TEST_COMPARE (info.si_code, CLD_EXITED); + + /* Once the process is reaped the associated PID is not available. */ + pid = pidfd_getpid (pidfork_pidfd); + TEST_COMPARE (pid, -1); + TEST_COMPARE (errno, ESRCH); + + xclose (pidfork_pidfd); + } + TEST_COMPARE (socketpair (AF_UNIX, SOCK_STREAM, 0, sockets), 0); pid_t pid = xfork (); @@ -118,6 +159,12 @@ do_test (void) int pidfd = pidfd_open (pid, 0); TEST_VERIFY (pidfd != -1); + TEST_COMPARE (pidfd_getpid (INT_MAX), -1); + { + pid_t querypid = pidfd_getpid (pidfd); + TEST_COMPARE (querypid, pid); + } + /* Wait for first sigtimedwait. */ support_process_state_wait (pid, support_process_state_sleeping); TEST_COMPARE (pidfd_send_signal (pidfd, SIGUSR1, NULL, 0), 0); diff --git a/sysdeps/unix/sysv/linux/tst-pidfd_getpid.c b/sysdeps/unix/sysv/linux/tst-pidfd_getpid.c new file mode 100644 index 0000000000..e48eed79ab --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-pidfd_getpid.c @@ -0,0 +1,123 @@ +/* Specific tests for Linux pidfd_getpid. + Copyright (C) 2023 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 <sched.h> +#include <stdlib.h> +#include <support/check.h> +#include <support/xunistd.h> +#include <support/test-driver.h> +#include <sys/pidfd.h> +#include <sys/wait.h> +#include <sys/mount.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"); + if (errno == EPERM) + FAIL_UNSUPPORTED ("kernel does not allow pidfd_getfd, skipping test"); + } + + /* Check if pidfd_getpid returns EREMOTE for process not in current + namespace. */ + { + pid_t child0 = xfork (); + TEST_VERIFY_EXIT (child0 >= 0); + if (child0 == 0) + { + /* Create another unrelated descriptor, so child2 will inherit the + file descriptor. */ + pid_t child1 = xfork (); + TEST_VERIFY_EXIT (child1 >= 0); + if (child1 == 0) + _exit (0); + int child1_pidfd = pidfd_open (child1, 0); + TEST_VERIFY_EXIT (child1_pidfd != -1); + + if (unshare (CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWPID) < 0) + { + /* Older kernels may not support all the options, or security + policy may block this call. */ + if (errno == EINVAL || errno == EPERM || errno == ENOSPC) + exit (EXIT_UNSUPPORTED); + FAIL_EXIT1 ("unshare user/fs/pid failed: %m"); + } + + if (mount (NULL, "/", NULL, MS_REC | MS_PRIVATE, 0) != 0) + { + /* This happens if we're trying to create a nested container, + like if the build is running under podman, and we lack + priviledges. */ + if (errno == EPERM) + _exit (EXIT_UNSUPPORTED); + else + _exit (EXIT_FAILURE); + } + + pid_t child2 = xfork (); + if (child2 > 0) + { + int status; + xwaitpid (child2, &status, 0); + TEST_VERIFY (WIFEXITED (status)); + xwaitpid (child1, &status, 0); + TEST_VERIFY (WIFEXITED (status)); + + _exit (WEXITSTATUS (status)); + } + + /* Now that we're pid 1 (effectively "root") we can mount /proc */ + if (mount ("proc", "/proc", "proc", 0, NULL) != 0) + { + if (errno == EPERM) + _exit (EXIT_UNSUPPORTED); + else + _exit (EXIT_FAILURE); + } + + TEST_COMPARE (pidfd_getpid (child1_pidfd), -1); + TEST_COMPARE (errno, EREMOTE); + + _exit (EXIT_SUCCESS); + } + int child0_pidfd = pidfd_open (child0, 0); + TEST_VERIFY_EXIT (child0_pidfd != -1); + + pid_t child0pid = pidfd_getpid (child0_pidfd); + + siginfo_t info; + TEST_COMPARE (waitid (P_PIDFD, child0_pidfd, &info, WEXITED), 0); + if (info.si_status == EXIT_UNSUPPORTED) + FAIL_UNSUPPORTED ("unable to unshare user/fs/pid"); + TEST_COMPARE (info.si_status, 0); + TEST_COMPARE (info.si_code, CLD_EXITED); + TEST_COMPARE (info.si_pid, child0pid); + } + + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index e35bf54779..893f0886dd 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2582,6 +2582,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index e7d7eb61c0..9bcc1986a1 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2688,6 +2688,7 @@ GLIBC_2.38 strlcat F GLIBC_2.38 strlcpy F GLIBC_2.38 wcslcat F GLIBC_2.38 wcslcpy F +GLIBC_2.39 pidfd_getpid F GLIBC_2.39 pidfd_spawn F GLIBC_2.39 pidfd_spawnp F GLIBC_2.39 posix_spawnattr_getcgroup_np F |