Bug #14834

rb_profile_frames SEGV when PC adjusted on IFUNC

Added by kivikakk (Ashe Connor) about 2 years ago. Updated 11 months ago.

Target version:
ruby -v:
ruby 2.6.0dev (2018-06-08 trunk 63606) [x86_64-linux]


Since r62052, we increment ec->cfp->pc by one pointer width (e.g. 8 bytes) in gc_event_hook_body around the EXEC_EVENT_HOOK call.

This becomes a problem when the hook is on an IFUNC: in this case, pc == 0x0, meaning we increment it to a non-zero value during that call.

rb_profile_frames uses the following check to determine if frame info should be recorded:

    if (cfp->iseq && cfp->pc) {

The example here is stackprof, which calls rb_profile_frames in a gc event hook. This will segfault currently, as the above check will pass.

calc_lineno then attempts to calculate the line number:

        size_t pos = (size_t)(pc - iseq->body->iseq_encoded);

This fails for a variety of reasons: iseq_encoded isn't valid because iseq isn't an rb_iseq_t underneath, producing an essentially random value, and pc is 0x8, so we underflow and eventually cause an overrun in succ_index_lookup with a huge pos argument.

We instead only adjust PC if it appears to be a valid pointer in the first place.


pc-treatment.diff (777 Bytes) pc-treatment.diff kivikakk (Ashe Connor), 06/08/2018 05:06 AM

Related issues

Related to Ruby master - Bug #14809: calc_lineno() returns wrong locationClosedshyouhei (Shyouhei Urabe)Actions

Also available in: Atom PDF