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