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] arm-linux-tdep.c: Fix a buffer overrun.


Hi,

Attached is a patch to fix a buffer overrun bug in gdb.

This patch fixes two separate problems, but since they are very
closely related, I put all into this patch.

Problem 1
=========

Consider the following on a native arm-none-linux-gnueabi-gdb:

(gdb) attach NNNN
(gdb) gcore

Then gdb segfaults.

It turns out that arm-linux-tdep.c:arm_linux_collect_gregset happens
to have a buffer overrun bug.  Here are the details.

When building gdb, we have the following #include sequence.

/* glibc-ports-2.8/sysdeps/unix/sysv/linux/arm/sys/user.h */
struct user_regs
{
  unsigned long int uregs[18];
};

/* glibc-ports-2.8/sysdeps/unix/sysv/linux/arm/sys/procfs.h */
typedef elf_greg_t elf_gregset_t[(sizeof (struct user_regs) / sizeof(elf_greg_t))];

/* gdb/gregset.h */
typedef elf_gregset_t gdb_gregset_t;

So, after a couple of redirections via typedef, gdb_gregset_t ends up
with 18 elements.

Then gdb/linux-nat.c:linux_nat_do_thread_registers declares:

  gdb_gregset_t gregs;

This GREGS is passed to arm-linux-tdep.c:arm_linux_collect_gregset,
which in turn calls:

  regcache_raw_collect (regcache, ARM_PS_REGNUM,
                        gregs + INT_REGISTER_SIZE * ARM_CPSR_REGNUM);

Since ARM_CPSR_REGNUM is 25, we add 100 to GREGS, which is of void *.
We end up speciying a location beyond the end of GREGS, destroying the
stack.

The patch fixes the problem by replacing ARM_CPSR_REGNUM with newly
introduced ARM_CPSR_GREGNUM in gdb/arm-linux-tdep.c.  The new
ARM_CPSR_GREGNUM is defined to be 16, and that matches the index that
GLIBC uses.

Problem 2
=========

Consider generating a core with:

int
main (void)
{
  return 1 / 0;
}

and loading the core file with arm-none-linux-gnueabi-gdb.

"info reg" shows a bogus value for CPSR register.

It turns out that GDB looks at a wrong location in the register data
structure for CPSR.

This patch fixes the problem by replacing ARM_CPSR_REGNUM with
ARM_CPSR_GREGNUM in gdb/arm-linux-nat.c.

After these replacements, nobody uses ARM_CPSR_REGNUM anymore, so the
patch removes ARM_CPSR_REGNUM.

Tested by loading a core file and checking the value of CPSR.  OK to
apply?

Kazu Hirata

2009-04-17  Kazu Hirata  <kazu@codesourcery.com>

	* arm-linux-nat.c (fetch_register, store_register): Use
	ARM_CPSR_GREGNUM instead of ARM_CPSR_REGNUM.
	* arm-linux-tdep.c (arm_linux_supply_gregset,
	arm_linux_collect_gregset): Likewise.
	* arm-linux-tdep.h (ARM_CPSR_GREGNUM): New.
	* arm-tdep.h (ARM_CPSR_REGNUM): Remove.

Index: gdb/arm-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-nat.c,v
retrieving revision 1.40
diff -u -d -p -r1.40 arm-linux-nat.c
--- gdb/arm-linux-nat.c	23 Feb 2009 00:03:48 -0000	1.40
+++ gdb/arm-linux-nat.c	17 Apr 2009 07:08:56 -0000
@@ -246,7 +246,7 @@ fetch_register (struct regcache *regcach
     {
       if (arm_apcs_32)
         regcache_raw_supply (regcache, ARM_PS_REGNUM,
-			     (char *) &regs[ARM_CPSR_REGNUM]);
+			     (char *) &regs[ARM_CPSR_GREGNUM]);
       else
         regcache_raw_supply (regcache, ARM_PS_REGNUM,
 			     (char *) &regs[ARM_PC_REGNUM]);
@@ -286,7 +286,7 @@ fetch_regs (struct regcache *regcache)
 
   if (arm_apcs_32)
     regcache_raw_supply (regcache, ARM_PS_REGNUM,
-			 (char *) &regs[ARM_CPSR_REGNUM]);
+			 (char *) &regs[ARM_CPSR_GREGNUM]);
   else
     regcache_raw_supply (regcache, ARM_PS_REGNUM,
 			 (char *) &regs[ARM_PC_REGNUM]);
