tags:

views:

217

answers:

2

The title says it all. I've known about the jmp instruction for awhile, but it never struck me as being even remotely unsafe. I recently had cause to check the CIL specs and was very surprised to discover jmp is considered unverifiable.

Any explanations would be much appreciated.

A: 

Where are you jumping to? That is why its unverifiable.

dviljoen
I think you need to read the documentation on the CLR's jmp instruction again.
naasking
+2  A: 

Because, unlike a call, callvirt, or calli, where the caller's stack frame would remain on the stack to be seen by future code access security stackwalks triggered (perhaps indirectly) by the callee, a jmp instruction tears down the caller's stack frame prior to transitioning into the callee and is thus invisible to any CAS stackwalks that the callee may trigger.

Edit: I think naasking is right about the answer above being wrong. I now think the difference between (verifiable) tail.call sequences and (unverifiable) jmp sequences may be that a tail call requires pushing the arguments to the call onto the evaluation stack where they can be verified in the normal way, whereas a jmp requires the evaluation stack to be empty and causes the jump-ee to inherit the arguments of the jump-er. There was probably no reason to complicate the verifier to check jmp instructions, but it might be possible to do so under conditions similar to those imposed on tail.call sequences (one of which is that the caller and callee must be in the same assembly, which rules out my CAS guess above, at least up to explicit .Deny( ) calls).

If so, this would be the relevant part of the spec: (Partition III, Section 3.37)

The current arguments are transferred to the destination method.

The evaluation stack must be empty when this instruction is executed. The calling convention, number and type of arguments at the destination address must match that of the current method.

Doug McClean
While reasonable at first blush, this doesn't stand up to closer scrutiny. The .tailcall prefix has roughly the same behaviour, albeit more general, but .tailcall is verifiable. The documentation simply states that .tailcall is ignored when calling from untrusted to trusted code. If this is the reason jmp is unverifiable, I don't see why they wouldn't have just used the same behaviour for jmp.
naasking
Very good point, thanks naasking.
Doug McClean
I think "Rodrigo Kumpera" who posted on the linked blog page has it right: if any of the arguments are by-ref, then you can store a reference to a local then execute a jmp. A control flow analysis is required to ensure this does not occur, albeit a relatively simple one. I'd wager they just didn't want to bother since jmp was added mainly to support C++. The same danger exists for .tailcall, so I'm not sure how that's handled, ie. unverifiable, or .tailcall ignored. I'll have to test it at some point.
naasking