From e03b3e30160ac5846b246931634962ce6bd1db83 Mon Sep 17 00:00:00 2001 From: Derek Morris Date: Mon, 10 Sep 2018 13:24:58 -0700 Subject: [PATCH] [CVE-2018-8315] Add guards for speculation on non-jit operations --- lib/Runtime/Language/JavascriptOperators.cpp | 1 + lib/Runtime/Library/JavascriptFunction.cpp | 17 +++++++++++++++++ lib/Runtime/Library/JavascriptFunction.h | 2 ++ lib/Runtime/Library/JavascriptString.cpp | 10 +++++++++- lib/Runtime/Library/amd64/JavascriptFunctionA.S | 7 +++++++ .../Library/amd64/JavascriptFunctionA.asm | 7 +++++++ .../Library/arm64/arm64_CallFunction.asm | 6 ++++++ 7 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/Runtime/Language/JavascriptOperators.cpp b/lib/Runtime/Language/JavascriptOperators.cpp index 53831e28cef..e210e933e90 100644 --- a/lib/Runtime/Language/JavascriptOperators.cpp +++ b/lib/Runtime/Language/JavascriptOperators.cpp @@ -3809,6 +3809,7 @@ using namespace Js; Var JavascriptOperators::OP_GetElementI(Var instance, Var index, ScriptContext* scriptContext) { + instance = BreakSpeculation(instance); if (TaggedInt::Is(index)) { return GetElementIIntIndex(instance, index, scriptContext); diff --git a/lib/Runtime/Library/JavascriptFunction.cpp b/lib/Runtime/Library/JavascriptFunction.cpp index e2244a74567..4161c86f12f 100644 --- a/lib/Runtime/Library/JavascriptFunction.cpp +++ b/lib/Runtime/Library/JavascriptFunction.cpp @@ -1155,6 +1155,18 @@ using namespace Js; template Var JavascriptFunction::CallFunction(RecyclableObject* function, JavascriptMethod entryPoint, Arguments args, bool useLargeArgCount); #if _M_IX86 + extern "C" Var BreakSpeculation(Var passthrough) + { + Var result = nullptr; + __asm + { + mov ecx, passthrough; + cmp ecx, ecx; + cmove eax, ecx; + mov result, eax; + } + return result; + } #ifdef ASMJS_PLAT template <> int JavascriptFunction::CallAsmJsFunction(RecyclableObject * function, JavascriptMethod entryPoint, Var * argv, uint argsSize, byte* reg) { @@ -1350,6 +1362,11 @@ void __cdecl _alloca_probe_16() extern Var arm_CallFunction(JavascriptFunction* function, CallInfo info, uint argCount, Var* values, JavascriptMethod entryPoint); } + extern "C" Var BreakSpeculation(Var passthrough) + { + return passthrough; + } + template Var JavascriptFunction::CallFunction(RecyclableObject* function, JavascriptMethod entryPoint, Arguments args, bool useLargeArgCount) { diff --git a/lib/Runtime/Library/JavascriptFunction.h b/lib/Runtime/Library/JavascriptFunction.h index ac049f0e11a..44e23b89f37 100644 --- a/lib/Runtime/Library/JavascriptFunction.h +++ b/lib/Runtime/Library/JavascriptFunction.h @@ -34,6 +34,8 @@ namespace Js extern "C" Var amd64_CallFunction(RecyclableObject *function, JavascriptMethod entryPoint, CallInfo callInfo, uint argc, Var *argv); #endif + extern "C" Var BreakSpeculation(Var passthroughObject); + class JavascriptFunction : public DynamicObject { private: diff --git a/lib/Runtime/Library/JavascriptString.cpp b/lib/Runtime/Library/JavascriptString.cpp index 7d55a97ecee..ec2ea3c5caa 100644 --- a/lib/Runtime/Library/JavascriptString.cpp +++ b/lib/Runtime/Library/JavascriptString.cpp @@ -747,6 +747,7 @@ namespace Js Var value; if (pThis->GetItemAt(idxPosition, &value)) { + value = BreakSpeculation(value); return value; } else @@ -795,7 +796,7 @@ namespace Js return scriptContext->GetLibrary()->GetNaN(); } - return TaggedInt::ToVarUnchecked(pThis->GetItem(idxPosition)); + return BreakSpeculation(TaggedInt::ToVarUnchecked(pThis->GetItem(idxPosition))); } Var JavascriptString::EntryCodePointAt(RecyclableObject* function, CallInfo callInfo, ...) @@ -1849,6 +1850,9 @@ namespace Js { idxEnd = idxStart; } + + pThis = (JavascriptString*)BreakSpeculation(pThis); + return SubstringCore(pThis, idxStart, idxEnd - idxStart, scriptContext); } @@ -1968,6 +1972,8 @@ namespace Js return pThis; } + pThis = (JavascriptString*)BreakSpeculation(pThis); + return SubstringCore(pThis, idxStart, idxEnd - idxStart, scriptContext); } @@ -2024,6 +2030,8 @@ namespace Js return pThis; } + pThis = (JavascriptString*)BreakSpeculation(pThis); + Assert(0 <= idxStart && idxStart <= idxEnd && idxEnd <= len); return SubstringCore(pThis, idxStart, idxEnd - idxStart, scriptContext); } diff --git a/lib/Runtime/Library/amd64/JavascriptFunctionA.S b/lib/Runtime/Library/amd64/JavascriptFunctionA.S index b5f5ef3093f..40679d9f9cb 100644 --- a/lib/Runtime/Library/amd64/JavascriptFunctionA.S +++ b/lib/Runtime/Library/amd64/JavascriptFunctionA.S @@ -235,3 +235,10 @@ NESTED_ENTRY _ZN2Js18JavascriptFunction24DeferredDeserializeThunkEPNS_16Recyclab jmp rax NESTED_END _ZN2Js18JavascriptFunction24DeferredDeserializeThunkEPNS_16RecyclableObjectENS_8CallInfoEz, _TEXT + +.balign 16 +NESTED_ENTRY BreakSpeculation, _TEXT, NoHandler + cmp rdi, rdi + cmove rax, rdi + ret +NESTED_END BreakSpeculation, _TEXT diff --git a/lib/Runtime/Library/amd64/JavascriptFunctionA.asm b/lib/Runtime/Library/amd64/JavascriptFunctionA.asm index db033bdbe6d..2fded75e90f 100644 --- a/lib/Runtime/Library/amd64/JavascriptFunctionA.asm +++ b/lib/Runtime/Library/amd64/JavascriptFunctionA.asm @@ -411,5 +411,12 @@ endif rex_jmp_reg rax ?DeferredDeserializeThunk@JavascriptFunction@Js@@SAPEAXPEAVRecyclableObject@2@UCallInfo@2@ZZ ENDP +align 16 +BreakSpeculation PROC + cmp rcx, rcx + cmove rax, rcx + ret +BreakSpeculation ENDP + _TEXT ENDS end diff --git a/lib/Runtime/Library/arm64/arm64_CallFunction.asm b/lib/Runtime/Library/arm64/arm64_CallFunction.asm index 7abc45b0e0d..9a0e39e4749 100644 --- a/lib/Runtime/Library/arm64/arm64_CallFunction.asm +++ b/lib/Runtime/Library/arm64/arm64_CallFunction.asm @@ -96,4 +96,10 @@ CopyLoop NESTED_END + NESTED_ENTRY BreakSpeculation + cmp x0, x0 + cseleq x0, x0, x0 + ret + NESTED_END + END