1  /* Basic tests for Linux pidfd interfaces.
       2     Copyright (C) 2022-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <fcntl.h>
      21  #include <support/capture_subprocess.h>
      22  #include <support/check.h>
      23  #include <support/process_state.h>
      24  #include <support/support.h>
      25  #include <support/xsignal.h>
      26  #include <support/xunistd.h>
      27  #include <support/xsocket.h>
      28  #include <sys/pidfd.h>
      29  #include <sys/wait.h>
      30  
      31  #define REMOTE_PATH "/dev/null"
      32  
      33  /* The pair of sockets used for coordination.  The subprocess uses
      34     sockets[1].  */
      35  static int sockets[2];
      36  
      37  static pid_t ppid;
      38  static uid_t puid;
      39  
      40  static void
      41  sighandler (int sig)
      42  {
      43  }
      44  
      45  static void
      46  subprocess (void)
      47  {
      48    xsignal (SIGUSR1, sighandler);
      49    xsignal (SIGUSR2, sighandler);
      50  
      51    /* Check first pidfd_send_signal with default NULL siginfo_t argument.  */
      52    {
      53      sigset_t set;
      54      sigemptyset (&set);
      55      sigaddset (&set, SIGUSR1);
      56      siginfo_t info;
      57      TEST_COMPARE (sigtimedwait (&set, &info, NULL), SIGUSR1);
      58      TEST_COMPARE (info.si_signo, SIGUSR1);
      59      TEST_COMPARE (info.si_errno, 0);
      60      TEST_COMPARE (info.si_code, SI_USER);
      61      TEST_COMPARE (info.si_pid, ppid);
      62      TEST_COMPARE (info.si_uid, puid);
      63    }
      64  
      65    /* Check second pidfd_send_signal with crafted siginfo_t argument.  */
      66    {
      67      sigset_t set;
      68      sigemptyset (&set);
      69      sigaddset (&set, SIGUSR2);
      70      siginfo_t info;
      71      TEST_COMPARE (sigtimedwait (&set, &info, NULL), SIGUSR2);
      72      TEST_COMPARE (info.si_signo, SIGUSR2);
      73      TEST_COMPARE (info.si_errno, EAGAIN);
      74      TEST_COMPARE (info.si_code, -10);
      75      TEST_COMPARE (info.si_pid, ppid);
      76      TEST_COMPARE (info.si_uid, puid);
      77    }
      78  
      79    /* Send a local file descriptor value to check pidfd_getfd.  */
      80    int remote_fd = xopen (REMOTE_PATH, O_WRONLY | O_CLOEXEC, 0);
      81    xsendto (sockets[1], &remote_fd, sizeof (remote_fd), 0, NULL, 0);
      82  
      83    /* Wait for final pidfd_send_signal.  */
      84    pause ();
      85  
      86    _exit (0);
      87  }
      88  
      89  static int
      90  do_test (void)
      91  {
      92    {
      93      /* The pidfd_getfd syscall was the last in the set of pidfd related
      94         syscalls added to the kernel.  Use pidfd_getfd to decide if this
      95         kernel has pidfd support that we can test.  */
      96      int r = pidfd_getfd (0, 0, 1);
      97      TEST_VERIFY_EXIT (r == -1);
      98      if (errno == ENOSYS)
      99        FAIL_UNSUPPORTED ("kernel does not support pidfd_getfd, skipping test");
     100    }
     101  
     102    ppid = getpid ();
     103    puid = getuid ();
     104  
     105    TEST_COMPARE (socketpair (AF_UNIX, SOCK_STREAM, 0, sockets), 0);
     106  
     107    pid_t pid = xfork ();
     108    if (pid == 0)
     109      {
     110        xclose (sockets[0]);
     111        subprocess ();
     112      }
     113    xclose (sockets[1]);
     114  
     115    TEST_COMPARE (pidfd_open (-1, 0), -1);
     116    TEST_COMPARE (errno, EINVAL);
     117  
     118    int pidfd = pidfd_open (pid, 0);
     119    TEST_VERIFY (pidfd != -1);
     120  
     121    /* Wait for first sigtimedwait.  */
     122    support_process_state_wait (pid, support_process_state_sleeping);
     123    TEST_COMPARE (pidfd_send_signal (pidfd, SIGUSR1, NULL, 0), 0);
     124  
     125    /* Wait for second sigtimedwait.  */
     126    support_process_state_wait (pid, support_process_state_sleeping);
     127    {
     128      siginfo_t info =
     129        {
     130  	.si_signo = SIGUSR2,
     131  	.si_errno = EAGAIN,
     132  	.si_code = -10,
     133  	.si_pid = ppid,
     134  	.si_uid = puid
     135        };
     136      TEST_COMPARE (pidfd_send_signal (pidfd, SIGUSR2, &info, 0), 0);
     137    }
     138  
     139    /* Get remote file descriptor to check for pidfd_getfd.  */
     140    {
     141      int remote_fd;
     142      xrecvfrom (sockets[0], &remote_fd, sizeof (remote_fd), 0, NULL, 0);
     143  
     144      int fd = pidfd_getfd (pidfd, remote_fd, 0);
     145      /* pidfd_getfd may fail with EPERM if the process does not have
     146         PTRACE_MODE_ATTACH_REALCREDS permissions. This means the call
     147         may be denied if the process doesn't have CAP_SYS_PTRACE or
     148         if a LSM security_ptrace_access_check denies access.  */
     149      if (fd == -1 && errno == EPERM)
     150        {
     151  	TEST_COMPARE (pidfd_send_signal (pidfd, SIGKILL, NULL, 0), 0);
     152  	FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, "
     153  			  "skipping test");
     154        }
     155      TEST_VERIFY (fd > 0);
     156  
     157      char *path = xasprintf ("/proc/%d/fd/%d", pid, remote_fd);
     158      char *resolved = xreadlink (path);
     159      TEST_COMPARE_STRING (resolved, REMOTE_PATH);
     160  
     161      int remote_fd_mode = fcntl (fd, F_GETFL);
     162      TEST_VERIFY (remote_fd_mode != -1);
     163      TEST_VERIFY (remote_fd_mode & O_WRONLY);
     164  
     165      int remote_fd_flags = fcntl (fd, F_GETFD);
     166      TEST_VERIFY (remote_fd_flags != -1);
     167      TEST_VERIFY (remote_fd_flags & FD_CLOEXEC);
     168    }
     169  
     170    TEST_COMPARE (pidfd_send_signal (pidfd, SIGKILL, NULL, 0), 0);
     171    {
     172      siginfo_t info;
     173      int r = waitid (P_PIDFD, pidfd, &info, WEXITED);
     174      TEST_COMPARE (r, 0);
     175      TEST_COMPARE (info.si_status, SIGKILL);
     176      TEST_COMPARE (info.si_code, CLD_KILLED);
     177    }
     178  
     179    return 0;
     180  }
     181  
     182  #include <support/test-driver.c>