Repository: util-linux/util-linux
Pull request #3439: include/pidfd-utils: improve robustness
Author: login: karelzak
Created: 2025-03-04T08:51:18Z | Merged: 2025-03-04T14:10:18Z

* Check for all SYS_* macros
* Define UL_HAVE_PIDFD only if all syscalls are available

Fixes: https://github.com/util-linux/util-linux/issues/3437


Diff:
diff --git a/include/pidfd-utils.h b/include/pidfd-utils.h
index 5bd59694a5b..08627ca8d28 100644
--- a/include/pidfd-utils.h
+++ b/include/pidfd-utils.h
@@ -36,35 +36,35 @@
 # include <sys/syscall.h>
 # include <unistd.h>
 
-# if defined(SYS_pidfd_send_signal) && defined(SYS_pidfd_open)
-#  ifndef HAVE_PIDFD_SEND_SIGNAL
+# if !defined(HAVE_PIDFD_SEND_SIGNAL) && defined(SYS_pidfd_send_signal)
 static inline int pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
 				    unsigned int flags)
 {
 	return syscall(SYS_pidfd_send_signal, pidfd, sig, info, flags);
 }
-#  endif
+# endif
 
-#  ifndef HAVE_PIDFD_OPEN
+# if !defined(HAVE_PIDFD_OPEN) && defined(SYS_pidfd_open)
 static inline int pidfd_open(pid_t pid, unsigned int flags)
 {
 	return syscall(SYS_pidfd_open, pid, flags);
 }
-#  endif
+# endif
 
-#  ifndef HAVE_PIDFD_GETFD
+# if !defined(HAVE_PIDFD_GETFD) && defined(SYS_pidfd_getfd)
 static inline int pidfd_getfd(int pidfd, int targetfd, unsigned int flags)
 {
 	return syscall(SYS_pidfd_getfd, pidfd, targetfd, flags);
 }
-#  endif
+# endif
+#endif /* HAVE_SYS_SYSCALL_H */
 
-#  define UL_HAVE_PIDFD 1
 
-# endif	/* SYS_pidfd_send_signal */
-#endif /* HAVE_SYS_SYSCALL_H */
+/*
+ * Dummy fallbacks for cases when #ifdef HAVE_PIDFD_* makes the code too complex.
+ */
 
