[Mono-dev] Possible bugs in tramp-amd64.c when addresses span 4Gb boundary

Ben Carter benml at saillune.net
Tue Sep 23 10:02:23 UTC 2014


  I've been looking into a bug that I've encountered running Mono on a 
64-bit x86 system - specifically, where the "((code - start) < buf_len)" 
assert in mono_arch_get_static_rgctx_trampoline() fires. This seems to 
be a result of this code:

if ((((guint64)addr) >> 32) == 0)
	buf_len = 16;
	buf_len = 30;

...which assumes that if the destination address is <4Gb then a 32-bit 
jump will be used, which isn't true if the code being generated is more 
than ~2Gb away.

  Looking further into this, I found that this pattern appears elsewhere 
in tramp-amd64.c as well - and may explain another problem I've been 
seeing where trampolines get "randomly" corrupted to point to 
nonsensical addresses.

  Specifically, what I think is happening there is that 
mono_arch_create_specific_trampoline() is creating the trampoline, and 
that at the time of creation the target address is within a 32-bit jump 
from the source, so it generates a regular 32-bit CALL.

  However, mono_arch_patch_callsite() appears to only check for the 
target address being >4Gb when patching, meaning that it can (as far as 
I can see) end up doing a 32-bit InterlockedExchange() that truncates 
the offset in the case where the target is too far away. This would then 
result in what I'm seeing, which is that the trampoline code is 
well-formed by the target of the CALL is non-executable memory with 
nothing in it.

  Does this sound like a reasonable hypothesis? Or is there something 
that I'm missing about how trampolines operate that means that offsets 
of this nature shouldn't occur in the first place?

  Thanks for any ideas or advice!
  Ben Carter - ben at saillune.net

More information about the Mono-devel-list mailing list