CVE-2017-0152 (C++, published 2017-07-17T13:18Z)
Description: value: A remote code execution vulnerability exists in the way affected Microsoft scripting engine render when handling objects in memory in Microsoft browsers. The vulnerability could corrupt memory in such a way that an attacker could execute arbitrary code in the context of the current user. An attacker who successfully exploited the vulnerability could gain the same user rights as the current user, aka "Scripting Engine Memory Corruption Vulnerability."
Severity: HIGH (CVSS v3 base score: 8.1)
Weakness: CWE-119 \u2014 Improper Restriction of Operations within the Bounds of a Memory Buffer
The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
Repository: https://github.com/Microsoft/ChakraCore
Files changed:
lib/Parser/Parse.cpp
lib/Runtime/ByteCode/ByteCodeEmitter.cpp
test/es6/default-splitscope.js
Commit message: [CVE-2017-0152] MSFT: 10592731 : Issue with Function name capturing in param scope

In a function expression with name, where the name is captured in one
of the param scope functions, if there is a function or var declaration
with the same name as the function expression name we were marking the
function expression name as shadowed. In non-eval case this causes
issue because the name symbol won't get added to the body. This change is to
fix it in such a way if the name is captured in the param scope then we
split the param and body scope such that the name symbol is added to the
param scope not body scope.


Vulnerable code:
                else if (varSym && varSym->GetSymbolType() == STVariable && (varSym->IsInSlot(funcInfo) || varSym->GetLocation() != Js::Constants::NoRegister))

Fixed code:
                if (paramScope->GetCanMergeWithBodyScope() && !fDeclaration && pnodeFnc->sxFnc.pnodeName != nullptr)
                {
                    Symbol* funcSym = pnodeFnc->sxFnc.pnodeName->sxVar.sym;
                    if (funcSym->GetPid()->GetTopRef()->GetFuncScopeId() > pnodeFnc->sxFnc.functionId)
                    {
                        // This is a function expression with name captured in the param scope. In non-eval, non-split cases the function
                        // name symbol is added to the body scope to make it accessible in the body. But if there is a function or var
                        // declaration with the same name in the body then adding to the body will fail. So in this case we have to add
                        // the name symbol to the param scope by splitting it.
                        paramScope->SetCannotMergeWithBodyScope();
                    }
                }

            Symbol* funcSym = funcInfo->root->sxFnc.GetFuncSymbol();
                else if ((funcSym == nullptr || funcSym != param)    // Do not copy the symbol over to body as the function expression symbol
                                                                     // is expected to stay inside the function expression scope
                    && (varSym && varSym->GetSymbolType() == STVariable && (varSym->IsInSlot(funcInfo) || varSym->GetLocation() != Js::Constants::NoRegister)))

        function f13() {
            var a = function jnvgfg(sfgnmj = function ccunlk() { jnvgfg(undefined, 1); }, b) {
                if (b) {
                    assert.areEqual(undefined, jnvgfg, "This refers to the instance in the body and the value of the function expression is not copied over");
                }
                var jnvgfg = 10;
                if (!b) {
                    sfgnmj();
                    return 100;
                }
            };
            assert.areEqual(100, a(), "After the recursion the right value is returned by the split scoped function");
        };
        f13();