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