Skip to content

Commit f022afb

Browse files
aneeshdkrajatd
authored andcommitted
[CVE-2017-0224, CVE-2017-0235] Chakra - JavascriptPromise::AsyncSpawnStep method invocation issue
While invoking then and catch functions on the promise returned by async function we were directly invoking those without checking. Overriding those methods with tagged int can cause wrong method execution.
1 parent 4332106 commit f022afb

6 files changed

Lines changed: 78 additions & 22 deletions

File tree

lib/Runtime/Library/JavascriptLibrary.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6184,7 +6184,7 @@ namespace Js
61846184
return function;
61856185
}
61866186

6187-
JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* JavascriptLibrary::CreatePromiseAsyncSpawnStepArgumentExecutorFunction(JavascriptMethod entryPoint, JavascriptGenerator* generator, Var argument, JavascriptFunction* resolve, JavascriptFunction* reject, bool isReject)
6187+
JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* JavascriptLibrary::CreatePromiseAsyncSpawnStepArgumentExecutorFunction(JavascriptMethod entryPoint, JavascriptGenerator* generator, Var argument, Var resolve, Var reject, bool isReject)
61886188
{
61896189
FunctionInfo* functionInfo = RecyclerNew(this->GetRecycler(), FunctionInfo, entryPoint);
61906190
DynamicType* type = CreateDeferredPrototypeFunctionType(this->inDispatchProfileMode ? ProfileEntryThunk : entryPoint);

lib/Runtime/Library/JavascriptLibrary.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,7 @@ namespace Js
984984
JavascriptExternalFunction* CreateStdCallExternalFunction(StdCallJavascriptMethod entryPointer, PropertyId nameId, void *callbackState);
985985
JavascriptExternalFunction* CreateStdCallExternalFunction(StdCallJavascriptMethod entryPointer, Var nameId, void *callbackState);
986986
JavascriptPromiseAsyncSpawnExecutorFunction* CreatePromiseAsyncSpawnExecutorFunction(JavascriptMethod entryPoint, JavascriptGenerator* generator, Var target);
987-
JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* CreatePromiseAsyncSpawnStepArgumentExecutorFunction(JavascriptMethod entryPoint, JavascriptGenerator* generator, Var argument, JavascriptFunction* resolve = NULL, JavascriptFunction* reject = NULL, bool isReject = false);
987+
JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* CreatePromiseAsyncSpawnStepArgumentExecutorFunction(JavascriptMethod entryPoint, JavascriptGenerator* generator, Var argument, Var resolve = nullptr, Var reject = nullptr, bool isReject = false);
988988
JavascriptPromiseCapabilitiesExecutorFunction* CreatePromiseCapabilitiesExecutorFunction(JavascriptMethod entryPoint, JavascriptPromiseCapability* capability);
989989
JavascriptPromiseResolveOrRejectFunction* CreatePromiseResolveOrRejectFunction(JavascriptMethod entryPoint, JavascriptPromise* promise, bool isReject, JavascriptPromiseResolveOrRejectFunctionAlreadyResolvedWrapper* alreadyResolvedRecord);
990990
JavascriptPromiseReactionTaskFunction* CreatePromiseReactionTaskFunction(JavascriptMethod entryPoint, JavascriptPromiseReaction* reaction, Var argument);

lib/Runtime/Library/JavascriptPromise.cpp

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,8 +1009,8 @@ namespace Js
10091009
JavascriptGenerator* gen = asyncSpawnExecutorFunction->GetGenerator();
10101010
JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* nextFunction = library->CreatePromiseAsyncSpawnStepArgumentExecutorFunction(EntryJavascriptPromiseAsyncSpawnStepNextExecutorFunction, gen, varCallArgs);
10111011

1012-
Assert(JavascriptFunction::Is(resolve) && JavascriptFunction::Is(reject));
1013-
AsyncSpawnStep(nextFunction, gen, JavascriptFunction::FromVar(resolve), JavascriptFunction::FromVar(reject));
1012+
Assert(JavascriptConversion::IsCallable(resolve) && JavascriptConversion::IsCallable(reject));
1013+
AsyncSpawnStep(nextFunction, gen, resolve, reject);
10141014

10151015
return undefinedVar;
10161016
}
@@ -1054,8 +1054,8 @@ namespace Js
10541054
JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* asyncSpawnStepExecutorFunction = JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction::FromVar(function);
10551055
JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* functionArg;
10561056
JavascriptGenerator* gen = asyncSpawnStepExecutorFunction->GetGenerator();
1057-
JavascriptFunction* reject = asyncSpawnStepExecutorFunction->GetReject();
1058-
JavascriptFunction* resolve = asyncSpawnStepExecutorFunction->GetResolve();
1057+
Var reject = asyncSpawnStepExecutorFunction->GetReject();
1058+
Var resolve = asyncSpawnStepExecutorFunction->GetResolve();
10591059

