446cf2
commit 2f9046fb059e94fe254c9a4ff5bcd52182069e44
446cf2
Author: Stefan Liebler <stli@linux.ibm.com>
446cf2
Date:   Wed Sep 18 12:40:00 2019 +0200
446cf2
446cf2
    Add UNSUPPORTED check in elf/tst-pldd.
446cf2
    
446cf2
    The testcase forks a child process and runs pldd with PID of
446cf2
    this child.  On systems where /proc/sys/kernel/yama/ptrace_scope
446cf2
    differs from zero, pldd will fail with
446cf2
    /usr/bin/pldd: cannot attach to process 3: Operation not permitted
446cf2
    
446cf2
    This patch checks if ptrace_scope exists, is zero "classic ptrace permissions"
446cf2
    or one "restricted ptrace".  If ptrace_scope exists and has a higher
446cf2
    restriction, then the test is marked as UNSUPPORTED.
446cf2
    
446cf2
    The case "restricted ptrace" is handled by rearranging the processes involved
446cf2
    during the test.  Now we have the following process tree:
446cf2
    -parent: do_test (performs output checks)
446cf2
    --subprocess 1: pldd_process (becomes pldd via execve)
446cf2
    ---subprocess 2: target_process (ptraced via pldd)
446cf2
    
446cf2
    ChangeLog:
446cf2
    
446cf2
            * elf/tst-pldd.c (do_test): Add UNSUPPORTED check.
446cf2
            Rearrange subprocesses.
446cf2
            (pldd_process): New function.
446cf2
            * support/Makefile (libsupport-routines): Add support_ptrace.
446cf2
            * support/xptrace.h: New file.
446cf2
            * support/support_ptrace.c: Likewise.
446cf2
446cf2
Conflicts:
446cf2
	elf/tst-pldd.c
446cf2
	  (Original backport uses spaces instead of tabs.)
446cf2
446cf2
diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c
446cf2
index e2de31282a131166..f381cb0fa7e6b93d 100644
446cf2
--- a/elf/tst-pldd.c
446cf2
+++ b/elf/tst-pldd.c
446cf2
@@ -30,6 +30,11 @@
446cf2
 #include <support/capture_subprocess.h>
446cf2
 #include <support/check.h>
446cf2
 #include <support/support.h>
446cf2
+#include <support/xptrace.h>
446cf2
+#include <support/xunistd.h>
446cf2
+#include <sys/mman.h>
446cf2
+#include <errno.h>
446cf2
+#include <signal.h>
446cf2
 
446cf2
 static void
446cf2
 target_process (void *arg)
446cf2
@@ -37,6 +42,34 @@ target_process (void *arg)
446cf2
   pause ();
446cf2
 }
446cf2
 
446cf2
+static void
446cf2
+pldd_process (void *arg)
446cf2
+{
446cf2
+  pid_t *target_pid_ptr = (pid_t *) arg;
446cf2
+
446cf2
+  /* Create a copy of current test to check with pldd.  As the
446cf2
+     target_process is a child of this pldd_process, pldd is also able
446cf2
+     to attach to target_process if YAMA is configured to 1 =
446cf2
+     "restricted ptrace".  */
446cf2
+  struct support_subprocess target = support_subprocess (target_process, NULL);
446cf2
+
446cf2
+  /* Store the pid of target-process as do_test needs it in order to
446cf2
+     e.g. terminate it at end of the test.  */
446cf2
+  *target_pid_ptr = target.pid;
446cf2
+
446cf2
+  /* Three digits per byte plus null terminator.  */
446cf2
+  char pid[3 * sizeof (uint32_t) + 1];
446cf2
+  snprintf (pid, array_length (pid), "%d", target.pid);
446cf2
+
446cf2
+  char *prog = xasprintf ("%s/pldd", support_bindir_prefix);
446cf2
+
446cf2
+  /* Run pldd and use the pid of target_process as argument.  */
446cf2
+  execve (prog, (char *const []) { (char *) prog, pid, NULL },
446cf2
+	  (char *const []) { NULL });
446cf2
+
446cf2
+  FAIL_EXIT1 ("Returned from execve: errno=%d=%m\n", errno);
446cf2
+}
446cf2
+
446cf2
 /* The test runs in a container because pldd does not support tracing
446cf2
    a binary started by the loader iself (as with testrun.sh).  */
