From:  Yuan Pinghai <pinghaiyuan@gmail.com>
Date:  23 Mar 2017 11:06:42 Hong Kong Time
Newsgroup:  news.mozilla.org/mozilla.dev.tech.js-engine.internals
Subject:  

Re: How to implement the security scheme that prevents the RET instructions from being misused

NNTP-Posting-Host:  63.245.214.181

Thank you Pierron!

I think i should make my situation clearer. I need your patient.

-----------------------------An Instance of JitCode before and after
protection----------------------
Suppose the original Jitcode is looked as the following:

#begin jitcode
[Codegen]  ******
[Codegen]  ******
[Codegen]  ret
#end jitcode

My scheme tries to protect only valid (aligned) RET instructions. (By the
way, this scheme is only a part of my whole security scheme.) The JitCode
would be like the following after enforcing the protection.

#begin jitcode
[Codegen] xorl       $cookie, (%rsp)
[Codegen] *****
[Codegen] ******
[Codegen] xorl       $cookie, (%rsp)
[Codegen] ret
#end jitcode

I use XOR instructions to encrypt and decrypt the return-address. In this
way, the RET instructions cannot be used for ROP attacks. I intend to
protect all RET instructions of JitCodes (exclude all stubs) , so
baseline'd code and ion'ed code would be hardened in this fashion.
----------------------------------------end-----------------------------------------------------


----------------------------------------Challenges-----------------------------------------------------

The key point is to ensure that the encrypting and decrypting operations
are paired with the same cookie value. Otherwise, the program (i.e. the js
shell) would be crashed because it will use a encrypted return-address.
However, making them paired is a big challenge as the control flow
sometimes exits the JitCode in the middle rather than at the end by
executing the tailed RET instruction.


An good instance occurs when osring from baseline'd code to ion'ed code;
the control-flow transition is implemented by the function
DoWarmUpCounterFallback. In this instance, the return-address (an address
within the EnterBaseJit Stub) of baseline'ed code is encrypted with a
cookie, suppose 0x11223344. However, this return-address will also be used
by Ion'ed code for returning, besides encrypting and decrypting it with
another cookie. Therefore, i have to make the return address clean by
decrypting it with  0x11223344 before transition. I do this work at the end
of function DoWarmUpCounterFallback.

---------------------------------------end---------------------------------------------

----Maybe to prototype it, it would be easier to create some reserved
memory which is used as a second stack space which only contains the
cookies?
----You could store them as part of the JSContext*, and fetch the one
corresponding to the top of the stack.

It's a good tip. I think we can reserve memory to store a RB-tree to record
the beginning and end of each JitCode; and add a new field in JitCode to
store the cookie.  With this tree, we can retrieve the correct JitCode
instance according to a code address (e.g. an address interrupted for
bailing-out), and then get the cookie for decryption. In this way,  no need
to modify the the JitFramLayout structures. This scheme is simple and also
applicable for WebAssembly / Asm.js.

My current implementation applies a trick. I use a single cookie which is
the highest bit of address value. So, my cookie is 0x80000000 and
0x8000000000000000 in x86 and x64 platforms, receptively.  In this way, by
only examining the return-address, we can decide whether it is encrypted or
not; and we can decrypt it simply by clear the highest bit.


-----What are you issues with bailouts and exceptions?  They are basically
reading a register dump from the stack to build a MachineState (structure
of pointers to each register spilled location if any) and then -----unwind
the frame and in case of a bailout replace it by the one created by
Baseline.

I found it is hard for me to pair the encrypting and decrypting operations
when bailing out mechanism is activated. The may reason is that, to be
honest, i cannot exactly decide where the control-flow would go in all
cases. As a result, i cannot exactly decide which return-address should be
decrypted in the bailing-out process. I will give more details after i
running the JIT-test cases.


Thank you very much.








2017-03-22 23:44 GMT+08:00 Nicolas B. Pierron :

> On 03/22/2017 04:07 AM, Yuan Pinghai wrote:
>
>> In my current design, the cookie is stored in a new field (named
>> retCookie_) of JitCode, and each JITCODE (representing an instance of
>> JitCode) has its own cookie. In this way, when i need the original
>> return-address, i can recover it by first getting the JITCODE and then
>> fetching the cookie. Now, my problem is how can i get the correct JITCODE
>> with an address (e.g. the interrupted address before bailing-out)?
>>
>
> The CalleeToken of JitFrameLayout frames holds either a JSFunction or a
> JSScript which contains a pointer to the Baseline and Ion structure
> containing references to the JitCode.
>
> When a JitCode is invalidated (Ion), the JitCode pointer is written above
> the return address.  JitFrameIterator::ionScript() should do the proper
> work to get the information you are looking for.
>
> Note that JitCode are used for all trampoline code which are created when
> the JitRuntime is created. (see Trampoline-*.cpp files) and these should be
> registered on the Runtime.
>
> Our stack frames are making assumption about the alignment of the stack,
> thus if you add any fields in the CommonFrameLayout, or JitFrameLayout,
> these might cause issue in all code able to produce code, in which case you
> should look for MacroAssembler::call and MacroAssembler::callJit.
>
> WebAssembly / Asm.js are not using any of the Jit frames.  Instead they
> are using the same frame layout as the ABI of the system, with some
> variations around the manipulation of SIMD registers.
>
> Could some body give me a tip? Any suggestions are welcome. I appreciate
>> for the help!
>>
>
> To be honest, our stack frames are not the easiest thing to manipulate.
>
> Maybe to prototype it, it would be easier to create some reserved memory
> which is used as a second stack space which only contains the cookies?
>
> You could store them as part of the JSContext*, and fetch the one
> corresponding to the top of the stack.
>
>
> By the way, i am working on Spidermonkey 45. By honest, i don't think i
>> have enough knowledge on fixing the bailing-out and exception handling
>> mechanisms, i also need suggestions on them.
>>
>
> What are you issues with bailouts and exceptions?  They are basically
> reading a register dump from the stack to build a MachineState (structure
> of pointers to each register spilled location if any) and then unwind the
> frame and in case of a bailout replace it by the one created by Baseline.
>
> What would matter would be to edit the return address, knowing the caller
> & callee, which you should have in both cases with the JitFrameIterator.
>
>
> --
> Nicolas B. Pierron
> _______________________________________________
> dev-tech-js-engine-internals mailing list
> dev-tech-js-engine-internals@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-tech-js-engine-internals
>