Skip to content

Commit 14a2773

Browse files
Meghana Guptarajatd
authored andcommitted
[CVE-2018-1019] Use after free of JavascriptExceptionObject - Individual
1 parent af07d28 commit 14a2773

File tree

4 files changed

+85
-52
lines changed

4 files changed

+85
-52
lines changed

lib/Runtime/Base/ThreadContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ const Js::PropertyRecord * const ThreadContext::builtInPropertyRecords[] =
7272
};
7373

7474
ThreadContext::RecyclableData::RecyclableData(Recycler *const recycler) :
75+
pendingFinallyException(nullptr),
7576
soErrorObject(nullptr, nullptr, nullptr, true),
7677
oomErrorObject(nullptr, nullptr, nullptr, true),
7778
terminatedErrorObject(nullptr, nullptr, nullptr),
@@ -94,7 +95,6 @@ ThreadContext::ThreadContext(AllocationPolicyManager * allocationPolicyManager,
9495
isThreadBound(false),
9596
hasThrownPendingException(false),
9697
hasBailedOutBitPtr(nullptr),
97-
pendingFinallyException(nullptr),
9898
noScriptScope(false),
9999
heapEnum(nullptr),
100100
threadContextFlags(ThreadContextFlagNoFlag),

lib/Runtime/Base/ThreadContext.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -441,8 +441,6 @@ class ThreadContext sealed :
441441

442442
private:
443443
const Js::PropertyRecord * emptyStringPropertyRecord;
444-
445-
Js::JavascriptExceptionObject * pendingFinallyException;
446444
bool noScriptScope;
447445

448446
#ifdef ENABLE_SCRIPT_DEBUGGING
@@ -557,6 +555,8 @@ class ThreadContext sealed :
557555
Field(Js::TempArenaAllocatorObject *) temporaryArenaAllocators[MaxTemporaryArenaAllocators];
558556
Field(Js::TempGuestArenaAllocatorObject *) temporaryGuestArenaAllocators[MaxTemporaryArenaAllocators];
559557

558+
Field(Js::JavascriptExceptionObject *) pendingFinallyException;
559+
560560
Field(Js::JavascriptExceptionObject *) exceptionObject;
561561
Field(bool) propagateException;
562562

@@ -1292,12 +1292,12 @@ class ThreadContext sealed :
12921292

12931293
void SetPendingFinallyException(Js::JavascriptExceptionObject * exceptionObj)
12941294
{
1295-
pendingFinallyException = exceptionObj;
1295+
recyclableData->pendingFinallyException = exceptionObj;
12961296
}
12971297

12981298
Js::JavascriptExceptionObject * GetPendingFinallyException()
12991299
{
1300-
return pendingFinallyException;
1300+
return recyclableData->pendingFinallyException;
13011301
}
13021302

13031303
Js::EntryPointInfo ** RegisterEquivalentTypeCacheEntryPoint(Js::EntryPointInfo * entryPoint);

lib/Runtime/Language/JavascriptExceptionOperators.cpp

Lines changed: 70 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,17 @@ namespace Js
7272
m_threadContext->SetTryCatchFrameAddr(m_prevTryCatchFrameAddr);
7373
}
7474

75+
JavascriptExceptionOperators::PendingFinallyExceptionStack::PendingFinallyExceptionStack(ScriptContext* scriptContext, Js::JavascriptExceptionObject *exceptionObj)
76+
{
77+
m_threadContext = scriptContext->GetThreadContext();
78+
m_threadContext->SetPendingFinallyException(exceptionObj);
79+
}
80+
81+
JavascriptExceptionOperators::PendingFinallyExceptionStack::~PendingFinallyExceptionStack()
82+
{
83+
m_threadContext->SetPendingFinallyException(nullptr);
84+
}
85+
7586
bool JavascriptExceptionOperators::CrawlStackForWER(Js::ScriptContext& scriptContext)
7687
{
7788
return Js::Configuration::Global.flags.WERExceptionSupport && !scriptContext.GetThreadContext()->HasCatchHandler();
@@ -199,9 +210,11 @@ namespace Js
199210
JavascriptExceptionOperators::DoThrow(exception, scriptContext);
200211
}
201212

202-
scriptContext->GetThreadContext()->SetPendingFinallyException(exception);
203-
void *continuation = amd64_CallWithFakeFrame(finallyAddr, frame, spillSize, argsSize, exception);
204-
return continuation;
213+
{
214+
Js::JavascriptExceptionOperators::PendingFinallyExceptionStack pendingFinallyExceptionStack(scriptContext, exception);
215+
void *continuation = amd64_CallWithFakeFrame(finallyAddr, frame, spillSize, argsSize, exception);
216+
return continuation;
217+
}
205218
}
206219

207220
scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
@@ -371,13 +384,15 @@ namespace Js
371384
JavascriptExceptionOperators::DoThrow(exception, scriptContext);
372385
}
373386

