[#11073] segfault printing instruction sequence for iterator — <noreply@...>

Bugs item #10527, was opened at 2007-05-02 14:42

14 messages 2007/05/02
[#11142] Re: [ ruby-Bugs-10527 ] segfault printing instruction sequence for iterator — Nobuyoshi Nakada <nobu@...> 2007/05/10

Hi,

[#11188] Re: [ ruby-Bugs-10527 ] segfault printing instruction sequence for iterator — Paul Brannan <pbrannan@...> 2007/05/16

On Thu, May 10, 2007 at 04:51:18PM +0900, Nobuyoshi Nakada wrote:

[#11234] Planning to release 1.8.6 errata — Urabe Shyouhei <shyouhei@...>

Hi all.

17 messages 2007/05/25

ruby packer prototype: core dumps ( design review request )

From: "Adam Bozanich" <adam.boz@...>
Date: 2007-05-03 06:30:14 UTC
List: ruby-core #11079
Hello All.

I'm developing a ruby-packer type of thing ( i'll give more details below ),
and have run into a problem where I keep getting core dumps.

I guess I'll lay out the problem area first.

I've isolated the coredump issue to this spot:

    rb_funcall( rb_cModule  ,
                rb_intern("require") , 1 , rb_str_new2("mu/loader") );
    VALUE tmp = rb_funcall( config , rb_intern("to_s") , 0 );

If I switch the order of those calls, the process runs fine ( there's other
issues, which I'm trying to debug.  could be related ).

Stepping through the debugger, the crash fails in rb_rescue2() in the
JUMP_TAG() macro when prot_tag is dereferenced ( it is null ).

This is proving to be a nasty bug to pin down, and I'm just wondering if
anybody has any comments/suggestions about the situation.

Let me give you an outline of what I'm trying to do:

We have a protocol fuzzer built with ruby. One of the features of our
product is that we give the user the option to download a single executable
P.O.C. to re-produce a crash.  Since we're using ( and loving ) ruby, we
need a scheme that will allow us to both give the user that single
executable _and_ protect our I.P.  The first iteration of this project is to
simply embed the scripts into the resulting executable, and override
Kernel.require.  We call the various Init_* functions for extensions, and
eval() the strings when they are needed.  Eventually we're gonna try to use
YARV instructions ( we've even looked into adding an opcode representation
other than SimpledataFormat ).

The sample code is below (no errors -- runs fine).  I'm wondering if the
design is just too naive.  Does anybody see any problems with our general
approach?  I'm sorry if this whole post is a bit vague, i just really don't
know where to start with this one.  If there are any requests for more
information, i'd be happy to answer them.

Thanks,
-Adam

#include<ruby.h>

struct test_resource {
    char path[1024];
    char loaded;
    char * src;
} test_resources[] = {

/* ble.rb */
    { "ble" , 0 ,
"require \"foo\"\n"
"puts Foo.new.inspect\n"
} ,

/* foo.rb */
    { "foo" , 0 ,
"require \"bar\"\n"
"class Foo < Bar\n"
"  hidden_method :baz\n"
"end\n"
} ,

/* bar.rb */
    { "bar" , 0 ,
"class Bar\n"
"  def self.hidden_method(*args)\n"
"    args.each do |meth|\n"
"      define_method(meth) do \n"
"        puts meth\n"
"      end\n"
"    end\n"
"  end\n"
"end"
} ,
    { }
};

static VALUE resource_require_path( VALUE str ) {
    char * path ;
    VALUE binding, ret ;
    struct test_resource * res;

    /* Find the source code */
    path    = StringValueCStr(str);
    for( res = &test_resources[0] ; res->path[0] ; res++ )
        if(!strcmp(res->path,path))
            break;
    if(!res->path[0])
        rb_bug("can't find path %s",res->path);
    if( res->loaded ) return Qtrue;

    /* Evaluate the string */
    binding = rb_const_get(rb_mKernel,rb_intern("TOPLEVEL_BINDING"));
    VALUE argv[4] = {
        rb_str_new2( res->src ) ,
        binding ,
        rb_str_new2( res->path ) ,
        INT2FIX(1)
    };

    ret = rb_funcall2( rb_mKernel , rb_intern("eval") , 4 , argv );
    res->loaded = 1;
    return ret;
}

static VALUE hooked_require( VALUE self , VALUE str ) {
    return resource_require_path( str );
}

/* set the require hook */
static void hook_require() {
    rb_define_global_function( "require" , hooked_require , 1 );
}

int main( int argc , char * argv[] ) {
    ruby_init();
    ruby_script("Test");
    ruby_init_loadpath();
    hook_require();
    resource_require_path( rb_str_new2("ble") );
    return 0;
}

In This Thread

Prev Next