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>
This commit is contained in:
Adhemerval Zanella Netto 2023-08-24 13:42:19 -03:00 committed by Adhemerval Zanella
parent 0d6f9f6265
commit e7190fc73d
44 changed files with 520 additions and 0 deletions

4
NEWS
View File

@ -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]

View File

@ -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

View File

@ -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 \

View File

@ -322,6 +322,7 @@ libc {
%endif
}
GLIBC_2.39 {
pidfd_getpid;
pidfd_spawn;
pidfd_spawnp;
posix_spawnattr_getcgroup_np;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -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>

View File

@ -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

View File

@ -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