This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[patch] arm-linux-tdep.c: Fix a buffer overrun.
- From: kazu at codesourcery dot com (Kazu Hirata)
- To: gdb-patches at sourceware dot org
- Cc: dan at codesourcery dot com
- Date: Fri, 17 Apr 2009 00:11:33 -0700 (PDT)
- Subject: [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 *) ®s[ARM_CPSR_REGNUM]);
+ (char *) ®s[ARM_CPSR_GREGNUM]);
else
regcache_raw_supply (regcache, ARM_PS_REGNUM,
(char *) ®s[ARM_PC_REGNUM]);
@@ -286,7 +286,7 @@ fetch_regs (struct regcache *regcache)
if (arm_apcs_32)
regcache_raw_supply (regcache, ARM_PS_REGNUM,
- (char *) ®s[ARM_CPSR_REGNUM]);
+ (char *) ®s[ARM_CPSR_GREGNUM]);
else
regcache_raw_supply (regcache, ARM_PS_REGNUM,
(char *) ®s[ARM_PC_REGNUM]);
@@ -324,7 +324,7 @@ store_register (const struct regcache *r
regcache_raw_collect (regcache, regno, (char *) ®s[regno]);
else if (arm_apcs_32 && regno == ARM_PS_REGNUM)
regcache_raw_collect (regcache, regno,
- (char *) ®s[ARM_CPSR_REGNUM]);
+ (char *) ®s[ARM_CPSR_GREGNUM]);
else if (!arm_apcs_32 && regno == ARM_PS_REGNUM)
regcache_raw_collect (regcache, ARM_PC_REGNUM,
(char *) ®s[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 *) ®s[ARM_CPSR_REGNUM]);
+ (char *) ®s[ARM_CPSR_GREGNUM]);
ret = ptrace (PTRACE_SETREGS, tid, 0, ®s);
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. */