10601060
if (asyncSpawnStepExecutorFunction->GetIsReject())
10611061
{
@@ -1071,9 +1071,9 @@ namespace Js
10711071
return undefinedVar;
10721072
}
10731073

1074-
void JavascriptPromise::AsyncSpawnStep(JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* nextFunction, JavascriptGenerator* gen, JavascriptFunction* resolve, JavascriptFunction* reject)
1074+
void JavascriptPromise::AsyncSpawnStep(JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* nextFunction, JavascriptGenerator* gen, Var resolve, Var reject)
10751075
{
1076-
ScriptContext* scriptContext = resolve->GetScriptContext();
1076+
ScriptContext* scriptContext = gen->GetScriptContext();
10771077
JavascriptLibrary* library = scriptContext->GetLibrary();
10781078
Var undefinedVar = library->GetUndefined();
10791079

@@ -1105,7 +1105,12 @@ namespace Js
11051105
{
11061106
// finished with success, resolve the promise
11071107
value = JavascriptOperators::GetProperty(next, PropertyIds::value, scriptContext);
1108-
CALL_FUNCTION(scriptContext->GetThreadContext(), resolve, CallInfo(CallFlags_Value, 2), undefinedVar, value);
1108+
if (!JavascriptConversion::IsCallable(resolve))
1109+
{
1110+
JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction);
1111+
}
1112+
CALL_FUNCTION(scriptContext->GetThreadContext(), RecyclableObject::FromVar(resolve), CallInfo(CallFlags_Value, 2), undefinedVar, value);
1113+
11091114
return;
11101115
}
11111116

@@ -1118,11 +1123,19 @@ namespace Js
11181123
Var promiseVar = CALL_FUNCTION(scriptContext->GetThreadContext(), promiseResolve, CallInfo(CallFlags_Value, 2), library->GetPromiseConstructor(), value);
11191124
JavascriptPromise* promise = FromVar(promiseVar);
11201125

1121-
JavascriptFunction* promiseThen = JavascriptFunction::FromVar(JavascriptOperators::GetProperty(promise, PropertyIds::then, scriptContext));
1122-
CALL_FUNCTION(scriptContext->GetThreadContext(), promiseThen, CallInfo(CallFlags_Value, 2), promise, successFunction);
1126+
Var promiseThen = JavascriptOperators::GetProperty(promise, PropertyIds::then, scriptContext);
1127+
if (!JavascriptConversion::IsCallable(promiseThen))
1128+
{
1129+
JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction);
1130+
}
1131+
CALL_FUNCTION(scriptContext->GetThreadContext(), RecyclableObject::FromVar(promiseThen), CallInfo(CallFlags_Value, 2), promise, successFunction);
11231132

1124-
JavascriptFunction* promiseCatch = JavascriptFunction::FromVar(JavascriptOperators::GetProperty(promise, PropertyIds::catch_, scriptContext));
1125-
CALL_FUNCTION(scriptContext->GetThreadContext(), promiseCatch, CallInfo(CallFlags_Value, 2), promise, failFunction);
1133+
Var promiseCatch = JavascriptOperators::GetProperty(promise, PropertyIds::catch_, scriptContext);
1134+
if (!JavascriptConversion::IsCallable(promiseCatch))
1135+
{
1136+
JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction);
1137+
}
1138+
CALL_FUNCTION(scriptContext->GetThreadContext(), RecyclableObject::FromVar(promiseCatch), CallInfo(CallFlags_Value, 2), promise, failFunction);
11261139
}
11271140

