PR gdb/16188: Verify PTRACE_TRACEME succeeded
authorSergio Durigan Junior <sergiodj@redhat.com>
Tue, 14 Feb 2017 23:27:23 +0000 (18:27 -0500)
committerSergio Durigan Junior <sergiodj@redhat.com>
Mon, 20 Feb 2017 12:48:44 +0000 (07:48 -0500)
This patch fixes PR gdb/16188, which is about the fact that
fork_inferior doesn't verify the return value of the "traceme_fun"
callback.  On most targets, this callback is actually a wrapper to a
ptrace call that does a PTRACE_TRACEME on the forked GDB process that
will eventually become the inferior.

Thanks to Pedro, this second version of the patch is simpler and more
more logical.  Basically, two helper functions are added:
trace_start_error and trace_start_error_with_name.  The former can be
used when there is a customized error message to be printed to the
user.  The latter works like perror_with_name, so you just need to
pass the function that error'd.

Both helper functions mentioned above do basically the same thing:
print the error message to stderr and call _exit, properly terminating
the forked inferior.

Most of the patch takes care of guarding the necessary system calls
against errors on the "traceme_fun" callbacks.  It is not right to
call error on these situations, so I've replaced these calls with the
proper helper function call.

Regression-tested on BuildBot.

Thanks,

gdb/ChangeLog:
2017-02-20  Sergio Durigan Junior  <sergiodj@redhat.com>
    Pedro Alves  <palves@redhat.com>

PR gdb/16188
* darwin-nat.c (darwin_ptrace_me): Check if calls to system
calls succeeded.
* fork-child.c (trace_start_error): New function.
(trace_start_error_with_name): Likewise.
* gnu-nat.c (gnu_ptrace_me): Check if call to PTRACE succeeded.
* inf-ptrace.c (inf_ptrace_me): Likewise.
* inferior.h (trace_start_error): New prototype.
(trace_start_error_with_name): Likewise.

gdb/ChangeLog
gdb/darwin-nat.c
gdb/fork-child.c
gdb/gnu-nat.c
gdb/inf-ptrace.c
gdb/inferior.h

index 4727433d048582370641ac77e4c685b373c12791..cf68c7e78c065ca78c3951e1000d0ee09bb65938 100644 (file)
@@ -1,3 +1,16 @@
+2017-02-20  Sergio Durigan Junior  <sergiodj@redhat.com>
+           Pedro Alves  <palves@redhat.com>
+
+       PR gdb/16188
+       * darwin-nat.c (darwin_ptrace_me): Check if calls to system
+       calls succeeded.
+       * fork-child.c (trace_start_error): New function.
+       (trace_start_error_with_name): Likewise.
+       * gnu-nat.c (gnu_ptrace_me): Check if call to PTRACE succeeded.
+       * inf-ptrace.c (inf_ptrace_me): Likewise.
+       * inferior.h (trace_start_error): New prototype.
+       (trace_start_error_with_name): Likewise.
+
 2017-02-15  Sergio Durigan Junior  <sergiodj@redhat.com>
 
        PR gdb/21164
index 8c5e8a0b1fd3859951c7464febb811d51df5f815..edee1be85898f632c83126e2a6a9cb7cabe26201 100644 (file)
@@ -1729,22 +1729,28 @@ darwin_ptrace_me (void)
   char c;
 
   /* Close write end point.  */
-  close (ptrace_fds[1]);
+  if (close (ptrace_fds[1]) < 0)
+    trace_start_error_with_name ("close");
 
   /* Wait until gdb is ready.  */
   res = read (ptrace_fds[0], &c, 1);
   if (res != 0)
-    error (_("unable to read from pipe, read returned: %d"), res);
-  close (ptrace_fds[0]);
+    trace_start_error (_("unable to read from pipe, read returned: %d"), res);
+
+  if (close (ptrace_fds[0]) < 0)
+    trace_start_error_with_name ("close");
 
   /* Get rid of privileges.  */