-#ifndef UL_HAVE_PIDFD
+#if !defined(HAVE_PIDFD_SEND_SIGNAL) && !defined(SYS_pidfd_send_signal)
 static inline int pidfd_send_signal(int pidfd __attribute__((unused)),
 				    int sig __attribute__((unused)),
 				    siginfo_t *info __attribute__((unused)),
@@ -73,14 +73,18 @@ static inline int pidfd_send_signal(int pidfd __attribute__((unused)),
 	errno = ENOSYS;
 	return -1;
 }
+#endif
 
+#if !defined(HAVE_PIDFD_OPEN) && !defined(SYS_pidfd_open)
 static inline int pidfd_open(pid_t pid __attribute__((unused)),
 			     unsigned int flags __attribute__((unused)))
 {
 	errno = ENOSYS;
 	return -1;
 }
+#endif
 
+# if !defined(HAVE_PIDFD_GETFD) && !defined(SYS_pidfd_getfd)
 static inline int pidfd_getfd(int pidfd __attribute__((unused)),
 			      int targetfd __attribute__((unused)),
 			      unsigned int flags __attribute__((unused)))
diff --git a/misc-utils/kill.c b/misc-utils/kill.c
index a911df6b723..fefe0d89179 100644
--- a/misc-utils/kill.c
+++ b/misc-utils/kill.c
@@ -67,12 +67,16 @@
 /* partial success, otherwise we return regular EXIT_{SUCCESS,FAILURE} */
 #define KILL_EXIT_SOMEOK	64
 
+#if defined(HAVE_PIDFD_OPEN) && defined(HAVE_PIDFD_SEND_SIGNAL)
+# define USE_KILL_WITH_TIMEOUT 1
+#endif
+
 enum {
 	KILL_FIELD_WIDTH = 11,
 	KILL_OUTPUT_WIDTH = 72
 };
 
-#ifdef UL_HAVE_PIDFD
+#ifdef USE_KILL_WITH_TIMEOUT
 # include <poll.h>
 # include "list.h"
 struct timeouts {
@@ -89,7 +93,7 @@ struct kill_control {
 #ifdef HAVE_SIGQUEUE
 	union sigval sigdata;
 #endif
-#ifdef UL_HAVE_PIDFD
+#ifdef USE_KILL_WITH_TIMEOUT
 	struct list_head follow_ups;
 #endif
 	bool	check_all,
@@ -97,7 +101,7 @@ struct kill_control {
 		do_pid,
 		require_handler,
 		use_sigval,
-#ifdef UL_HAVE_PIDFD
+#ifdef USE_KILL_WITH_TIMEOUT
 		timeout,
 #endif
 		verbose;
@@ -269,7 +273,7 @@ static void __attribute__((__noreturn__)) usage(void)
 #ifdef HAVE_SIGQUEUE
 	fputs(_(" -q, --queue <value>    use sigqueue(2), not kill(2), and pass <value> as data\n"), out);
 #endif
-#ifdef UL_HAVE_PIDFD
+#ifdef USE_KILL_WITH_TIMEOUT
 	fputs(_("     --timeout <milliseconds> <follow-up signal>\n"
 		"                        wait up to timeout and send follow-up signal\n"), out);
 #endif
@@ -296,7 +300,7 @@ static void __attribute__((__noreturn__)) print_kill_version(void)
 #ifdef HAVE_SIGQUEUE
 		"sigqueue",
 #endif
-#ifdef UL_HAVE_PIDFD
+#ifdef USE_KILL_WITH_TIMEOUT
 		"pidfd",
 #endif
 	};
@@ -443,7 +447,7 @@ static char **parse_arguments(int argc, char **argv, struct kill_control *ctl)
 			continue;
 		}
 #endif
-#ifdef UL_HAVE_PIDFD
+#ifdef USE_KILL_WITH_TIMEOUT
 		if (!strcmp(arg, "--timeout")) {
 			struct timeouts *next;
 
@@ -485,7 +489,7 @@ static char **parse_arguments(int argc, char **argv, struct kill_control *ctl)
 	return argv;
 }
 
-#ifdef UL_HAVE_PIDFD
+#ifdef USE_KILL_WITH_TIMEOUT
 static int kill_with_timeout(const struct kill_control *ctl)
 {
 	int pfd, n;
@@ -537,7 +541,7 @@ static int kill_verbose(const struct kill_control *ctl)
 		printf("%ld\n", (long) ctl->pid);
 		return 0;
 	}
-#ifdef UL_HAVE_PIDFD
+#ifdef USE_KILL_WITH_TIMEOUT
 	if (ctl->timeout) {
 		rc = kill_with_timeout(ctl);
 	} else
@@ -590,7 +594,7 @@ int main(int argc, char **argv)
 	textdomain(PACKAGE);
 	close_stdout_atexit();
 
-#ifdef UL_HAVE_PIDFD
+#ifdef USE_KILL_WITH_TIMEOUT
 	INIT_LIST_HEAD(&ctl.follow_ups);
 #endif
 	argv = parse_arguments(argc, argv, &ctl);
@@ -642,7 +646,7 @@ int main(int argc, char **argv)
 		}
 	}
 
-#ifdef UL_HAVE_PIDFD
+#ifdef USE_KILL_WITH_TIMEOUT
 	while (!list_empty(&ctl.follow_ups)) {
 		struct timeouts *x = list_entry(ctl.follow_ups.next,
 				                  struct timeouts, follow_ups);
diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c
index 9ec6ef7cce1..d5ce369c2b4 100644
--- a/sys-utils/unshare.c
+++ b/sys-utils/unshare.c
@@ -889,7 +889,7 @@ int main(int argc, char *argv[])
 	pid_t pid_bind = 0, pid_idmap = 0;
 	const char *newinterp = NULL;
 	pid_t pid = 0;
-#ifdef UL_HAVE_PIDFD
+#ifdef HAVE_PIDFD_OPEN
 	int fd_parent_pid = -1;
 #endif
 	int fd_idmap, fd_bind = -1;
@@ -1116,7 +1116,7 @@ int main(int argc, char *argv[])
 			sigaddset(&sigset, SIGTERM) != 0 ||
 			sigprocmask(SIG_BLOCK, &sigset, &oldsigset) != 0)
 			err(EXIT_FAILURE, _("sigprocmask block failed"));
