Skip to content

Commit d4aafa4

Browse files
sergeiglazunovCommit Bot
authored andcommitted
[turbofan] Harden ArrayPrototypePop and ArrayPrototypeShift
An exploitation technique that abuses `pop` and `shift` to create a JS array with a negative length was publicly disclosed some time ago. Add extra checks to break the technique. Bug: chromium:1198696 Change-Id: Ie008e9ae60bbdc3b25ca3a986d3cdc5e3cc00431 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2823707 Reviewed-by: Georg Neis <[email protected]> Commit-Queue: Sergei Glazunov <[email protected]> Cr-Commit-Position: refs/heads/master@{#73973}
1 parent e1cae86 commit d4aafa4

File tree

1 file changed

+24
-9
lines changed

1 file changed

+24
-9
lines changed

src/compiler/js-call-reducer.cc

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5393,24 +5393,31 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
53935393
}
53945394

53955395
// Compute the new {length}.
5396-
length = graph()->NewNode(simplified()->NumberSubtract(), length,
5397-
jsgraph()->OneConstant());
5396+
Node* new_length = graph()->NewNode(simplified()->NumberSubtract(),
5397+
length, jsgraph()->OneConstant());
5398+
5399+
// This extra check exists solely to break an exploitation technique
5400+
// that abuses typer mismatches.
5401+
new_length = efalse = graph()->NewNode(
5402+
simplified()->CheckBounds(p.feedback(),
5403+
CheckBoundsFlag::kAbortOnOutOfBounds),
5404+
new_length, length, efalse, if_false);
53985405

53995406
// Store the new {length} to the {receiver}.
54005407
efalse = graph()->NewNode(
54015408
simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)),
5402-
receiver, length, efalse, if_false);
5409+
receiver, new_length, efalse, if_false);
54035410

54045411
// Load the last entry from the {elements}.
54055412
vfalse = efalse = graph()->NewNode(
54065413
simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(kind)),
5407-
elements, length, efalse, if_false);
5414+
elements, new_length, efalse, if_false);
54085415

54095416
// Store a hole to the element we just removed from the {receiver}.
54105417
efalse = graph()->NewNode(
54115418
simplified()->StoreElement(
54125419
AccessBuilder::ForFixedArrayElement(GetHoleyElementsKind(kind))),
5413-
elements, length, jsgraph()->TheHoleConstant(), efalse, if_false);
5420+
elements, new_length, jsgraph()->TheHoleConstant(), efalse, if_false);
54145421
}
54155422

54165423
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
@@ -5586,19 +5593,27 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
55865593
}
55875594

55885595
// Compute the new {length}.
5589-
length = graph()->NewNode(simplified()->NumberSubtract(), length,
5590-
jsgraph()->OneConstant());
5596+
Node* new_length = graph()->NewNode(simplified()->NumberSubtract(),
5597+
length, jsgraph()->OneConstant());
5598+
5599+
// This extra check exists solely to break an exploitation technique
5600+
// that abuses typer mismatches.
5601+
new_length = etrue1 = graph()->NewNode(
5602+
simplified()->CheckBounds(p.feedback(),
5603+
CheckBoundsFlag::kAbortOnOutOfBounds),
5604+
new_length, length, etrue1, if_true1);
55915605

55925606
// Store the new {length} to the {receiver}.
55935607
etrue1 = graph()->NewNode(
55945608
simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)),
5595-
receiver, length, etrue1, if_true1);
5609+
receiver, new_length, etrue1, if_true1);
55965610

55975611
// Store a hole to the element we just removed from the {receiver}.
55985612
etrue1 = graph()->NewNode(
55995613
simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
56005614
GetHoleyElementsKind(kind))),
5601-
elements, length, jsgraph()->TheHoleConstant(), etrue1, if_true1);
5615+
elements, new_length, jsgraph()->TheHoleConstant(), etrue1,
5616+
if_true1);
56025617
}
56035618

56045619
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);

0 commit comments

Comments
 (0)