-  setegid (getgid ());
+  if (setegid (getgid ()) < 0)
+    trace_start_error_with_name ("setegid");
 
   /* Set TRACEME.  */
-  PTRACE (PT_TRACE_ME, 0, 0, 0);
+  if (PTRACE (PT_TRACE_ME, 0, 0, 0) < 0)
+    trace_start_error_with_name ("PTRACE");
 
   /* Redirect signals to exception port.  */
-  PTRACE (PT_SIGEXC, 0, 0, 0);
+  if (PTRACE (PT_SIGEXC, 0, 0, 0) < 0)
+    trace_start_error_with_name ("PTRACE");
 }
 
 /* Dummy function to be sure fork_inferior uses fork(2) and not vfork(2).  */
index eaa8cb5448ed26c8891f74819d32843cfebc7e6a..f6256fb01ad59fb940fca775d1f5a4d9fa90c3d0 100644 (file)
@@ -109,6 +109,31 @@ escape_bang_in_quoted_argument (const char *shell_file)
   return 0;
 }
 
+/* See inferior.h.  */
+
+void
+trace_start_error (const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start (ap, fmt);
+  fprintf_unfiltered (gdb_stderr, "Could not trace the inferior "
+                                 "process.\nError: ");
+  vfprintf_unfiltered (gdb_stderr, fmt, ap);
+  va_end (args);
+
+  gdb_flush (gdb_stderr);
+  _exit (0177);
+}
+
+/* See inferior.h.  */
+
+void
+trace_start_error_with_name (const char *string)
+{
+  trace_start_error ("%s: %s", string, safe_strerror (errno));
+}
+
 /* Start an inferior Unix child process and sets inferior_ptid to its
    pid.  EXEC_FILE is the file to run.  ALLARGS is a string containing
    the arguments to the program.  ENV is the environment vector to
index 9935dcb65a29ce1292164007498a7948dc16d3e2..7efb3c17b399b792964e594c16b04e3f4a951b35 100644 (file)
@@ -2126,7 +2126,7 @@ gnu_ptrace_me (void)
   struct inf *inf = cur_inf ();
   inf_debug (inf, "tracing self");
   if (ptrace (PTRACE_TRACEME) != 0)
-    error (_("ptrace (PTRACE_TRACEME) failed!"));
+    trace_start_error_with_name ("ptrace");
 }
 
 static void
index f61bfe7d64be5242dc50199c68e13986154ffeda..215787425f8818b42f089a4270a2b30e15b7ae86 100644 (file)
@@ -79,7 +79,8 @@ static void
 inf_ptrace_me (void)
 {
   /* "Trace me, Dr. Memory!"  */
-  ptrace (PT_TRACE_ME, 0, (PTRACE_TYPE_ARG3)0, 0);
+  if (ptrace (PT_TRACE_ME, 0, (PTRACE_TYPE_ARG3) 0, 0) < 0)
+    trace_start_error_with_name ("ptrace");
 }
 
 /* Start a new inferior Unix child process.  EXEC_FILE is the file to
index 258cc29157205f9cfc57bcccb787c08e3af24001..7c0ddf37f1e0bdea33833916fd2718ce3eb3076b 100644 (file)
@@ -132,6 +132,20 @@ extern void child_terminal_init_with_pgrp (int pgrp);
 
 /* From fork-child.c */
 
+/* Report an error that happened when starting to trace the inferior
+   (i.e., when the "traceme_fun" callback is called on fork_inferior)
+   and bail out.  This function does not return.  */
+
+extern void trace_start_error (const char *fmt, ...)
+  ATTRIBUTE_NORETURN;
+
+/* Like "trace_start_error", but the error message is constructed by
+   combining STRING with the system error message for errno.  This
+   function does not return.  */
+
+extern void trace_start_error_with_name (const char *string)
+  ATTRIBUTE_NORETURN;
+
 extern int fork_inferior (char *, char *, char **,
                          void (*)(void),
                          void (*)(int), void (*)(void), char *,