446cf2
 
446cf2
@@ -52,25 +85,22 @@ in_str_list (const char *libname, const char *const strlist[])
446cf2
 static int
446cf2
 do_test (void)
446cf2
 {
446cf2
-  /* Create a copy of current test to check with pldd.  */
446cf2
-  struct support_subprocess target = support_subprocess (target_process, NULL);
446cf2
-
446cf2
-  /* Run 'pldd' on test subprocess.  */
446cf2
-  struct support_capture_subprocess pldd;
446cf2
+  /* Check if our subprocess can be debugged with ptrace.  */
446cf2
   {
446cf2
-    /* Three digits per byte plus null terminator.  */
446cf2
-    char pid[3 * sizeof (uint32_t) + 1];
446cf2
-    snprintf (pid, array_length (pid), "%d", target.pid);
446cf2
-
446cf2
-    char *prog = xasprintf ("%s/pldd", support_bindir_prefix);
446cf2
-
446cf2
-    pldd = support_capture_subprogram (prog,
446cf2
-      (char *const []) { (char *) prog, pid, NULL });
446cf2
+    int ptrace_scope = support_ptrace_scope ();
446cf2
+    if (ptrace_scope >= 2)
446cf2
+      FAIL_UNSUPPORTED ("/proc/sys/kernel/yama/ptrace_scope >= 2");
446cf2
+  }
446cf2
 
446cf2
-    support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout);
446cf2
+  pid_t *target_pid_ptr = (pid_t *) xmmap (NULL, sizeof (pid_t),
446cf2
+					   PROT_READ | PROT_WRITE,
446cf2
+					   MAP_SHARED | MAP_ANONYMOUS, -1);
446cf2
 
446cf2
-    free (prog);
446cf2
-  }
446cf2
+  /* Run 'pldd' on test subprocess which will be created in pldd_process.
446cf2
+     The pid of the subprocess will be written to target_pid_ptr.  */
446cf2
+  struct support_capture_subprocess pldd;
446cf2
+  pldd = support_capture_subprocess (pldd_process, target_pid_ptr);
446cf2
+  support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout);
446cf2
 
446cf2
   /* Check 'pldd' output.  The test is expected to be linked against only
446cf2
      loader and libc.  */
446cf2
@@ -85,15 +115,15 @@ do_test (void)
446cf2
     /* First line is in the form of <pid>: <full path of executable>  */
446cf2
     TEST_COMPARE (fscanf (out, "%u: " STRINPUT (512), &pid, buffer), 2);
446cf2
 
446cf2
-    TEST_COMPARE (pid, target.pid);
446cf2
+    TEST_COMPARE (pid, *target_pid_ptr);
446cf2
     TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0);
446cf2
 
446cf2
     /* It expects only one loader and libc loaded by the program.  */
446cf2
     bool interpreter_found = false, libc_found = false;
446cf2
     while (fgets (buffer, array_length (buffer), out) != NULL)
