Fix use-after-free in gdbserver
authorTom Tromey <tom@tromey.com>
Mon, 30 Jul 2018 01:21:01 +0000 (19:21 -0600)
committerTom Tromey <tom@tromey.com>
Thu, 29 Nov 2018 17:47:42 +0000 (10:47 -0700)
-fsanitize=address pointed out a use-after-free in gdbserver.  In
particular, handle_detach could reference "process" after it was
deleted by detach_inferior.  Avoiding this also necessitated changing
target_ops::join to take a pid rather than a process_info*.

Tested by the buildbot using a few of the gdbserver builders.

gdb/gdbserver/ChangeLog
2018-11-29  Tom Tromey  <tom@tromey.com>

* win32-low.c (win32_join): Take pid, not process.
* target.h (struct target_ops) <join>: Change argument type.
(join_inferior): Change argument name.
* spu-low.c (spu_join): Take pid, not process.
* server.c (handle_detach): Preserve pid before destroying
process.
* lynx-low.c (lynx_join): Take pid, not process.
* linux-low.c (linux_join): Take pid, not process.

gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-low.c
gdb/gdbserver/lynx-low.c
gdb/gdbserver/server.c
gdb/gdbserver/spu-low.c
gdb/gdbserver/target.h
gdb/gdbserver/win32-low.c

index 91a62b6228a9bc7c298701b8fc6ac0967568bd5d..ec4d72f81f8738b9afdbc162fb96d4e01d682157 100644 (file)
@@ -1,3 +1,14 @@
+2018-11-29  Tom Tromey  <tom@tromey.com>
+
+       * win32-low.c (win32_join): Take pid, not process.
+       * target.h (struct target_ops) <join>: Change argument type.
+       (join_inferior): Change argument name.
+       * spu-low.c (spu_join): Take pid, not process.
+       * server.c (handle_detach): Preserve pid before destroying
+       process.
+       * lynx-low.c (lynx_join): Take pid, not process.
+       * linux-low.c (linux_join): Take pid, not process.
+
 2018-11-23  Alan Hayward  <alan.hayward@arm.com>
 
        * linux-aarch64-low.c (aarch64_cannot_store_register): Remove.
index 701f3e863c0a665832549680a22f9bc1c80dd13f..4d849279ca3d3e6199b360b4fb45efeb9991989d 100644 (file)
@@ -1670,12 +1670,12 @@ linux_mourn (struct process_info *process)
 }
 
 static void
-linux_join (process_info *proc)
+linux_join (int pid)
 {
   int status, ret;
 
   do {
-    ret = my_waitpid (proc->pid, &status, 0);
+    ret = my_waitpid (pid, &status, 0);
     if (WIFEXITED (status) || WIFSIGNALED (status))
       break;
   } while (ret != -1 || errno != ECHILD);
index 6c5933bc4705022c4d3b6a8714ea34851bd5ab6d..3bf3588a71b636ba70f23ed74bca063013b1e479 100644 (file)
@@ -562,7 +562,7 @@ lynx_mourn (struct process_info *proc)
 /* Implement the join target_ops method.  */
 
 static void
-lynx_join (process_info *proc)
+lynx_join (int pid)
 {
   /* The PTRACE_DETACH is sufficient to detach from the process.
      So no need to do anything extra.  */
index 4ec3548d64444ac11e5417f4d7b40acb6dcfe27d..a0be0d4f7ea7241c4bde7997614f4534aed27398 100644 (file)
@@ -1255,11 +1255,15 @@ handle_detach (char *own_buf)
 
   fprintf (stderr, "Detaching from process %d\n", process->pid);
   stop_tracing ();
+
+  /* We'll need this after PROCESS has been destroyed.  */
+  int pid = process->pid;
+
   if (detach_inferior (process) != 0)
     write_enn (own_buf);
   else
     {
-      discard_queued_stop_replies (ptid_t (process->pid));
+      discard_queued_stop_replies (ptid_t (pid));
       write_ok (own_buf);
 
       if (extended_protocol || target_running ())
@@ -1269,7 +1273,7 @@ handle_detach (char *own_buf)
             and instead treat this like a normal program exit.  */
          cs.last_status.kind = TARGET_WAITKIND_EXITED;
          cs.last_status.value.integer = 0;
-         cs.last_ptid = ptid_t (process->pid);
+         cs.last_ptid = ptid_t (pid);
 
          current_thread = NULL;
        }
@@ -1281,7 +1285,7 @@ handle_detach (char *own_buf)
          /* If we are attached, then we can exit.  Otherwise, we
             need to hang around doing nothing, until the child is
             gone.  */
-         join_inferior (process);
+         join_inferior (pid);
          exit (0);
        }
     }
index 83a31a203d48b1fe1ce0ed834c97682775530854..239c2126391db46a8f1fea5b8505e32e8170082b 100644 (file)
@@ -362,12 +362,12 @@ spu_mourn (struct process_info *process)
 }
 
 static void
-spu_join (process_info *proc)
+spu_join (int pid)
 {
   int status, ret;
 
   do {
-    ret = waitpid (proc->pid, &status, 0);
+    ret = waitpid (pid, &status, 0);
     if (WIFEXITED (status) || WIFSIGNALED (status))
       break;
   } while (ret != -1 || errno != ECHILD);
index fce54e05adbc3b6509cb2c891a067154cc72cd4f..6f810b6db9eeed64d28cedfc2263edc68532730d 100644 (file)
@@ -103,9 +103,9 @@ struct target_ops
 
   void (*mourn) (struct process_info *proc);
 
-  /* Wait for process PROC to exit.  */
+  /* Wait for process PID to exit.  */
 
-  void (*join) (process_info *proc);
+  void (*join) (int pid);
 
   /* Return 1 iff the thread with process ID PID is alive.  */
 
@@ -530,8 +530,8 @@ int kill_inferior (process_info *proc);
 #define store_inferior_registers(regcache, regno) \
   (*the_target->store_registers) (regcache, regno)
 
-#define join_inferior(proc) \
-  (*the_target->join) (proc)
+#define join_inferior(pid) \
+  (*the_target->join) (pid)
 
 #define target_supports_non_stop() \
   (the_target->supports_non_stop ? (*the_target->supports_non_stop ) () : 0)
index 4aed58d3b8e6e34d1ed8255da2be564a04fe3225..1ad71c7be994656ba90ede22c5ab20d6065f6af8 100644 (file)
@@ -873,9 +873,9 @@ win32_mourn (struct process_info *process)
 /* Implementation of target_ops::join.  */
 
 static void
-win32_join (process_info *proc)
+win32_join (int pid)
 {
-  HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, proc->pid);
+  HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
   if (h != NULL)
     {
       WaitForSingleObject (h, INFINITE);