

Rewrite your Ruby VM at runtime to hot patch useful features - ice799
http://timetobleed.com/rewrite-your-ruby-vm-at-runtime-to-hot-patch-useful-features/

======
tptacek
I love posts like this, but I think the authors would benefit from a close
read of the Microsoft Detours paper, which runtime patchers have been cribbing
from for the past 5 years or so.

The general Detours approach:

* Disassemble the first N bytes of a target location

* Scoop N bytes worth of opcodes out of the target, and re-host them somewhere heap-allocated

* Replace the N bytes with an absolute jump to a heap-allocated trampoline

* Bounce to your code

* Execute the scooped-up N bytes worth of opcodes

* Jump back to the target

This approach (what the post calls "caller-side trampolines") works well when
your targets are function prologues, and less well when it's an arbitrary
bblock.

We have an implementation in pure Ruby, complete with a pure-Ruby ia32
assembler (which is one of the most useful little pieces of code I've written)
at Timur's Ragweed repository --- google "Ruby ragweed github".

------
bensummers
See also: <http://rentzsch.com/mach_override>

It used to be used quite comprehensively to add non-Apple-sanctioned
functionality to Mac OS X. Hopefully it isn't used much these days.

------
futuremint
I'm probably not thinking this through all the way, but wouldn't a memory
profiler be more straight-forward, and less dangerous in Smalltalk?

I haven't built one myself, but I know that the Seaside framework comes with a
built-in memory profiler.

Doing intercession of messages to objects in Smalltalk isn't trivial, but it
isn't voodoo either. I whipped up a quick method replacement class that swaps
out a database 'save' method's behavior for testing. However, I would imagine
that trying to replace VM primitive calls would lead to some not-so-nice side
effects (maybe... or would it just make the image slower?).

I like Ruby, and I like Smalltalk, but I'm liking Smalltalk much better lately
because the "turtles all the way down" aspect which makes things like a memory
profiler much less "voodoo-y".

~~~
tptacek
Replace "memory profiler" with any other piece of runtime manipulation, and
the point is just as valid with Smalltalk. It is not, in fact, "turtles all
the way down"; eventually you hit the ABI, and that's what this article is
talking about.

------
KirinDave
I am surprised this works. I was under the impression that more modern
implementations write protected the pages that libraries in the initial link
are loaded to. There is really no good reason for them to be writable save for
extremely strange uses such as in this article.

Is this assumption false?

~~~
tptacek
Userland code can't usually modify program text. The kernel can. The kernel
will modify program text on your program's behalf if you own the process you
want to modify. Depending on the OS, that happens via WriteProcessMemory,
ptrace, Mach, or procfs.

~~~
KirinDave
Well in the code Joe posted, he takes the marked pages and calls mprotect on
them so they can be modified. I am surprised he's allowed to do this at all.
Is there ever a legitimate reason to do this in most modern systems?

I mean besides this crazy-like-a-fox twin trampoline system, or for
compromising binaries at runtime maliciously. The days of overlays are long
gone. :)

~~~
tptacek

       int
       main(int argc, char **argv) {
            void *faddr = strxfrm;
            void *paddr = (void*) ((u_int32_t)faddr & 0xfffff000);
    
            if(mprotect(paddr, 4096, PROT_READ|PROT_WRITE|PROT_EXEC) >= 0) {
                    ((u_char *)faddr)[0] = 0xcc;
                    strxfrm("foo", "", 0);
            } else
                    perror("mprotect");
    
            exit(0);
       }
    
       $ ./mp
       Trace/BPT trap
    

The simplest answer to your question that jumps into my head is "relocations",
but I'm always surprised by the everyday craziness of the C runtime and the
Unix ABI, so I'm sure there's a simpler answer.

------
teilo
This is a perfect example of "because I can". Never ever do this for real.

~~~
tptacek
In a dev/test environment, do whatever works best and fastest. If you have the
skillset and toolset to jump right to the ABI to solve a problem, it's pretty
silly to stay in the confines of MRI just out of orthodoxy.