446cf2
       {
446cf2
-       /* Ignore vDSO.  */
446cf2
-        if (buffer[0] != '/')
446cf2
+	/* Ignore vDSO.  */
446cf2
+	if (buffer[0] != '/')
446cf2
 	  continue;
446cf2
 
446cf2
 	/* Remove newline so baseline (buffer) can compare against the
446cf2
@@ -128,7 +158,9 @@ do_test (void)
446cf2
   }
446cf2
 
446cf2
   support_capture_subprocess_free (&pldd);
446cf2
-  support_process_terminate (&target);
446cf2
+  if (kill (*target_pid_ptr, SIGKILL) != 0)
446cf2
+    FAIL_EXIT1 ("Unable to kill target_process: errno=%d=%m\n", errno);
446cf2
+  xmunmap (target_pid_ptr, sizeof (pid_t));
446cf2
 
446cf2
   return 0;
446cf2
 }
446cf2
diff --git a/support/Makefile b/support/Makefile
446cf2
index 65b16299573af1ed..79d03bd6bfe02540 100644
446cf2
--- a/support/Makefile
446cf2
+++ b/support/Makefile
446cf2
@@ -58,6 +58,7 @@ libsupport-routines = \
446cf2
   support_format_hostent \
446cf2
   support_format_netent \
446cf2
   support_isolate_in_subprocess \
446cf2
+  support_ptrace \
446cf2
   support_openpty \
446cf2
   support_paths \
446cf2
   support_quote_blob \
446cf2
diff --git a/support/support_ptrace.c b/support/support_ptrace.c
446cf2
new file mode 100644
446cf2
index 0000000000000000..616b08cff33022ef
446cf2
--- /dev/null
446cf2
+++ b/support/support_ptrace.c
446cf2
@@ -0,0 +1,44 @@
446cf2
+/* Support functions handling ptrace_scope.
446cf2
+   Copyright (C) 2019 Free Software Foundation, Inc.
446cf2
+   This file is part of the GNU C Library.
446cf2
+
446cf2
+   The GNU C Library is free software; you can redistribute it and/or
446cf2
+   modify it under the terms of the GNU Lesser General Public
446cf2
+   License as published by the Free Software Foundation; either
446cf2
+   version 2.1 of the License, or (at your option) any later version.
446cf2
+
446cf2
+   The GNU C Library is distributed in the hope that it will be useful,
446cf2
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
446cf2
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
446cf2
+   Lesser General Public License for more details.
446cf2
+
446cf2
+   You should have received a copy of the GNU Lesser General Public
446cf2
+   License along with the GNU C Library; if not, see
446cf2
+   <https://www.gnu.org/licenses/>.  */
446cf2
+
446cf2
+#include <support/check.h>
446cf2
+#include <support/xstdio.h>
446cf2
+#include <support/xptrace.h>
446cf2
+#include <sys/prctl.h>
446cf2
+
446cf2
+int
446cf2
+support_ptrace_scope (void)
446cf2
+{
446cf2
+  int ptrace_scope = -1;
446cf2
+
446cf2
+#ifdef __linux__
446cf2
+  /* YAMA may be not enabled.  Otherwise it contains a value from 0 to 3:
446cf2
+     - 0 classic ptrace permissions
446cf2
+     - 1 restricted ptrace
446cf2
+     - 2 admin-only attach
446cf2
+     - 3 no attach  */
446cf2
+  FILE *f = fopen ("/proc/sys/kernel/yama/ptrace_scope", "r");
446cf2
+  if (f != NULL)
446cf2
+    {
446cf2
+      TEST_COMPARE (fscanf (f, "%d", &ptrace_scope), 1);
446cf2
+      xfclose (f);
446cf2
+    }
446cf2
+#endif
446cf2
+
446cf2
+  return ptrace_scope;
446cf2
+}
446cf2
diff --git a/support/xptrace.h b/support/xptrace.h
446cf2
new file mode 100644
446cf2
index 0000000000000000..7af892680578fffd
446cf2
--- /dev/null
446cf2
+++ b/support/xptrace.h
446cf2
@@ -0,0 +1,32 @@
446cf2
+/* Support functions handling ptrace_scope.
446cf2
+   Copyright (C) 2019 Free Software Foundation, Inc.
446cf2
+   This file is part of the GNU C Library.
446cf2
+
446cf2
+   The GNU C Library is free software; you can redistribute it and/or
446cf2
+   modify it under the terms of the GNU Lesser General Public
446cf2
+   License as published by the Free Software Foundation; either
446cf2
+   version 2.1 of the License, or (at your option) any later version.
446cf2
+
446cf2
+   The GNU C Library is distributed in the hope that it will be useful,
446cf2
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
446cf2
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
446cf2
+   Lesser General Public License for more details.
446cf2
+
446cf2
+   You should have received a copy of the GNU Lesser General Public
446cf2
+   License along with the GNU C Library; if not, see
446cf2
+   <https://www.gnu.org/licenses/>.  */
446cf2
+
446cf2
+#ifndef SUPPORT_PTRACE_H
446cf2
+#define SUPPORT_PTRACE_H
446cf2
+
446cf2
+#include <sys/cdefs.h>
446cf2
+
446cf2
+__BEGIN_DECLS
446cf2
+
446cf2
+/* Return the current YAMA mode set on the machine (0 to 3) or -1
446cf2
+   if YAMA is not supported.  */
446cf2
+int support_ptrace_scope (void);
446cf2
+
446cf2
+__END_DECLS
446cf2
+
446cf2
+#endif