-#ifdef UL_HAVE_PIDFD
+#ifdef HAVE_PIDFD_OPEN
 		if (kill_child_signo != 0) {
 			/* make a connection to the original process (parent) */
 			fd_parent_pid = pidfd_open(getpid(), 0);
@@ -1182,7 +1182,7 @@ int main(int argc, char *argv[])
 	if (kill_child_signo != 0) {
 		if (prctl(PR_SET_PDEATHSIG, kill_child_signo) < 0)
 			err(EXIT_FAILURE, "prctl failed");
-#ifdef UL_HAVE_PIDFD
+#ifdef HAVE_PIDFD_OPEN
 		/* Use poll() to check that there is still the original parent. */
 		if (fd_parent_pid != -1) {
 			struct pollfd pollfds[1] = {
diff --git a/tests/helpers/test_mkfds.c b/tests/helpers/test_mkfds.c
index 2a9bc5c49dd..82f7a794eb2 100644
--- a/tests/helpers/test_mkfds.c
+++ b/tests/helpers/test_mkfds.c
@@ -21,6 +21,7 @@
 #include "xalloc.h"
 #include "test_mkfds.h"
 #include "exitcodes.h"
+#include "pidfd-utils.h"
 
 #include <arpa/inet.h>
 #include <ctype.h>
@@ -81,7 +82,6 @@
 
 #define _U_ __attribute__((__unused__))
 
-static int pidfd_open(pid_t pid, unsigned int flags);
 static void do_nothing(int signum _U_);
 
 static void __attribute__((__noreturn__)) usage(FILE *out, int status)
@@ -4410,22 +4410,6 @@ static void do_nothing(int signum _U_)
 {
 }
 
-#ifdef __NR_pidfd_open
-
-static int
-pidfd_open(pid_t pid, unsigned int flags)
-{
-	return syscall(__NR_pidfd_open, pid, flags);
-}
-#else
-static int
-pidfd_open(pid_t pid _U_, unsigned int flags _U_)
-{
-	errno = ENOSYS;
-	return -1;
-}
-#endif
-
 /*
  * Multiplexers
  */


Reviews:
user: login: echoechoin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T09:13:12Z
user: login: karelzak
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-04T10:11:35Z

Review comments:
diff_hunk: @@ -36,34 +36,35 @@
 # include <sys/syscall.h>
 # include <unistd.h>
 
-# if defined(SYS_pidfd_send_signal) && defined(SYS_pidfd_open)
-#  ifndef HAVE_PIDFD_SEND_SIGNAL
+# if !defined(HAVE_PIDFD_SEND_SIGNAL) && defined(SYS_pidfd_send_signal)
 static inline int pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
 				    unsigned int flags)
 {
 	return syscall(SYS_pidfd_send_signal, pidfd, sig, info, flags);
 }
-#  endif
+# endif
 
-#  ifndef HAVE_PIDFD_OPEN
+# if !defined(HAVE_PIDFD_OPEN) && defined(SYS_pidfd_open)
 static inline int pidfd_open(pid_t pid, unsigned int flags)
 {
 	return syscall(SYS_pidfd_open, pid, flags);
 }
-#  endif
+# endif
 
-#  ifndef HAVE_PIDFD_GETFD
+# if !defined(HAVE_PIDFD_GETFD) && defined(SYS_pidfd_getfd)
 static inline int pidfd_getfd(int pidfd, int targetfd, unsigned int flags)
 {
 	return syscall(SYS_pidfd_getfd, pidfd, targetfd, flags);
 }
-#  endif
+# endif
 
+# if defined(SYS_pidfd_send_signal) && defined(SYS_pidfd_open) && defined(SYS_pidfd_getfd)
path: include/pidfd-utils.h
user: login: echoechoin
body: If SYS_pidfd_getfd not defined, pidfd_send_signal will be redefined:
```bash
  CC       misc-utils/kill.o
In file included from misc-utils/kill.c:58:
./include/pidfd-utils.h:69:19: error: redefinition of ‘pidfd_send_signal’
   69 | static inline int pidfd_send_signal(int pidfd __attribute__((unused)),
      |                   ^~~~~~~~~~~~~~~~~
./include/pidfd-utils.h:40:19: note: previous definition of ‘pidfd_send_signal’ was here
   40 | static inline int pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
      |                   ^~~~~~~~~~~~~~~~~
./include/pidfd-utils.h:78:19: error: redefinition of ‘pidfd_open’
   78 | static inline int pidfd_open(pid_t pid __attribute__((unused)),
      |                   ^~~~~~~~~~
./include/pidfd-utils.h:48:19: note: previous definition of ‘pidfd_open’ was here
   48 | static inline int pidfd_open(pid_t pid, unsigned int flags)
      |                   ^~~~~~~~~~
make[2]: *** [Makefile:11272: misc-utils/kill.o] Error 1
make[2]: Leaving directory '/home/echo/tmpRepository/util-linux'
make[1]: *** [Makefile:17522: all-recursive] Error 1
make[1]: Leaving directory '/home/echo/tmpRepository/util-linux'
make: *** [Makefile:7554: all] Error 2
```
created_at: 2025-03-04T09:13:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -36,34 +36,35 @@
 # include <sys/syscall.h>
 # include <unistd.h>
 
-# if defined(SYS_pidfd_send_signal) && defined(SYS_pidfd_open)
-#  ifndef HAVE_PIDFD_SEND_SIGNAL
+# if !defined(HAVE_PIDFD_SEND_SIGNAL) && defined(SYS_pidfd_send_signal)
 static inline int pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
 				    unsigned int flags)
 {
 	return syscall(SYS_pidfd_send_signal, pidfd, sig, info, flags);
 }
-#  endif
+# endif
 
-#  ifndef HAVE_PIDFD_OPEN
+# if !defined(HAVE_PIDFD_OPEN) && defined(SYS_pidfd_open)
 static inline int pidfd_open(pid_t pid, unsigned int flags)
 {
 	return syscall(SYS_pidfd_open, pid, flags);
 }
-#  endif
+# endif
 
-#  ifndef HAVE_PIDFD_GETFD
+# if !defined(HAVE_PIDFD_GETFD) && defined(SYS_pidfd_getfd)
 static inline int pidfd_getfd(int pidfd, int targetfd, unsigned int flags)
 {
 	return syscall(SYS_pidfd_getfd, pidfd, targetfd, flags);
 }
-#  endif
+# endif
 
+# if defined(SYS_pidfd_send_signal) && defined(SYS_pidfd_open) && defined(SYS_pidfd_getfd)
path: include/pidfd-utils.h
user: login: karelzak
body: Ah, I see.
created_at: 2025-03-04T10:11:35Z
author_association: COLLABORATOR

PR comments:
user: login: masatake
created_at: 2025-03-04T10:28:09Z
body: !!!
```
 gcc-13: internal compiler error: Segmentation fault signal terminated program cc1
``` 
author_association: MEMBER
user: login: karelzak
created_at: 2025-03-04T10:34:41Z
body: >  gcc-13: internal compiler error: Segmentation fault signal terminated program cc1

This is pretty common in the last month (see c389f166e5c35e3a7d91205997b75bec5d4353fb)
author_association: COLLABORATOR
user: login: karelzak
created_at: 2025-03-04T10:47:32Z
body: @echoechoin Please test it in your environment. Thanks.
author_association: COLLABORATOR
user: login: karelzak
created_at: 2025-03-04T10:48:46Z
body: @masatake I have removed pidfd_open() local fallback in test_mkfds.c. It seems better to use include/pidfd-utils.h.
author_association: COLLABORATOR
user: login: echoechoin
created_at: 2025-03-04T11:02:53Z
body: > @echoechoin Please test it in your environment. Thanks.

It works.
author_association: CONTRIBUTOR