This fixes a regression in the testsuite since c3653f7f, where four of
the timeout tests fail with "Timeouts suppressed" messages.

The timeouts are being suppressed because the testsuite is erroneously
detecting that a debugger is attached.  This detection mechanism
(adopted from libinput) uses ptrace to test if there is a debugger
parent process that can be attached.  Unfortunately, this is an
unreliable test: Kernel security policies exist to restrict the scope of
ptrace to prevent processes from snooping on one another.[1] This
security policy is set as the default on Ubuntu, and potentially other
Linux distributions.[2]

The Yama documentation suggests, "For software that has defined
application-specific relationships between a debugging process and its
inferior (crash handlers, etc), prctl(PR_SET_PTRACER, pid, ...) can be
used.  An inferior can declare which other process (and its descendents)
are allowed to call PTRACE_ATTACH against it."

The child needs to be synchronized to the client to prevent a race
condition where the child might try to operate before the parent has
finished its prctl call.  This synchronization is done via pipes.

1: 
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=2d514487faf188938a4ee4fb3464eeecfbdcf8eb
2: 
https://wiki.ubuntu.com/SecurityTeam/Roadmap/KernelHardening#ptrace_Protection

Signed-off-by: Bryce Harrington <[email protected]>
---
 tests/test-runner.c | 35 ++++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/tests/test-runner.c b/tests/test-runner.c
index b813b69..11d064e 100644
--- a/tests/test-runner.c
+++ b/tests/test-runner.c
@@ -34,6 +34,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <sys/ptrace.h>
+#include <linux/prctl.h>
 
 #include "test-runner.h"
 
@@ -255,13 +256,33 @@ is_debugger_attached(void)
 {
        int status;
        int rc;
-       pid_t pid = fork();
+       pid_t pid;
+       int pipefd[2];
 
-       if (pid == -1)
+       if (pipe(pipefd) == -1) {
+               perror("pipe");
                return 0;
+       }
+
+       pid = fork();
+       if (pid == -1) {
+               perror("fork");
+               close(pipefd[0]);
+               close(pipefd[1]);
+               return 0;
+       }
 
        if (pid == 0) {
-               pid_t ppid = getppid();
+               char buf;
+               pid_t ppid;
+
+               /* Wait until parent is ready */
+               close(pipefd[1]); /* Close unused write end */
+               while (read(pipefd[0], &buf, 1) > 0);
+               close(pipefd[0]);
+
+               /* Attempt to ptrace the parent */
+               ppid = getppid();
                rc = ptrace(PTRACE_ATTACH, ppid, NULL, NULL);
                if (rc == 0) {
                        waitpid(ppid, NULL, 0);
@@ -273,6 +294,14 @@ is_debugger_attached(void)
                }
                _exit(rc);
        } else {
+               close(pipefd[0]);
+
+               /* Enable child to ptrace the parent process */
+               prctl(PR_SET_PTRACER, pid);
+
+               /* Signal to client that parent is ready */
+               close(pipefd[1]);
+
                waitpid(pid, &status, 0);
                rc = WEXITSTATUS(status);
        }
-- 
1.9.1

_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to