@@ -324,7 +324,7 @@ store_register (const struct regcache *r
     regcache_raw_collect (regcache, regno, (char *) &regs[regno]);
   else if (arm_apcs_32 && regno == ARM_PS_REGNUM)
     regcache_raw_collect (regcache, regno,
-			 (char *) &regs[ARM_CPSR_REGNUM]);
+			 (char *) &regs[ARM_CPSR_GREGNUM]);
   else if (!arm_apcs_32 && regno == ARM_PS_REGNUM)
     regcache_raw_collect (regcache, ARM_PC_REGNUM,
 			 (char *) &regs[ARM_PC_REGNUM]);
@@ -362,7 +362,7 @@ store_regs (const struct regcache *regca
 
   if (arm_apcs_32 && regcache_valid_p (regcache, ARM_PS_REGNUM))
     regcache_raw_collect (regcache, ARM_PS_REGNUM,
-			 (char *) &regs[ARM_CPSR_REGNUM]);
+			 (char *) &regs[ARM_CPSR_GREGNUM]);
 
   ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
 
Index: gdb/arm-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-tdep.c,v
retrieving revision 1.66
diff -u -d -p -r1.66 arm-linux-tdep.c
--- gdb/arm-linux-tdep.c	22 Feb 2009 01:02:17 -0000	1.66
+++ gdb/arm-linux-tdep.c	17 Apr 2009 07:08:56 -0000
@@ -382,7 +382,7 @@ arm_linux_supply_gregset (const struct r
     {
       if (arm_apcs_32)
 	regcache_raw_supply (regcache, ARM_PS_REGNUM,
-			     gregs + INT_REGISTER_SIZE * ARM_CPSR_REGNUM);
+			     gregs + INT_REGISTER_SIZE * ARM_CPSR_GREGNUM);
       else
 	regcache_raw_supply (regcache, ARM_PS_REGNUM,
 			     gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM);
@@ -416,7 +416,7 @@ arm_linux_collect_gregset (const struct 
     {
       if (arm_apcs_32)
 	regcache_raw_collect (regcache, ARM_PS_REGNUM,
-			      gregs + INT_REGISTER_SIZE * ARM_CPSR_REGNUM);
+			      gregs + INT_REGISTER_SIZE * ARM_CPSR_GREGNUM);
       else
 	regcache_raw_collect (regcache, ARM_PS_REGNUM,
 			      gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM);
Index: gdb/arm-linux-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-tdep.h,v
retrieving revision 1.6
diff -u -d -p -r1.6 arm-linux-tdep.h
--- gdb/arm-linux-tdep.h	3 Jan 2009 05:57:50 -0000	1.6
+++ gdb/arm-linux-tdep.h	17 Apr 2009 07:08:56 -0000
@@ -24,6 +24,9 @@ struct regcache;
 				+ 2 * INT_REGISTER_SIZE \
 				+ 8 + INT_REGISTER_SIZE)
 
+/* The index to access CSPR in user_regs defined in GLIBC.  */
+#define ARM_CPSR_GREGNUM 16
+
 /* Support for register format used by the NWFPE FPA emulator.  Each
    register takes three words, where either the first one, two, or
    three hold a single, double, or extended precision value (depending
Index: gdb/arm-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.h,v
retrieving revision 1.33
diff -u -d -p -r1.33 arm-tdep.h
--- gdb/arm-tdep.h	3 Jan 2009 05:57:50 -0000	1.33
+++ gdb/arm-tdep.h	17 Apr 2009 07:08:56 -0000
@@ -38,7 +38,6 @@ enum gdb_regnum {
   ARM_F7_REGNUM = 23, 		/* last floating point register */
   ARM_FPS_REGNUM = 24,		/* floating point status register */
   ARM_PS_REGNUM = 25,		/* Contains processor status */
-  ARM_CPSR_REGNUM = ARM_PS_REGNUM,
   ARM_WR0_REGNUM,		/* WMMX data registers.  */
   ARM_WR15_REGNUM = ARM_WR0_REGNUM + 15,
   ARM_WC0_REGNUM,		/* WMMX control registers.  */


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