diff options
author | Yao Qi <yao.qi@linaro.org> | 2015-11-18 11:49:32 +0000 |
---|---|---|
committer | Yao Qi <yao.qi@linaro.org> | 2015-11-18 11:49:55 +0000 |
commit | 0735fdddbc086291f6d2357e8fa57e5df6095e89 (patch) | |
tree | 6a3547a34749155d60def0ed0d631ed193619e89 /gdb/aarch64-tdep.c | |
parent | 4978e369fb75a8b7756bf4201668b2a9d9556286 (diff) | |
download | gdb-0735fdddbc086291f6d2357e8fa57e5df6095e89.zip gdb-0735fdddbc086291f6d2357e8fa57e5df6095e89.tar.gz gdb-0735fdddbc086291f6d2357e8fa57e5df6095e89.tar.bz2 |
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.
Diffstat (limited to 'gdb/aarch64-tdep.c')
-rw-r--r-- | gdb/aarch64-tdep.c | 17 |
1 files changed, 13 insertions, 4 deletions
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index de045e6..de85cb0 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -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 |