Fix out of boundary access in pass_in_v

Hi,
I build GDB with -fsanitize=address, and run testsuite.  In
gdb.base/callfuncs.exp, I see the following error,

p t_float_values(0.0,0.0)
=================================================================
==8088==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000cb650 at pc 0x6e195c bp 0x7fff164f9770 sp 0x7fff164f9768
READ of size 16 at 0x6020000cb650 thread T0^
    #0 0x6e195b in regcache_raw_write /home/yao/SourceCode/gnu/gdb/git/gdb/regcache.c:912
    #1 0x6e1e52 in regcache_cooked_write /home/yao/SourceCode/gnu/gdb/git/gdb/regcache.c:945
    #2 0x466d69 in pass_in_v /home/yao/SourceCode/gnu/gdb/git/gdb/aarch64-tdep.c:1101
    #3 0x467512 in pass_in_v_or_stack /home/yao/SourceCode/gnu/gdb/git/gdb/aarch64-tdep.c:1196
    #4 0x467d7d in aarch64_push_dummy_call /home/yao/SourceCode/gnu/gdb/git/gdb/aarch64-tdep.c:1335

The code in pass_in_v read contents from V registers (128 bit), but the
data passed through V registers can be less than 128 bit.  In this case,
float is passed.  So writing V registers contents into contents buff
will cause overflow.  In this patch, we add an array reg[V_REGISTER_SIZE],
which is to hold the contents from V registers, and then copy useful
bits to buf.

gdb:

2015-11-18  Yao Qi  <yao.qi@linaro.org>

	* aarch64-tdep.c (pass_in_v): Add argument len.  Add local array
	reg.  Callers updated.
This commit is contained in:
Yao Qi 2015-11-18 11:49:32 +00:00
parent 4978e369fb
commit 0735fdddbc
2 changed files with 18 additions and 4 deletions

View File

@ -1,3 +1,8 @@
2015-11-18 Yao Qi <yao.qi@linaro.org>
* aarch64-tdep.c (pass_in_v): Add argument len. Add local array
reg. Callers updated.
2015-11-17 Yao Qi <yao.qi@linaro.org>
* infrun.c (resume): Check control.trap_expected only

View File

@ -1034,17 +1034,23 @@ static int
pass_in_v (struct gdbarch *gdbarch,
struct regcache *regcache,
struct aarch64_call_info *info,
const bfd_byte *buf)
int len, const bfd_byte *buf)
{
if (info->nsrn < 8)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int regnum = AARCH64_V0_REGNUM + info->nsrn;
gdb_byte reg[V_REGISTER_SIZE];
info->argnum++;
info->nsrn++;
regcache_cooked_write (regcache, regnum, buf);
memset (reg, 0, sizeof (reg));
/* PCS C.1, the argument is allocated to the least significant
bits of V register. */
memcpy (reg, buf, len);
regcache_cooked_write (regcache, regnum, reg);
if (aarch64_debug)
{
debug_printf ("arg %d in %s\n", info->argnum,
@ -1138,7 +1144,8 @@ pass_in_v_or_stack (struct gdbarch *gdbarch,
struct type *type,
struct value *arg)
{
if (!pass_in_v (gdbarch, regcache, info, value_contents (arg)))
if (!pass_in_v (gdbarch, regcache, info, TYPE_LENGTH (type),
value_contents (arg)))
pass_on_stack (info, type, arg);
}
@ -1263,8 +1270,10 @@ aarch64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct type *target_type =
check_typedef (TYPE_TARGET_TYPE (arg_type));
pass_in_v (gdbarch, regcache, &info, buf);
pass_in_v (gdbarch, regcache, &info,
TYPE_LENGTH (target_type), buf);
pass_in_v (gdbarch, regcache, &info,
TYPE_LENGTH (target_type),
buf + TYPE_LENGTH (target_type));
}
else