374-
scriptContext->GetThreadContext()->SetPendingFinallyException(exception);
387+
{
388+
Js::JavascriptExceptionOperators::PendingFinallyExceptionStack pendingFinallyExceptionStack(scriptContext, exception);
375389
#if defined(_M_ARM)
376-
void * finallyContinuation = arm_CallEhFrame(finallyAddr, framePtr, localsPtr, argsSize);
390+
void * finallyContinuation = arm_CallEhFrame(finallyAddr, framePtr, localsPtr, argsSize);
377391
#elif defined(_M_ARM64)
378-
void * finallyContinuation = arm64_CallEhFrame(finallyAddr, framePtr, localsPtr, argsSize);
392+
void * finallyContinuation = arm64_CallEhFrame(finallyAddr, framePtr, localsPtr, argsSize);
379393
#endif
380-
return finallyContinuation;
394+
return finallyContinuation;
395+
}
381396
}
382397

383398
scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);
@@ -699,60 +714,68 @@ namespace Js
699714
JavascriptExceptionOperators::DoThrow(pExceptionObject, scriptContext);
700715
}
701716

702-
scriptContext->GetThreadContext()->SetPendingFinallyException(pExceptionObject);
717+
{
718+
Js::JavascriptExceptionOperators::PendingFinallyExceptionStack pendingFinallyExceptionStack(scriptContext, pExceptionObject);
703719

704-
void* newContinuationAddr = NULL;
720+
if (!tryAddr)
721+
{
722+
// Bug in compiler optimizer: dtor is not called, it is a compiler bug
723+
// The compiler thinks the asm cannot throw, so add an explicit throw to generate dtor calls
724+
Js::Throw::InternalError();
725+
}
726+
void* newContinuationAddr = NULL;
705727
#ifdef _M_IX86
706-
void *savedEsp;
728+
void *savedEsp;
707729

708-
__asm
709-
{
710-
// Save and restore the callee-saved registers around the call.
711-
// TODO: track register kills by region and generate per-region prologs and epilogs
712-
push esi
713-
push edi
714-
push ebx
730+
__asm
731+
{
732+
// Save and restore the callee-saved registers around the call.
733+
// TODO: track register kills by region and generate per-region prologs and epilogs
734+
push esi
735+
push edi
736+
push ebx
715737

716-
// 8-byte align frame to improve floating point perf of our JIT'd code.
717-
// Save ESP
718-
mov ecx, esp
719-
mov savedEsp, ecx
720-
and esp, -8
738+
// 8-byte align frame to improve floating point perf of our JIT'd code.
739+
// Save ESP
740+
mov ecx, esp
741+
mov savedEsp, ecx
742+
and esp, -8
721743

722-
// Set up the call target
723-
mov eax, handlerAddr
744+
// Set up the call target
745+
mov eax, handlerAddr
724746

725747
#if 0 && defined(_CONTROL_FLOW_GUARD)
726-
// verify that the call target is valid
727-
mov ebx, eax; save call target
728-
mov ecx, eax
729-
call[__guard_check_icall_fptr]
730-
mov eax, ebx; restore call target
748+
// verify that the call target is valid
749+
mov ebx, eax; save call target
750+
mov ecx, eax
751+
call[__guard_check_icall_fptr]
752+
mov eax, ebx; restore call target
731753
#endif
732754

733-
// save the current frame ptr, and adjust the frame to access
734-
// locals in native code.
735-
push ebp
736-
mov ebp, framePtr
737-
call eax
738-
pop ebp
755+
// save the current frame ptr, and adjust the frame to access
756+
// locals in native code.
757+
push ebp
758+
mov ebp, framePtr
759+
call eax
760+
pop ebp
739761

740-
// The native code gives us the address where execution should continue on exit
741-
// from the finally, but only if flow leaves the finally before it completes.
742-
mov newContinuationAddr, eax
762+
// The native code gives us the address where execution should continue on exit
763+
// from the finally, but only if flow leaves the finally before it completes.
764+
mov newContinuationAddr, eax
743765

744-
// Restore ESP
745-
mov ecx, savedEsp
746-
mov esp, ecx
766+
// Restore ESP
767+
mov ecx, savedEsp
768+
mov esp, ecx
747769

748-
pop ebx
749-
pop edi
750-
pop esi
751-
}
770+
pop ebx
771+
pop edi
772+
pop esi
773+
}
752774
#else
753-
AssertMsg(FALSE, "Unsupported native try-finally handler");
775+
AssertMsg(FALSE, "Unsupported native try-finally handler");
754776
#endif
755-
return newContinuationAddr;
777+
return newContinuationAddr;
778+
}
756779
}
757780

758781
scriptContext->GetThreadContext()->SetHasBailedOutBitPtr(nullptr);

lib/Runtime/Language/JavascriptExceptionOperators.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,16 @@ namespace Js
5454
~TryCatchFrameAddrStack();
5555
};
5656

57+
class PendingFinallyExceptionStack
58+
{
59+
private:
60+
ThreadContext* m_threadContext;
61+
62+
public:
63+
PendingFinallyExceptionStack(ScriptContext* scriptContext, Js::JavascriptExceptionObject *exceptionObj);
64+
~PendingFinallyExceptionStack();
65+
};
66+
5767
static void __declspec(noreturn) OP_Throw(Var object, ScriptContext* scriptContext);
5868
static void __declspec(noreturn) Throw(Var object, ScriptContext* scriptContext);
5969
static void __declspec(noreturn) ThrowExceptionObject(Js::JavascriptExceptionObject* exceptionObject, ScriptContext* scriptContext, bool considerPassingToDebugger = false, PVOID returnAddress = NULL, bool resetStack = false);

0 commit comments

Comments
 (0)