11281141
#if ENABLE_TTD
@@ -1435,7 +1448,7 @@ namespace Js
14351448
}
14361449
#endif
14371450

1438-
JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction::JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction(DynamicType* type, FunctionInfo* functionInfo, JavascriptGenerator* generator, Var argument, JavascriptFunction* resolve, JavascriptFunction* reject, bool isReject)
1451+
JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction::JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction(DynamicType* type, FunctionInfo* functionInfo, JavascriptGenerator* generator, Var argument, Var resolve, Var reject, bool isReject)
14391452
: RuntimeFunction(type, functionInfo), generator(generator), argument(argument), resolve(resolve), reject(reject), isReject(isReject)
14401453
{ }
14411454

@@ -1464,12 +1477,12 @@ namespace Js
14641477
return this->generator;
14651478
}
14661479

1467-
JavascriptFunction* JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction::GetResolve()
1480+
Var JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction::GetResolve()
14681481
{
14691482
return this->resolve;
14701483
}
14711484

1472-
JavascriptFunction* JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction::GetReject()
1485+
Var JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction::GetReject()
14731486
{
14741487
return this->reject;
14751488
}

lib/Runtime/Library/JavascriptPromise.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,21 +78,21 @@ namespace Js
7878
DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction);
7979

8080
public:
81-
JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction(DynamicType* type, FunctionInfo* functionInfo, JavascriptGenerator* generator, Var argument, JavascriptFunction* resolve = NULL, JavascriptFunction* reject = NULL, bool isReject = false);
81+
JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction(DynamicType* type, FunctionInfo* functionInfo, JavascriptGenerator* generator, Var argument, Var resolve = nullptr, Var reject = nullptr, bool isReject = false);
8282

8383
inline static bool Is(Var var);
8484
inline static JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* FromVar(Var var);
8585

8686
JavascriptGenerator* GetGenerator();
87-
JavascriptFunction* GetReject();
88-
JavascriptFunction* GetResolve();
87+
Var GetReject();
88+
Var GetResolve();
8989
bool GetIsReject();
9090
Var GetArgument();
9191

9292
private:
9393
JavascriptGenerator* generator;
94-
JavascriptFunction* reject;
95-
JavascriptFunction* resolve;
94+
Var reject;
95+
Var resolve;
9696
bool isReject;
9797
Var argument;
9898

@@ -466,7 +466,7 @@ namespace Js
466466
JavascriptPromiseReactionList* rejectReactions;
467467

468468
private :
469-
static void AsyncSpawnStep(JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* nextFunction, JavascriptGenerator* gen, JavascriptFunction* resolve, JavascriptFunction* reject);
469+
static void AsyncSpawnStep(JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* nextFunction, JavascriptGenerator* gen, Var resolve, Var reject);
470470

471471
#if ENABLE_TTD
472472
public:

test/Bugs/bug11026788.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
//-------------------------------------------------------------------------------------------------------
5+
6+
async function foo( ) {
7+
var p1 = new Promise(
8+
timeout1 => {
9+
setTimeout( () => {
10+
timeout1( 1 );
11+
}, 500 );
12+
}
13+
);
14+
15+
var p2 = new Promise(
16+
timeout2 => {
17+
setTimeout( () => {
18+
timeout2( 2 );
19+
}, 500 );
20+
}
21+
);
22+
23+
return await p1 + await p2;
24+
}
25+
26+
promise = foo();
27+
promise.__proto__.then = (0x41414141 - 8) >> 0;
28+
29+
try {
30+
promise.then( function( value ){} );
31+
WScript.Echo("FAILED");
32+
} catch (e) {
33+
if (e instanceof TypeError) {
34+
WScript.Echo("PASSED");
35+
} else {
36+
WScript.Echo("FAILED");
37+
}
38+
}

test/Bugs/rlexe.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,4 +392,9 @@
392392
<compile-flags>-mic:1 -off:simplejit -oopjit- -bgjit-</compile-flags>
393393
</default>
394394
</test>
395+
<test>
396+
<default>
397+
<files>bug11026788.js</files>
398+
</default>
399+
</test>
395400
</regress-exe>

0 commit comments

Comments
 (0)