This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH PR gdb/15236] gdbserver write to linux memory with zero length corrupts stack


PROBLEM:

The function linux_write_memory () in linux-low.c allocates a buffer on
the stack to hold a copy of the data to be written.

  register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *)
    alloca (count * sizeof (PTRACE_XFER_TYPE));

"count" is the number of bytes to be written, rounded up to the nearest
multiple of sizeof (PTRACE_XFER_TYPE) and allowing for not being an
aligned address. The function later uses 

  buffer[0] = ptrace (PTRACE_PEEKTEXT, pid,
                      (PTRACE_ARG3_TYPE) (uintptr_t) addr, 0);

The problem is that this function can be called to write zero bytes on
an aligned address, for example when receiving an X packet of length 0
(used to test if 8-bit write is supported). Under these circumstances,
count can be zero.

Since in this case, buffer[0] may never have been allocated, the stack
is corrupted and gdbserver may crash.

Demonstrated with the port of GDB 7.5.1 for the Synopsys
arc-linux-uclibc- target, currently under development at:

        https://github.com/foss-for-synopsys-dwc-arc-processors/gdb

(to be submitted to the FSF in due course).

SOLUTION:

Writing zero bytes should always succeed. The patch below returns
successfully early if the length is zero, so avoiding the stack
corruption.

Verified on the ARC GDB 7.5.1 port.

CHANGELOG ENTRY:

2013-03-06  Jeremy Bennett  <jeremy.bennett@embecosm.com> 

	PR gdb/15236
	* linux-low.c (linux_write_memory): Return early success if len is
	zero.

PATCH:

I'm working from a git mirror and have produced this using git diff.
Advice on how to do this properly appreciated!

diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 7b79cd1..450e2db 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,9 @@
+2013-03-06  Jeremy Bennett  <jeremy.bennett@embecosm.com>
+
+	PR gdb/15236
+	* linux-low.c (linux_write_memory): Return early success if len is
+	zero.
+
 2012-04-29  Yao Qi  <yao@codesourcery.com>
 
 	* server.h: Move some code to ...
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index bbb0693..8e576bd 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -4421,7 +4421,14 @@ linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
 
 /* Copy LEN bytes of data from debugger memory at MYADDR to inferior's
    memory at MEMADDR.  On failure (cannot write to the inferior)
-   returns the value of errno.  */
+   returns the value of errno.
+
+   6-Mar-13, Jeremy Bennett: [PR gdb/15236] This function can be called with
+   length 0 (for example with a zero length X packet). If memaddr is aligned
+   to sizeof (PTRACE_XFER_TYPE), then count will be zero and nothing may be
+   allocated for buffer (architecture dependent). The function must return
+   early in this circumstance, to avoid stack corruption when assigning
+   to buffer[0]. */
 
 static int
 linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
@@ -4440,6 +4447,10 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
 
   int pid = lwpid_of (get_thread_lwp (current_inferior));
 
+  if (0 == len) {
+    return 0;			/* Zero length write always succeeds. */
+  }
+
   if (debug_threads)
     {
       /* Dump up to four bytes.  */


Best wishes,

Jeremy

-- 
Tel:      +44 (1590) 610184
Cell:     +44 (7970) 676050
SkypeID: jeremybennett
Email:   jeremy.bennett@embecosm.com
Web:     www.embecosm.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]