summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpthier <pthier@chromium.org>2023-10-24 13:28:22 +0200
committerMichael BrĂ¼ning <michael.bruning@qt.io>2023-12-19 10:26:47 +0000
commit6a382d96ac3becf92f28f8549318390193da1ddd (patch)
tree3ea29c1359303a6f6f0e602543a1cebe00d375a2
parent4d095ba080045a255cb93ecadb9f3358fdc7cd80 (diff)
[Backport] Security bug 1488199 (1/2)
Manual backport of patch originally reviewed on https://chromium-review.googlesource.com/c/v8/v8/+/4971832: [regexp] Fix stack check in native code when interrupt was requested When an interrupt was requested at the time we hit the stack check, the check to ensure we have enough space for local variables was skipped. Bug: chromium:1488199 Change-Id: I95d82fe737420d2ef43c1ace35560cfd5860829b Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4971832 Commit-Queue: Patrick Thier <pthier@chromium.org> Reviewed-by: Jakob Linke <jgruber@chromium.org> Cr-Commit-Position: refs/heads/main@{#90560} Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/523701 Reviewed-by: Michal Klocek <michal.klocek@qt.io>
-rw-r--r--chromium/v8/src/regexp/arm/regexp-macro-assembler-arm.cc22
-rw-r--r--chromium/v8/src/regexp/arm/regexp-macro-assembler-arm.h5
-rw-r--r--chromium/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc21
-rw-r--r--chromium/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h6
-rw-r--r--chromium/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc19
-rw-r--r--chromium/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h5
-rw-r--r--chromium/v8/src/regexp/regexp-macro-assembler.cc5
-rw-r--r--chromium/v8/src/regexp/regexp-macro-assembler.h2
-rw-r--r--chromium/v8/src/regexp/x64/regexp-macro-assembler-x64.cc35
-rw-r--r--chromium/v8/src/regexp/x64/regexp-macro-assembler-x64.h4
10 files changed, 78 insertions, 46 deletions
diff --git a/chromium/v8/src/regexp/arm/regexp-macro-assembler-arm.cc b/chromium/v8/src/regexp/arm/regexp-macro-assembler-arm.cc
index 78b586e265d..099fc62fa07 100644
--- a/chromium/v8/src/regexp/arm/regexp-macro-assembler-arm.cc
+++ b/chromium/v8/src/regexp/arm/regexp-macro-assembler-arm.cc
@@ -670,11 +670,13 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
__ mov(r0, Operand(stack_limit));
__ ldr(r0, MemOperand(r0));
__ sub(r0, sp, r0, SetCC);
+ Operand extra_space_for_variables(num_registers_ * kPointerSize);
+
// Handle it if the stack pointer is already below the stack limit.
__ b(ls, &stack_limit_hit);
// Check if there is room for the variable number of registers above
// the stack limit.
- __ cmp(r0, Operand(num_registers_ * kPointerSize));
+ __ cmp(r0, extra_space_for_variables);
__ b(hs, &stack_ok);
// Exit with OutOfMemory exception. There is not enough space on the stack
// for our working registers.
@@ -682,7 +684,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
__ jmp(&return_r0);
__ bind(&stack_limit_hit);
- CallCheckStackGuardState();
+ CallCheckStackGuardState(extra_space_for_variables);
__ cmp(r0, Operand::Zero());
// If returned value is non-zero, we exit with the returned value as result.
__ b(ne, &return_r0);
@@ -1048,16 +1050,18 @@ void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) {
// Private methods:
-void RegExpMacroAssemblerARM::CallCheckStackGuardState() {
+void RegExpMacroAssemblerARM::CallCheckStackGuardState(Operand extra_space) {
DCHECK(!isolate()->IsGeneratingEmbeddedBuiltins());
DCHECK(!masm_->options().isolate_independent_code);
- __ PrepareCallCFunction(3);
+ __ PrepareCallCFunction(4);
+ // Extra space for variables to consider in stack check.
+ __ mov(arg_reg_4, extra_space);
// RegExp code frame pointer.
- __ mov(r2, frame_pointer());
+ __ mov(arg_reg3, frame_pointer());
// Code of self.
- __ mov(r1, Operand(masm_->CodeObject()));
+ __ mov(arg_reg2, Operand(masm_->CodeObject()));
// We need to make room for the return address on the stack.
int stack_alignment = base::OS::ActivationFrameAlignment();
@@ -1101,7 +1105,8 @@ static T* frame_entry_address(Address re_frame, int frame_offset) {
int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
Address raw_code,
- Address re_frame) {
+ Address re_frame,
+ uintptr_t extra_space) {
Code re_code = Code::cast(Object(raw_code));
return NativeRegExpMacroAssembler::CheckStackGuardState(
frame_entry<Isolate*>(re_frame, kIsolate),
@@ -1110,7 +1115,8 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
return_address, re_code,
frame_entry_address<Address>(re_frame, kInputString),
frame_entry_address<const byte*>(re_frame, kInputStart),
- frame_entry_address<const byte*>(re_frame, kInputEnd));
+ frame_entry_address<const byte*>(re_frame, kInputEnd),
+ extra_space);
}
diff --git a/chromium/v8/src/regexp/arm/regexp-macro-assembler-arm.h b/chromium/v8/src/regexp/arm/regexp-macro-assembler-arm.h
index 910e5c46079..114120755fc 100644
--- a/chromium/v8/src/regexp/arm/regexp-macro-assembler-arm.h
+++ b/chromium/v8/src/regexp/arm/regexp-macro-assembler-arm.h
@@ -89,7 +89,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM
// returning.
// {raw_code} is an Address because this is called via ExternalReference.
static int CheckStackGuardState(Address* return_address, Address raw_code,
- Address re_frame);
+ Address re_frame, uintptr_t extra_space);
private:
// Offsets from frame_pointer() of function parameters and stored registers.
@@ -134,7 +134,8 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM
// Generate a call to CheckStackGuardState.
- void CallCheckStackGuardState();
+ void CallCheckStackGuardState(
+ Operand extra_space_for_variables = Operand::Zero());
// The ebp-relative location of a regexp register.
MemOperand register_location(int register_index);
diff --git a/chromium/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc b/chromium/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc
index ac33f8631ff..1e5342dd42e 100644
--- a/chromium/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc
+++ b/chromium/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc
@@ -781,13 +781,14 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
__ Mov(x10, stack_limit);
__ Ldr(x10, MemOperand(x10));
__ Subs(x10, sp, x10);
+ Operand extra_space_for_variables(num_wreg_to_allocate * kWRegSize);
// Handle it if the stack pointer is already below the stack limit.
__ B(ls, &stack_limit_hit);
// Check if there is room for the variable number of registers above
// the stack limit.
- __ Cmp(x10, num_wreg_to_allocate * kWRegSize);
+ __ Cmp(x10, extra_space_for_variables);
__ B(hs, &stack_ok);
// Exit with OutOfMemory exception. There is not enough space on the stack
@@ -796,7 +797,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
__ B(&return_w0);
__ Bind(&stack_limit_hit);
- CallCheckStackGuardState(x10);
+ CallCheckStackGuardState(x10, extra_space_for_variables);
// If returned value is non-zero, we exit with the returned value as result.
__ Cbnz(w0, &return_w0);
@@ -1332,13 +1333,14 @@ static T* frame_entry_address(Address re_frame, int frame_offset) {
int RegExpMacroAssemblerARM64::CheckStackGuardState(
Address* return_address, Address raw_code, Address re_frame,
- int start_index, const byte** input_start, const byte** input_end) {
+ int start_index, const byte** input_start, const byte** input_end,
+ uintptr_t extra_space) {
Code re_code = Code::cast(Object(raw_code));
return NativeRegExpMacroAssembler::CheckStackGuardState(
frame_entry<Isolate*>(re_frame, kIsolate), start_index,
static_cast<RegExp::CallOrigin>(frame_entry<int>(re_frame, kDirectCall)),
return_address, re_code, frame_entry_address<Address>(re_frame, kInput),
- input_start, input_end);
+ input_start, input_end, extra_space);
}
@@ -1357,21 +1359,24 @@ void RegExpMacroAssemblerARM64::CheckPosition(int cp_offset,
// Private methods:
-void RegExpMacroAssemblerARM64::CallCheckStackGuardState(Register scratch) {
+void RegExpMacroAssemblerARM64::CallCheckStackGuardState(Register scratch,
+ Operand extra_space) {
DCHECK(!isolate()->IsGeneratingEmbeddedBuiltins());
DCHECK(!masm_->options().isolate_independent_code);
// Allocate space on the stack to store the return address. The
// CheckStackGuardState C++ function will override it if the code
- // moved. Allocate extra space for 2 arguments passed by pointers.
- // AAPCS64 requires the stack to be 16 byte aligned.
+ // moved. Allocate extra space for 3 arguments (2 for input start/end and 1
+ // for gap). AAPCS64 requires the stack to be 16 byte aligned.
int alignment = masm_->ActivationFrameAlignment();
DCHECK_EQ(alignment % 16, 0);
int align_mask = (alignment / kXRegSize) - 1;
- int xreg_to_claim = (3 + align_mask) & ~align_mask;
+ int xreg_to_claim = (4 + align_mask) & ~align_mask;
__ Claim(xreg_to_claim);
+ __ Mov(x0, extra_space);
+ __ Poke(x0, 3 * kSystemPointerSize);
// CheckStackGuardState needs the end and start addresses of the input string.
__ Poke(input_end(), 2 * kSystemPointerSize);
__ Add(x5, sp, 2 * kSystemPointerSize);
diff --git a/chromium/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h b/chromium/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h
index aeb49aa9fff..e4c4b0ac34f 100644
--- a/chromium/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h
+++ b/chromium/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h
@@ -97,7 +97,8 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64
static int CheckStackGuardState(Address* return_address, Address raw_code,
Address re_frame, int start_offset,
const byte** input_start,
- const byte** input_end);
+ const byte** input_end,
+ uintptr_t extra_space);
private:
// Above the frame pointer - Stored registers and stack passed parameters.
@@ -145,7 +146,8 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64
void CheckStackLimit();
// Generate a call to CheckStackGuardState.
- void CallCheckStackGuardState(Register scratch);
+ void CallCheckStackGuardState(Register scratch,
+ Operand extra_space = Operand(0));
// Location of a 32 bit position register.
MemOperand register_location(int register_index);
diff --git a/chromium/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc b/chromium/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc
index 2135e977a74..d5fbd960675 100644
--- a/chromium/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc
+++ b/chromium/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc
@@ -700,11 +700,13 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
ExternalReference::address_of_jslimit(isolate());
__ mov(ecx, esp);
__ sub(ecx, StaticVariable(stack_limit));
+ Immediate extra_space_for_variables(num_registers_ * kSystemPointerSize);
+
// Handle it if the stack pointer is already below the stack limit.
__ j(below_equal, &stack_limit_hit);
// Check if there is room for the variable number of registers above
// the stack limit.
- __ cmp(ecx, num_registers_ * kSystemPointerSize);
+ __ cmp(ecx, extra_space_for_variables);
__ j(above_equal, &stack_ok);
// Exit with OutOfMemory exception. There is not enough space on the stack
// for our working registers.
@@ -712,7 +714,7 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
__ jmp(&return_eax);
__ bind(&stack_limit_hit);
- CallCheckStackGuardState(ebx);
+ CallCheckStackGuardState(ebx, extra_space_for_variables);
__ or_(eax, eax);
// If returned value is non-zero, we exit with the returned value as result.
__ j(not_zero, &return_eax);
@@ -1080,9 +1082,12 @@ void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
// Private methods:
-void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
- static const int num_arguments = 3;
+void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch,
+ Immediate extra_space) {
+ static const int num_arguments = 4;
__ PrepareCallCFunction(num_arguments, scratch);
+ // Extra space for variables.
+ __ mov(Operand(esp, 3 * kSystemPointerSize), extra_space);
// RegExp code frame pointer.
__ mov(Operand(esp, 2 * kSystemPointerSize), ebp);
// Code of self.
@@ -1113,7 +1118,8 @@ static T* frame_entry_address(Address re_frame, int frame_offset) {
int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
Address raw_code,
- Address re_frame) {
+ Address re_frame,
+ uintptr_t extra_space) {
Code re_code = Code::cast(Object(raw_code));
return NativeRegExpMacroAssembler::CheckStackGuardState(
frame_entry<Isolate*>(re_frame, kIsolate),
@@ -1122,7 +1128,8 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
return_address, re_code,
frame_entry_address<Address>(re_frame, kInputString),
frame_entry_address<const byte*>(re_frame, kInputStart),
- frame_entry_address<const byte*>(re_frame, kInputEnd));
+ frame_entry_address<const byte*>(re_frame, kInputEnd),
+ extra_space);
}
diff --git a/chromium/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h b/chromium/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h
index a30bff29a15..620e7fb2982 100644
--- a/chromium/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h
+++ b/chromium/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h
@@ -88,7 +88,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32
// returning.
// {raw_code} is an Address because this is called via ExternalReference.
static int CheckStackGuardState(Address* return_address, Address raw_code,
- Address re_frame);
+ Address re_frame, uintptr_t extra_space);
private:
Operand StaticVariable(const ExternalReference& ext);
@@ -133,7 +133,8 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32
void CheckStackLimit();
// Generate a call to CheckStackGuardState.
- void CallCheckStackGuardState(Register scratch);
+ void CallCheckStackGuardState(Register scratch,
+ Immediate extra_space = Immediate(0));
// The ebp-relative location of a regexp register.
Operand register_location(int register_index);
diff --git a/chromium/v8/src/regexp/regexp-macro-assembler.cc b/chromium/v8/src/regexp/regexp-macro-assembler.cc
index cf4346309eb..009027c1039 100644
--- a/chromium/v8/src/regexp/regexp-macro-assembler.cc
+++ b/chromium/v8/src/regexp/regexp-macro-assembler.cc
@@ -168,14 +168,15 @@ bool NativeRegExpMacroAssembler::CanReadUnaligned() {
int NativeRegExpMacroAssembler::CheckStackGuardState(
Isolate* isolate, int start_index, RegExp::CallOrigin call_origin,
Address* return_address, Code re_code, Address* subject,
- const byte** input_start, const byte** input_end) {
+ const byte** input_start, const byte** input_end,
+ uintptr_t gap) {
DisallowHeapAllocation no_gc;
Address old_pc = PointerAuthentication::AuthenticatePC(return_address, 0);
DCHECK_LE(re_code.raw_instruction_start(), old_pc);
DCHECK_LE(old_pc, re_code.raw_instruction_end());
StackLimitCheck check(isolate);
- bool js_has_overflowed = check.JsHasOverflowed();
+ bool js_has_overflowed = check.JsHasOverflowed(gap);
if (call_origin == RegExp::CallOrigin::kFromJs) {
// Direct calls from JavaScript can be interrupted in two ways:
diff --git a/chromium/v8/src/regexp/regexp-macro-assembler.h b/chromium/v8/src/regexp/regexp-macro-assembler.h
index 52465610cb6..da233d3c73d 100644
--- a/chromium/v8/src/regexp/regexp-macro-assembler.h
+++ b/chromium/v8/src/regexp/regexp-macro-assembler.h
@@ -261,7 +261,7 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
RegExp::CallOrigin call_origin,
Address* return_address, Code re_code,
Address* subject, const byte** input_start,
- const byte** input_end);
+ const byte** input_end, uintptr_t gap);
// Byte map of one byte characters with a 0xff if the character is a word
// character (digit, letter or underscore) and 0x00 otherwise.
diff --git a/chromium/v8/src/regexp/x64/regexp-macro-assembler-x64.cc b/chromium/v8/src/regexp/x64/regexp-macro-assembler-x64.cc
index da0397689fb..6ae1114f24e 100644
--- a/chromium/v8/src/regexp/x64/regexp-macro-assembler-x64.cc
+++ b/chromium/v8/src/regexp/x64/regexp-macro-assembler-x64.cc
@@ -736,11 +736,13 @@ Handle<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
__ movq(rcx, rsp);
__ Move(kScratchRegister, stack_limit);
__ subq(rcx, Operand(kScratchRegister, 0));
+ Immediate extra_space_for_variables(num_registers_ * kSystemPointerSize);
+
// Handle it if the stack pointer is already below the stack limit.
__ j(below_equal, &stack_limit_hit);
// Check if there is room for the variable number of registers above
// the stack limit.
- __ cmpq(rcx, Immediate(num_registers_ * kSystemPointerSize));
+ __ cmpq(rcx, extra_space_for_variables);
__ j(above_equal, &stack_ok);
// Exit with OutOfMemory exception. There is not enough space on the stack
// for our working registers.
@@ -749,7 +751,8 @@ Handle<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
__ bind(&stack_limit_hit);
__ Move(code_object_pointer(), masm_.CodeObject());
- CallCheckStackGuardState(); // Preserves no registers beside rbp and rsp.
+ // CallCheckStackGuardState preserves no registers beside rbp and rsp.
+ CallCheckStackGuardState(extra_space_for_variables);
__ testq(rax, rax);
// If returned value is non-zero, we exit with the returned value as result.
__ j(not_zero, &return_rax);
@@ -1147,27 +1150,31 @@ void RegExpMacroAssemblerX64::WriteStackPointerToRegister(int reg) {
// Private methods:
-void RegExpMacroAssemblerX64::CallCheckStackGuardState() {
+void RegExpMacroAssemblerX64::CallCheckStackGuardState(Immediate extra_space) {
// This function call preserves no register values. Caller should
// store anything volatile in a C call or overwritten by this function.
- static const int num_arguments = 3;
+ static const int num_arguments = 4;
__ PrepareCallCFunction(num_arguments);
#ifdef V8_TARGET_OS_WIN
- // Second argument: Code of self. (Do this before overwriting r8).
- __ movq(rdx, code_object_pointer());
+ // Fourth argument: Extra space for variables.
+ __ movq(arg_reg_4, extra_space);
+ // Second argument: Code of self. (Do this before overwriting r8 (arg_reg_3)).
+ __ movq(arg_reg_2, code_object_pointer());
// Third argument: RegExp code frame pointer.
- __ movq(r8, rbp);
+ __ movq(arg_reg_3, rbp);
// First argument: Next address on the stack (will be address of
// return address).
- __ leaq(rcx, Operand(rsp, -kSystemPointerSize));
+ __ leaq(arg_reg_1, Operand(rsp, -kSystemPointerSize));
#else
+ // Fourth argument: Extra space for variables.
+ __ movq(arg_reg_4, extra_space);
// Third argument: RegExp code frame pointer.
- __ movq(rdx, rbp);
+ __ movq(arg_reg_3, rbp);
// Second argument: Code of self.
- __ movq(rsi, code_object_pointer());
+ __ movq(arg_reg_2, code_object_pointer());
// First argument: Next address on the stack (will be address of
// return address).
- __ leaq(rdi, Operand(rsp, -kSystemPointerSize));
+ __ leaq(arg_reg_1, Operand(rsp, -kSystemPointerSize));
#endif
ExternalReference stack_check =
ExternalReference::re_check_stack_guard_state(isolate());
@@ -1189,7 +1196,8 @@ static T* frame_entry_address(Address re_frame, int frame_offset) {
int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
Address raw_code,
- Address re_frame) {
+ Address re_frame,
+ uintptr_t extra_space) {
Code re_code = Code::cast(Object(raw_code));
return NativeRegExpMacroAssembler::CheckStackGuardState(
frame_entry<Isolate*>(re_frame, kIsolate),
@@ -1198,7 +1206,8 @@ int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
return_address, re_code,
frame_entry_address<Address>(re_frame, kInputString),
frame_entry_address<const byte*>(re_frame, kInputStart),
- frame_entry_address<const byte*>(re_frame, kInputEnd));
+ frame_entry_address<const byte*>(re_frame, kInputEnd),
+ extra_space);
}
diff --git a/chromium/v8/src/regexp/x64/regexp-macro-assembler-x64.h b/chromium/v8/src/regexp/x64/regexp-macro-assembler-x64.h
index ea4d45edba8..6e5dcd18c28 100644
--- a/chromium/v8/src/regexp/x64/regexp-macro-assembler-x64.h
+++ b/chromium/v8/src/regexp/x64/regexp-macro-assembler-x64.h
@@ -82,7 +82,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64
// returning.
// {raw_code} is an Address because this is called via ExternalReference.
static int CheckStackGuardState(Address* return_address, Address raw_code,
- Address re_frame);
+ Address re_frame, uintptr_t extra_space);
private:
// Offsets from rbp of function parameters and stored registers.
@@ -166,7 +166,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64
void CheckStackLimit();
// Generate a call to CheckStackGuardState.
- void CallCheckStackGuardState();
+ void CallCheckStackGuardState(Immediate extra_space = Immediate(0));
// The rbp-relative location of a regexp register.
Operand register_location(int register_index);