From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12471 invoked by alias); 13 Jun 2017 14:06:07 -0000 Mailing-List: contact elfutils-devel-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Post: List-Help: List-Subscribe: Sender: elfutils-devel-owner@sourceware.org Received: (qmail 12451 invoked by uid 89); 13 Jun 2017 14:06:06 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.99.2 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.7 required=5.0 tests=BAYES_00,KAM_LAZY_DOMAIN_SECURITY,KAM_LOTSOFHASH autolearn=no version=3.3.2 spammy=H*M:222, hotspot, H*F:U*mark, cie X-Spam-Status: No, score=-0.7 required=5.0 tests=BAYES_00,KAM_LAZY_DOMAIN_SECURITY,KAM_LOTSOFHASH autolearn=no version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on sourceware.org X-Spam-Level: X-HELO: gnu.wildebeest.org Received: from wildebeest.demon.nl (HELO gnu.wildebeest.org) (212.238.236.112) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 13 Jun 2017 14:05:59 +0000 Received: from tarox.wildebeest.org (tarox.wildebeest.org [172.31.17.39]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by gnu.wildebeest.org (Postfix) with ESMTPSA id 000C631AC0D2; Tue, 13 Jun 2017 16:06:01 +0200 (CEST) Received: by tarox.wildebeest.org (Postfix, from userid 1000) id E55194021693; Tue, 13 Jun 2017 16:06:01 +0200 (CEST) Message-ID: <1497362761.3755.222.camel@klomp.org> Subject: Re: overflows in Dwfl_Thread_Callbacks::memory_read callback From: Mark Wielaard To: Milian Wolff Cc: elfutils-devel@sourceware.org Date: Tue, 13 Jun 2017 16:15:00 -0000 In-Reply-To: <2117244.RMs6e62TRU@agathebauer> References: <2117244.RMs6e62TRU@agathebauer> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Mailer: Evolution 3.12.11 (3.12.11-22.el7) Mime-Version: 1.0 X-IsSubscribed: yes X-SW-Source: 2017-q2/txt/msg00243.txt.bz2 On Thu, 2017-06-01 at 22:46 +0200, Milian Wolff wrote: > in the perfparser that Ulf wrote, and to which I'm contributing too, we o= ften=20 > see abnormal data being passed to the memory_read callback we define.=20 >=20 > I.e. our callback gets invoked with addr=3D0xFFFFFFFFFFFFFFFF which clear= ly=20 > isn't an expected or valid address. So far we ignored this, as things see= m to=20 > work okayish, but I still suspect something is wrong somewhere... Out of= =20 > interest, I would like to ask if anyone has ever seen something like that? Yes, you sometimes see that some register or location value is zero for some reason, but the expression parser wants to read some memory at an offset from that register. e.g. the SP being zero and trying to read at SP +/- offset to get some value from the stack. Maybe the expression parser should notice this situation and not even invoke the memory_read callback in that case since it is obvious it will fail. > I can easily reproduce this problem. I recorded a session with rr and the= n=20 > investigated what is going on. Below is a "screenshot" of my rr replay=20 > session: >=20 > ~~~~~~~~~~~~~~ >=20 > warning: perfparser/memoryRead: Invalid memory read requested by dwfl=20 > 18446744073709551615 [/home/milian/projects/kdab/rnd/hotspot/3rdparty/ > perfparser/app/perfsymboltable.cpp:150/pid=3D31690] >=20 > Breakpoint 1, memoryRead (dwfl=3D0x1baaa80, addr=3D18446744073709551615,= =20 > result=3D0x7ffe83f69fe8, arg=3D0x7ffe83f6c278) at /home/milian/projects/k= dab/rnd/ > hotspot/3rdparty/perfparser/app/perfsymboltable.cpp:151 > 151 ui->firstGuessedFrame =3D ui->frames.length(); > (rr) up > #1 0x00007fd107ff7345 in expr_eval (state=3Dstate@entry=3D0x1bca010,=20 > frame=3D0x1bcbdf0, ops=3D0x7ffe83f69ff0, nops=3D2,=20 > result=3Dresult@entry=3D0x7ffe83f69fe8, bias=3Dbias@entry=3D1400922298572= 80) > at /home/milian/projects/src/elfutils/libdwfl/frame_unwind.c:501 > 501 if (! process->callbacks->memory_read (process->dwfl, *resu= lt,=20 > result, > (rr) watch -l *result > Hardware watchpoint 2: -location *result > (rr) reverse-continue=20 > Continuing. >=20 > Hardware watchpoint 2: -location *result >=20 > Old value =3D 18446744073709551615 > New value =3D 18446744073709551575 > 0x00007fd107ff72fe in do_pop (stack=3D0x7ffe83f69f20, stack=3D0x7ffe83f69= f20,=20 > val=3D0x7ffe83f69fe8) at /home/milian/projects/src/elfutils/libdwfl/ > frame_unwind.c:139 > 139 *val =3D stack->addrs[--stack->used]; > (rr) print stack->used > $1 =3D 0 > (rr) reverse-step > 139 *val =3D stack->addrs[--stack->used]; > (rr) print stack->used > $2 =3D 1 > (rr) print stack->addrs[0] > $3 =3D 18446744073709551615 > (rr) print stack->addrs[1] > $4 =3D 140535749912192 > (rr) print stack->addrs[0] > $5 =3D 18446744073709551615 > (rr) watch -l stack->addrs[0] > Hardware watchpoint 3: -location stack->addrs[0] > (rr) reverse-conQuit > (rr) del 2 > (rr) reverse-continue=20 > Continuing. >=20 > Hardware watchpoint 3: -location stack->addrs[0] >=20 > Old value =3D 18446744073709551615 > New value =3D 15 > 0x00007fd107ff6e8a in do_push (stack=3D0x7ffe83f69f20, val=3D184467440737= 09551615)=20 > at /home/milian/projects/src/elfutils/libdwfl/frame_unwind.c:127 > 127 stack->addrs[stack->used++] =3D val; > (rr) print val > $6 =3D 18446744073709551615 > (rr) up > #1 0x00007fd107ff7a4f in expr_eval (state=3Dstate@entry=3D0x1bca010,=20 > frame=3D0x1bcbdf0, ops=3D0x7ffe83f69ff0, nops=3D2,=20 > result=3Dresult@entry=3D0x7ffe83f69fe8, bias=3Dbias@entry=3D1400922298572= 80) > at /home/milian/projects/src/elfutils/libdwfl/frame_unwind.c:361 > 361 if (! pop (&val1) || ! push (val1 + op->number)) > (rr) print val1 > $7 =3D 15 > (rr) print op->number > $8 =3D 18446744073709551600 > (rr) watch -l op->number > Hardware watchpoint 4: -location op->number > (rr) del 3 > (rr) reverse-continue=20 > Continuing. >=20 > Hardware watchpoint 4: -location op->number >=20 > Old value =3D 18446744073709551600 > New value =3D 0 > 0x00007fd107fe06e8 in dwarf_frame_register (fs=3D0x1bcbdf0, regno=3Dregno= @entry=3D6,=20 > ops_mem=3Dops_mem@entry=3D0x7ffe83f69ff0, ops=3Dops@entry=3D0x7ffe83f69fd= 8,=20 > nops=3Dnops@entry=3D0x7ffe83f69fe0) > at /home/milian/projects/src/elfutils/libdw/dwarf_frame_register.c:80 > 80 ops_mem[(*nops)++] =3D (Dwarf_Op) { .atom =3D DW_OP_plus_= uconst, > (rr) list > 75 > 76 case reg_offset: > 77 case reg_val_offset: > 78 ops_mem[(*nops)++] =3D (Dwarf_Op) { .atom =3D DW_OP_call_fr= ame_cfa=20 > }; > 79 if (reg->value !=3D 0) > 80 ops_mem[(*nops)++] =3D (Dwarf_Op) { .atom =3D DW_OP_plus_= uconst, > 81 .number =3D reg->value = }; > 82 if (reg->rule =3D=3D reg_val_offset) > 83 /* A value, not a location. */ > 84 ops_mem[(*nops)++] =3D (Dwarf_Op) { .atom =3D DW_OP_stack= _value }; > (rr) print reg->value > $9 =3D -16 > (rr) watch -l reg->value > Hardware watchpoint 5: -location reg->value > (rr) reverse-continue=20 > Continuing. >=20 > Hardware watchpoint 4: -location op->number >=20 > Old value =3D 0 > New value =3D 18446744073709551560 > dwarf_frame_register (fs=3D0x1bcbdf0, regno=3Dregno@entry=3D6,=20 > ops_mem=3Dops_mem@entry=3D0x7ffe83f69ff0, ops=3Dops@entry=3D0x7ffe83f69fd= 8,=20 > nops=3Dnops@entry=3D0x7ffe83f69fe0) > at /home/milian/projects/src/elfutils/libdw/dwarf_frame_register.c:80 > 80 ops_mem[(*nops)++] =3D (Dwarf_Op) { .atom =3D DW_OP_plus_= uconst, > (rr) del 4 > (rr) reverse-continue=20 > Continuing. >=20 > Hardware watchpoint 5: -location reg->value >=20 > Old value =3D -16 > New value =3D 0 > 0x00007fd107fddf17 in execute_cfi (cache=3Dcache@entry=3D0x1bb5b00, cie= =3D0x1b9d100,=20 > state=3Dstate@entry=3D0x7ffe83f69ed0, program=3D, end=3D0x= 7fd108039778=20 > ",", abi_cfi=3Dabi_cfi@entry=3Dfalse, loc=3D21649,=20 > find_pc=3D23177) at /home/milian/projects/src/elfutils/libdw/cfi.c:260 > 260 register_rule (operand, val_offset, offset); > (rr) list > 255 get_uleb128 (operand, program, end); > 256 cfi_assert (program < end); > 257 get_uleb128 (offset, program, end); > 258 offset *=3D cie->data_alignment_factor; > 259 val_offset: > 260 register_rule (operand, val_offset, offset); > 261 continue; > 262 > 263 case DW_CFA_val_offset_sf: > 264 get_uleb128 (operand, program, end); > (rr) print offset > $10 =3D > (rr) print val_offset > No symbol "val_offset" in current context. > (rr) print operand > $11 =3D > (rr) print operand > $12 =3D >=20 > ~~~~~~~~~~~~~~ >=20 > So from the above I notice a couple of... "interesting" behavior: >=20 > - op->number is an unsigned value, but gets the signed value -16 written = to=20 > it, thereby producing the large value 0xFFFFFFFFFFFFFFF0 >=20 > - even if the above would be signed, the expression "15 - 16" is always g= oing=20 > to result in a bogus address >=20 > - has anyone a clue of what may be going wrong here? Is one of our callba= cks=20 > returning wrong values before? Is the DWARF info broken? Is there any kin= d of=20 > DWARF validator or anything like that which I could use here to check? I= =20 > notice that this issue often arises with frames in libc and ld.so. But, s= o=20 > far, I have not come up with a good way to write a MWE that reliably test= s=20 > this behavior... Is there maybe something in the elfutils source code rep= o=20 > that I could use as a basis? I am not following the above trace completely, but what is going on seems to be that we have CFI and want to get a register value. So we call dwarf_frame_register to determine the DWARF expression operations that we need to execute to get the register value. dwarf_frame_register determines that that the register is described by a register offset value rule, so it generates operations saying see an the CFA (DW_OP_call_frame_cfa) plus some offset (DW_OP_plus_uconst) as a value (so read the value from cfa + offset, which is somewhere on the stack). But then the cfa comes out as 15? That is obviously bogus. But I don't really understand how that happened. It should be a value somewhere near the current stack. Then reading 15 - offset (16) clearly fails. Cheers, Mark