Message ID | 20230516114612.159103-4-adhemerval.zanella@linaro.org |
---|---|
State | New |
Headers | show |
Series | Add pidfd_spawn, pidfd_spawnp, pidfd_fork, and pidfd_getpid | expand |
On Tue, 16 May 2023 at 12:46, Adhemerval Zanella <adhemerval.zanella@linaro.org> wrote: > > This interface allows to obtain the associated pid 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 set the > errno accordingly. The possible errno values are the smae from > open, read, and close (used on procps parsing), along with: > > - EINVAL if the FP is negative (similar to fexecve). > > - EBADF if the FD does not have a PID associated of if the fdinfo > fields contains 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_PID or waitid > support), Linux 5.15 (only clone support), and Linux 5.19 (full > support including clone3). > --- <..> > +#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; > +}; > + > +static int > +parse_fdinfo (const char *l, void *arg) > +{ > + enum { fieldlen = sizeof ("Pid:") - 1 }; > + if (strncmp (l, "Pid:", fieldlen) != 0) > + return 0; > + > + l += fieldlen; > + > + char *endp; > + unsigned long n = strtoul (l, &endp, 10); > + if (l == endp || (n > INT_MAX && n != ULONG_MAX)) > + return 0; How can this tell the difference between '-1' and garbage input? It seems to me this will confuse mangled input here with ESRCH, given the pid in fdinfo is initialized to -1, no? > + struct parse_fdinfo_t *fdinfo = arg; > + fdinfo->found = true; > + fdinfo->pid = n; > + > + return 1; > +} > + > +pid_t > +pidfd_getpid (int fd) > +{ > + if (__glibc_unlikely (fd < 0)) > + { > + __set_errno (EINVAL); > + 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) == -1) > + /* 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); Here it just assumes this is an ESRSCH case, but again it could be failing to parse it for other corner cases of stroul. It should return ESRCH _only_ if it really parsed -1 from fdinfo, otherwise we cannot rely on it. Kind regards, Luca Boccassi
On Mai 16 2023, Adhemerval Zanella via Libc-alpha wrote: > diff --git a/NEWS b/NEWS > index aaecdc1c5b..7334bb49e9 100644 > --- a/NEWS > +++ b/NEWS > @@ -47,6 +47,10 @@ Major new features: > return a process ID, it returns a file descriptor that can be used along > other pidfd functions. > > +* On Linux, the pidfd_getpid has been added. It allows to retrieve the the pidfd_getpid function > diff --git a/manual/process.texi b/manual/process.texi > index 93e0ab5fb7..25417dce0d 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 > @@ -389,6 +390,37 @@ Acts as @code{_Fork}, where it does not invoke any callbacks registered with > > This function is specific to Linux. > > +@node Querying a Process > +@section Querying a Process > + > +The @code{pidfd_fork} function returned file descriptor can be used to query > +for process extra information. The file descriptor returned by the @code{pidfd_fork} function > +@deftypefun pid_t pidfd_getpid (int @var{fd}) > +@standards{GNU, sys/pidfd.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > + > +The @code{pidfd_getpid} retrieves the process ID associated with process file The @code{pidfd_getpid} function > +If the operation fails, @code{pidfd_getpid} return a value of @code{-1} and the returns @code{-1}
On 16/05/23 08:54, Luca Boccassi wrote: > On Tue, 16 May 2023 at 12:46, Adhemerval Zanella > <adhemerval.zanella@linaro.org> wrote: >> >> This interface allows to obtain the associated pid 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 set the >> errno accordingly. The possible errno values are the smae from >> open, read, and close (used on procps parsing), along with: >> >> - EINVAL if the FP is negative (similar to fexecve). >> >> - EBADF if the FD does not have a PID associated of if the fdinfo >> fields contains 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_PID or waitid >> support), Linux 5.15 (only clone support), and Linux 5.19 (full >> support including clone3). >> --- > <..> >> +#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; >> +}; >> + >> +static int >> +parse_fdinfo (const char *l, void *arg) >> +{ >> + enum { fieldlen = sizeof ("Pid:") - 1 }; >> + if (strncmp (l, "Pid:", fieldlen) != 0) >> + return 0; >> + >> + l += fieldlen; >> + >> + char *endp; >> + unsigned long n = strtoul (l, &endp, 10); >> + if (l == endp || (n > INT_MAX && n != ULONG_MAX)) >> + return 0; > > How can this tell the difference between '-1' and garbage input? It > seems to me this will confuse mangled input here with ESRCH, given the > pid in fdinfo is initialized to -1, no? Because -1 will be parsed as ULONG_MAX. For instance, with the inputs: Input: | Function result | parse_fdinfo_t -------------------|-----------------|----------------------- "Pid: 0" | 1 | {1, 0} "Pid: 1" | 1 | {1, 1} "Pid: 2147483647" | 1 | {1, 2147483647} "Pid: 2147483648" | 0 | {0, -1} "Pid: -1" | 1 | {1, -1} "Pid: -3" | 0 | {0, -1} "Pid: -24x" | 0 | {0, -1} So only if the PID if positive less than INT_MAX or -1 the function will set that the PID as found. > >> + struct parse_fdinfo_t *fdinfo = arg; >> + fdinfo->found = true; >> + fdinfo->pid = n; >> + >> + return 1; >> +} >> + >> +pid_t >> +pidfd_getpid (int fd) >> +{ >> + if (__glibc_unlikely (fd < 0)) >> + { >> + __set_errno (EINVAL); >> + 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) == -1) >> + /* 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); > > Here it just assumes this is an ESRSCH case, but again it could be > failing to parse it for other corner cases of stroul. It should return > ESRCH _only_ if it really parsed -1 from fdinfo, otherwise we cannot > rely on it. It is already handled by the 'found' check above, where for values not in PID range or error in strtoul, EBADF will be returned. I might improve the comments to make it clear.
On Tue, 16 May 2023 at 13:26, Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> wrote: > On 16/05/23 08:54, Luca Boccassi wrote: > > On Tue, 16 May 2023 at 12:46, Adhemerval Zanella > > <adhemerval.zanella@linaro.org> wrote: > >> > >> This interface allows to obtain the associated pid 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 set the > >> errno accordingly. The possible errno values are the smae from > >> open, read, and close (used on procps parsing), along with: > >> > >> - EINVAL if the FP is negative (similar to fexecve). > >> > >> - EBADF if the FD does not have a PID associated of if the fdinfo > >> fields contains 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_PID or waitid > >> support), Linux 5.15 (only clone support), and Linux 5.19 (full > >> support including clone3). > >> --- > > <..> > >> +#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; > >> +}; > >> + > >> +static int > >> +parse_fdinfo (const char *l, void *arg) > >> +{ > >> + enum { fieldlen = sizeof ("Pid:") - 1 }; > >> + if (strncmp (l, "Pid:", fieldlen) != 0) > >> + return 0; > >> + > >> + l += fieldlen; > >> + > >> + char *endp; > >> + unsigned long n = strtoul (l, &endp, 10); > >> + if (l == endp || (n > INT_MAX && n != ULONG_MAX)) > >> + return 0; > > > > How can this tell the difference between '-1' and garbage input? It > > seems to me this will confuse mangled input here with ESRCH, given the > > pid in fdinfo is initialized to -1, no? > > Because -1 will be parsed as ULONG_MAX. For instance, with the inputs: > > Input: | Function result | parse_fdinfo_t > -------------------|-----------------|----------------------- > "Pid: 0" | 1 | {1, 0} > "Pid: 1" | 1 | {1, 1} > "Pid: 2147483647" | 1 | {1, 2147483647} > "Pid: 2147483648" | 0 | {0, -1} > "Pid: -1" | 1 | {1, -1} > "Pid: -3" | 0 | {0, -1} > "Pid: -24x" | 0 | {0, -1} > > So only if the PID if positive less than INT_MAX or -1 the function > will set that the PID as found. This seems excessively convoluted and fragile to me, relying on overflows and so on. I cannot stress this enough, in order to use this from systemd et al I need to be absolutely certain that garbage input is not treated the same as ESCHR. Why not just use strtoll or so, to get an exact result out of it? Kind regards, Luca Boccassi
On Tue, May 16, 2023, at 8:38 AM, Luca Boccassi via Libc-alpha wrote: > On Tue, 16 May 2023 at 13:26, Adhemerval Zanella Netto > <adhemerval.zanella@linaro.org> wrote: >> >> + unsigned long n = strtoul (l, &endp, 10); >> >> + if (l == endp || (n > INT_MAX && n != ULONG_MAX)) >> >> + return 0; >> > >> > How can this tell the difference between '-1' and garbage input? It >> > seems to me this will confuse mangled input here with ESRCH, given the >> > pid in fdinfo is initialized to -1, no? >> >> Because -1 will be parsed as ULONG_MAX. For instance, with the inputs: >> >> Input: | Function result | parse_fdinfo_t >> -------------------|-----------------|----------------------- >> "Pid: 0" | 1 | {1, 0} >> "Pid: 1" | 1 | {1, 1} >> "Pid: 2147483647" | 1 | {1, 2147483647} >> "Pid: 2147483648" | 0 | {0, -1} >> "Pid: -1" | 1 | {1, -1} >> "Pid: -3" | 0 | {0, -1} >> "Pid: -24x" | 0 | {0, -1} >> >> So only if the PID if positive less than INT_MAX or -1 the function >> will set that the PID as found. > > This seems excessively convoluted and fragile to me, relying on > overflows and so on. I cannot stress this enough, in order to use this > from systemd et al I need to be absolutely certain that garbage input > is not treated the same as ESCHR. Why not just use strtoll or so, to > get an exact result out of it? Also, all of the strto* functions are sensitive to the locale. It shouldn't be too hard to make this function async-signal-safe and I think we really ought to. (Actually, why isn't this operation exposed as an ioctl on the pidfd? I thought the kernel people had come around to accepting that parsing text files in /proc is fragile, inconvenient, and slow.) zw
On 16/05/23 09:55, Zack Weinberg via Libc-alpha wrote: > On Tue, May 16, 2023, at 8:38 AM, Luca Boccassi via Libc-alpha wrote: >> On Tue, 16 May 2023 at 13:26, Adhemerval Zanella Netto >> <adhemerval.zanella@linaro.org> wrote: >>>>> + unsigned long n = strtoul (l, &endp, 10); >>>>> + if (l == endp || (n > INT_MAX && n != ULONG_MAX)) >>>>> + return 0; >>>> >>>> How can this tell the difference between '-1' and garbage input? It >>>> seems to me this will confuse mangled input here with ESRCH, given the >>>> pid in fdinfo is initialized to -1, no? >>> >>> Because -1 will be parsed as ULONG_MAX. For instance, with the inputs: >>> >>> Input: | Function result | parse_fdinfo_t >>> -------------------|-----------------|----------------------- >>> "Pid: 0" | 1 | {1, 0} >>> "Pid: 1" | 1 | {1, 1} >>> "Pid: 2147483647" | 1 | {1, 2147483647} >>> "Pid: 2147483648" | 0 | {0, -1} >>> "Pid: -1" | 1 | {1, -1} >>> "Pid: -3" | 0 | {0, -1} >>> "Pid: -24x" | 0 | {0, -1} >>> >>> So only if the PID if positive less than INT_MAX or -1 the function >>> will set that the PID as found. >> >> This seems excessively convoluted and fragile to me, relying on >> overflows and so on. I cannot stress this enough, in order to use this >> from systemd et al I need to be absolutely certain that garbage input >> is not treated the same as ESCHR. Why not just use strtoll or so, to >> get an exact result out of it? > > Also, all of the strto* functions are sensitive to the locale. It shouldn't be too hard to make this function async-signal-safe and I think we really ought to. Indeed the locale sensitivity is far from ideal, I will change to a async-signal-safe one. > > (Actually, why isn't this operation exposed as an ioctl on the pidfd? I thought the kernel people had come around to accepting that parsing text files in /proc is fragile, inconvenient, and slow.) My guess is the usercases for this interface has not yet clashed with the interfaces that require direct pid access.
diff --git a/NEWS b/NEWS index aaecdc1c5b..7334bb49e9 100644 --- a/NEWS +++ b/NEWS @@ -47,6 +47,10 @@ Major new features: return a process ID, it returns a file descriptor that can be used along other pidfd functions. +* On Linux, the pidfd_getpid has been added. It allows to retrieve the + process ID associated with process file descriptor created with + pid_spawn, pidfd_fork, or pidfd_open. + Deprecated and removed features, and other changes affecting compatibility: * In the Linux kernel for the hppa/parisc architecture some of the diff --git a/manual/process.texi b/manual/process.texi index 93e0ab5fb7..25417dce0d 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 @@ -389,6 +390,37 @@ Acts as @code{_Fork}, where it does not invoke any callbacks registered with This function is specific to Linux. +@node Querying a Process +@section Querying a Process + +The @code{pidfd_fork} function returned file descriptor can be used to query +for 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} 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 a value of @code{-1} and the +following @code{errno} error conditionas are defined: + +@table @code +@item EINVAL +The input file descriptor is negative. +@item EBADF +The input file descriptor 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. +@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 8673b6e437..52e277f8c0 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -210,6 +210,7 @@ tests += \ tst-ofdlocks \ tst-personality \ tst-pidfd \ + tst-pidfd_getpid \ tst-pkey \ tst-ppoll \ tst-prctl \ @@ -489,8 +490,10 @@ sysdep_routines += \ getcpu \ oldglob \ pidfd_fork \ + pidfd_getpid \ pidfd_spawn \ pidfd_spawnp \ + procutils \ sched_getcpu \ sched_getcpu \ # sysdep_routines diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions index 7e4109e9c5..047bc0c92a 100644 --- a/sysdeps/unix/sysv/linux/Versions +++ b/sysdeps/unix/sysv/linux/Versions @@ -323,6 +323,7 @@ libc { } GLIBC_2.38 { pidfd_fork; + pidfd_getpid; pidfd_spawn; pidfd_spawnp; } diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index dbf7c44319..febfc78f29 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2666,5 +2666,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index a9d6ffce14..87f93beeb8 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -2775,6 +2775,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 _IO_fprintf F diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist index c08d548556..dd33567a75 100644 --- a/sysdeps/unix/sysv/linux/arc/libc.abilist +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist @@ -2427,5 +2427,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist index f348336ee7..2344b8ae48 100644 --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist @@ -547,6 +547,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 _Exit F diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist index 5aed593521..b34ec3e9cc 100644 --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist @@ -544,6 +544,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 _Exit F diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist index 8a7022aaa8..f59d84fdb0 100644 --- a/sysdeps/unix/sysv/linux/csky/libc.abilist +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist @@ -2703,5 +2703,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index e2ac6949df..f6527bb9db 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -2652,6 +2652,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index 5e8d49fc1f..28ccb54206 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -2836,6 +2836,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist index 3cd3c80334..aabf217819 100644 --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist @@ -2601,6 +2601,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist index 0965db2ff0..8b53d82e8c 100644 --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist @@ -2187,5 +2187,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index 1ec24886a3..66bf4532ab 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -548,6 +548,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 _Exit F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index 239b1d70be..0ee9fef825 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2779,6 +2779,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist index dd41d63394..8861ebb4ca 100644 --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist @@ -2752,5 +2752,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist index 55c3dcd471..008dda3746 100644 --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist @@ -2749,5 +2749,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index 295e4d8608..2d0af493ed 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -2744,6 +2744,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index 19fb1aebe7..ae82d18edb 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -2742,6 +2742,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index 2dd6ef5416..87aee7f86d 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -2750,6 +2750,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index 6445d27220..c0d1fd370a 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -2652,6 +2652,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist index c1cc5134c9..06092621b9 100644 --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist @@ -2791,5 +2791,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist index 293643346a..88dcdd8b98 100644 --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist @@ -2173,5 +2173,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp 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..8650f60586 --- /dev/null +++ b/sysdeps/unix/sysv/linux/pidfd_getpid.c @@ -0,0 +1,94 @@ +/* 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; +}; + +static int +parse_fdinfo (const char *l, void *arg) +{ + enum { fieldlen = sizeof ("Pid:") - 1 }; + if (strncmp (l, "Pid:", fieldlen) != 0) + return 0; + + l += fieldlen; + + char *endp; + unsigned long n = strtoul (l, &endp, 10); + if (l == endp || (n > INT_MAX && n != ULONG_MAX)) + return 0; + + struct parse_fdinfo_t *fdinfo = arg; + fdinfo->found = true; + fdinfo->pid = n; + + return 1; +} + +pid_t +pidfd_getpid (int fd) +{ + if (__glibc_unlikely (fd < 0)) + { + __set_errno (EINVAL); + 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) == -1) + /* 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 03a35e860d..ce885f9136 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -2818,6 +2818,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 _IO_fprintf F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index a91af4245b..8063a0606e 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -2851,6 +2851,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 _IO_fprintf F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist index c15137b9ad..21fb95a352 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist @@ -2572,6 +2572,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 _IO_fprintf F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist index 12c0f4cfba..14bda5b5b8 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist @@ -2886,5 +2886,6 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F diff --git a/sysdeps/unix/sysv/linux/procutils.c b/sysdeps/unix/sysv/linux/procutils.c new file mode 100644 index 0000000000..83b327cb9a --- /dev/null +++ b/sysdeps/unix/sysv/linux/procutils.c @@ -0,0 +1,104 @@ +/* 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 = __read_nocancel (fd, *re, buffer_end - *re); + if (n < 0) + return -1; + + *re += n; + + nl = memchr (*cp, '\n', *re - *cp); + while (nl == NULL && *re == buffer_end) + { + /* Truncate too long lines. */ + *re = buffer + 3 * (buffer_end - buffer) / 4; + n = __read_nocancel (fd, *re, buffer_end - *re); + if (n < 0) + return -1; + + nl = memchr (*re, '\n', n); + **re = '\0'; + *re += n; + } + } + 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; +} + +int +procutils_read_file (const char *filename, procutils_closure_t closure, + void *arg) +{ + enum { buffer_size = 1024 }; + char buffer[buffer_size]; + char *buffer_end = buffer + buffer_size; + char *cp = buffer_end; + char *re = buffer_end; + + int fd = __open64_nocancel (filename, O_RDONLY | O_CLOEXEC); + if (fd == -1) + return -1; + + 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; +} diff --git a/sysdeps/unix/sysv/linux/procutils.h b/sysdeps/unix/sysv/linux/procutils.h new file mode 100644 index 0000000000..64e1080920 --- /dev/null +++ b/sysdeps/unix/sysv/linux/procutils.h @@ -0,0 +1,35 @@ +/* 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 + +typedef int (*procutils_closure_t)(const char *line, void *arg); + +/* 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 true if the read should continue, or false + if the function should stop. + + It returns 0 in case of success, or -1 otherwise. */ +int 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 9537dac42d..b294ec1021 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist @@ -2429,5 +2429,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index ea72e6b648..61921a02d4 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2629,5 +2629,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index d6c895b487..fbc2d5826f 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -2816,6 +2816,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 _IO_fprintf F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index b375f5a7ab..45ab26d7a7 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2609,6 +2609,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 _IO_fprintf F diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist index 7b2266ecb3..8de69e0057 100644 --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist @@ -2659,6 +2659,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist index 2f9f732044..3821ce3676 100644 --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist @@ -2656,6 +2656,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index 144d54ebf2..7be5b0c125 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -2811,6 +2811,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 _IO_fprintf F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index bc8bd8ff54..a09b2efc90 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2624,6 +2624,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/sys/pidfd.h b/sysdeps/unix/sysv/linux/sys/pidfd.h index 1942773957..5be3eb1167 100644 --- a/sysdeps/unix/sysv/linux/sys/pidfd.h +++ b/sysdeps/unix/sysv/linux/sys/pidfd.h @@ -59,4 +59,8 @@ extern int pidfd_send_signal (int __pidfd, int __sig, siginfo_t *__info, of the new process to the parent process. */ extern int pidfd_fork (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..a03de4b290 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,9 @@ #include <support/xsocket.h> #include <sys/pidfd.h> #include <sys/wait.h> +#include <stdlib.h> + +#include <string.h> #define REMOTE_PATH "/dev/null" @@ -102,6 +106,41 @@ do_test (void) ppid = getpid (); puid = getuid (); + /* Sanity check for invalid inputs. */ + TEST_COMPARE (pidfd_getpid (-1), -1); + TEST_COMPARE (errno, EINVAL); + + { + pid_t pid = pidfd_getpid (STDOUT_FILENO); + TEST_COMPARE (pid, -1); + TEST_COMPARE (errno, EBADF); + } + + /* Check if pidfd_getpid returns ESRCH for exited subprocess. */ + { + int pidfd = pidfd_fork (0); + if (pidfd == 0) + exit (EXIT_SUCCESS); + + /* The process might be still running or already in zombie state, in any + case the PID is still allocated to the process. */ + pid_t pid = pidfd_getpid (pidfd); + if (pid > 0) + support_process_state_wait (pid, support_process_state_zombie); + + siginfo_t info; + TEST_COMPARE (waitid (P_PIDFD, pidfd, &info, WEXITED), 0); + 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 (pidfd); + TEST_COMPARE (pid, -1); + TEST_COMPARE (errno, ESRCH); + + xclose (pidfd); + } + TEST_COMPARE (socketpair (AF_UNIX, SOCK_STREAM, 0, sockets), 0); pid_t pid = xfork (); @@ -118,6 +157,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..c079ed5883 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-pidfd_getpid.c @@ -0,0 +1,177 @@ +/* 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/xsocket.h> +#include <support/xunistd.h> +#include <support/test-driver.h> +#include <sys/pidfd.h> +#include <sys/wait.h> +#include <sys/mount.h> +#include <string.h> + +#include <stdio.h> + +static int sockfd[2]; + +static void +send_fd (const int sock, const int fd) +{ + union + { + struct cmsghdr hdr; + char buf[CMSG_SPACE (sizeof (int))]; + } cmsgbuf = {0}; + struct cmsghdr *cmsg; + char ch = 'A'; + struct iovec vec = + { + .iov_base = &ch, + .iov_len = sizeof ch + }; + struct msghdr msg = + { + .msg_control = &cmsgbuf.buf, + .msg_controllen = sizeof (cmsgbuf.buf), + .msg_iov = &vec, + .msg_iovlen = 1, + }; + + cmsg = CMSG_FIRSTHDR (&msg); + cmsg->cmsg_len = CMSG_LEN (sizeof (int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + memcpy (CMSG_DATA (cmsg), &fd, sizeof (fd)); + + ssize_t n; + while ((n = sendmsg (sock, &msg, 0)) == -1 && errno == EINTR); + + TEST_VERIFY_EXIT (n == 1); +} + +static int +recv_fd (const int sock) +{ + union + { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf = {0}; + struct cmsghdr *cmsg; + char ch = '\0'; + struct iovec vec = + { + .iov_base = &ch, + .iov_len = sizeof ch + }; + struct msghdr msg = + { + .msg_control = &cmsgbuf.buf, + .msg_controllen = sizeof (cmsgbuf.buf), + .msg_iov = &vec, + .msg_iovlen = 1, + }; + + ssize_t n; + while ((n = recvmsg (sock, &msg, 0)) == -1 && errno == EINTR); + if (n != 1 || ch != 'A') + return -1; + + cmsg = CMSG_FIRSTHDR (&msg); + if (cmsg == NULL) + return -1; + if (cmsg->cmsg_type != SCM_RIGHTS) + return -1; + + int fd = -1; + memcpy (&fd, CMSG_DATA (cmsg), sizeof (fd)); + if (fd < 0) + return -1; + return fd; +} + +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"); + } + + TEST_VERIFY_EXIT (socketpair (AF_UNIX, SOCK_STREAM, 0, sockfd) == 0); + + /* Check if pidfd_getpid returns EREMOTE for process not in current + namespace. */ + { + int pidfd = pidfd_fork (0); + TEST_VERIFY (pidfd >= 0); + if (pidfd == 0) + { + 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"); + } + + TEST_VERIFY_EXIT (mount (NULL, "/", NULL, MS_REC | MS_PRIVATE, 0) + == 0); + + pid_t child = xfork (); + if (child > 0) + { + int status; + xwaitpid (child, &status, 0); + TEST_VERIFY (WIFEXITED (status)); + exit (WEXITSTATUS (status)); + } + + /* Now that we're pid 1 (effectively "root") we can mount /proc */ + TEST_VERIFY_EXIT (mount ("proc", "/proc", "proc", 0, NULL) == 0); + + int ppidfd = recv_fd (sockfd[0]); + TEST_COMPARE (pidfd_getpid (ppidfd), -1); + TEST_COMPARE (errno, EREMOTE); + + exit (EXIT_SUCCESS); + } + + send_fd (sockfd[1], pidfd); + + siginfo_t info; + TEST_COMPARE (waitid (P_PIDFD, 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); + } + + 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 045205de0c..0726b6e8d0 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2575,6 +2575,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index 5a67604948..9c1f6830ba 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2681,5 +2681,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F GLIBC_2.38 pidfd_fork F +GLIBC_2.38 pidfd_getpid F GLIBC_2.38 pidfd_spawn F GLIBC_2.38 pidfd_spawnp F