diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-01-15 10:25:41 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-01-15 12:31:26 +0000 |
commit | 4848d71bd91915a856f17a2bc45b402bda1d96f7 (patch) | |
tree | 6156ea01655bc723ce5db7c3e0f357953ae8a340 /chromium | |
parent | 35e15c600128669499d1a6994886050bab51d646 (diff) | |
download | qtwebengine-chromium-4848d71bd91915a856f17a2bc45b402bda1d96f7.tar.gz |
[Backport] Security bug 881252 and 896326
Check for stack overflow when pushing arguments in JSConstructStubGeneric
Bug: chromium:896326
Change-Id: I9257573963f611711edbc48a46a3bacbe12a567d
Reviewed-on: https://chromium-review.googlesource.com/c/1305934
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Mythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57398}
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium')
-rw-r--r-- | chromium/v8/src/builtins/arm/builtins-arm.cc | 42 | ||||
-rw-r--r-- | chromium/v8/src/builtins/arm64/builtins-arm64.cc | 69 | ||||
-rw-r--r-- | chromium/v8/src/builtins/ia32/builtins-ia32.cc | 65 | ||||
-rw-r--r-- | chromium/v8/src/builtins/x64/builtins-x64.cc | 54 |
4 files changed, 152 insertions, 78 deletions
diff --git a/chromium/v8/src/builtins/arm/builtins-arm.cc b/chromium/v8/src/builtins/arm/builtins-arm.cc index a5219bf0701..e30100452b8 100644 --- a/chromium/v8/src/builtins/arm/builtins-arm.cc +++ b/chromium/v8/src/builtins/arm/builtins-arm.cc @@ -167,6 +167,20 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { __ Jump(lr); } +void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, + Register scratch, Label* stack_overflow) { + // Check the stack for overflow. We are not trying to catch + // interruptions (e.g. debug break and preemption) here, so the "real stack + // limit" is checked. + __ LoadRoot(scratch, Heap::kRealStackLimitRootIndex); + // Make scratch the space we have left. The stack might already be overflowed + // here which will cause scratch to become negative. + __ sub(scratch, sp, scratch); + // Check if the arguments will overflow the stack. + __ cmp(scratch, Operand(num_args, LSL, kPointerSizeLog2)); + __ b(le, stack_overflow); // Signed comparison. +} + } // namespace // The construct stub for ES5 constructor functions and ES6 class constructors. @@ -251,6 +265,19 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { // Set up pointer to last argument. __ add(r4, fp, Operand(StandardFrameConstants::kCallerSPOffset)); + Label enough_stack_space, stack_overflow; + Generate_StackOverflowCheck(masm, r0, r5, &stack_overflow); + __ b(&enough_stack_space); + + __ bind(&stack_overflow); + // Restore the context from the frame. + __ ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset)); + __ CallRuntime(Runtime::kThrowStackOverflow); + // Unreachable code. + __ bkpt(0); + + __ bind(&enough_stack_space); + // Copy arguments and receiver to the expression stack. Label loop, entry; __ mov(r5, r0); @@ -495,21 +522,6 @@ void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) { __ CallRuntime(Runtime::kThrowConstructedNonConstructable); } -static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, - Register scratch, - Label* stack_overflow) { - // Check the stack for overflow. We are not trying to catch - // interruptions (e.g. debug break and preemption) here, so the "real stack - // limit" is checked. - __ LoadRoot(scratch, Heap::kRealStackLimitRootIndex); - // Make scratch the space we have left. The stack might already be overflowed - // here which will cause scratch to become negative. - __ sub(scratch, sp, scratch); - // Check if the arguments will overflow the stack. - __ cmp(scratch, Operand(num_args, LSL, kPointerSizeLog2)); - __ b(le, stack_overflow); // Signed comparison. -} - static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, bool is_construct) { // Called from Generate_JS_Entry diff --git a/chromium/v8/src/builtins/arm64/builtins-arm64.cc b/chromium/v8/src/builtins/arm64/builtins-arm64.cc index 2254f010c13..6bad8b2849c 100644 --- a/chromium/v8/src/builtins/arm64/builtins-arm64.cc +++ b/chromium/v8/src/builtins/arm64/builtins-arm64.cc @@ -193,6 +193,44 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { __ Ret(); } +void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, + Label* stack_overflow) { + UseScratchRegisterScope temps(masm); + Register scratch = temps.AcquireX(); + + // Check the stack for overflow. + // We are not trying to catch interruptions (e.g. debug break and + // preemption) here, so the "real stack limit" is checked. + Label enough_stack_space; + __ LoadRoot(scratch, Heap::kRealStackLimitRootIndex); + // Make scratch the space we have left. The stack might already be overflowed + // here which will cause scratch to become negative. + __ Sub(scratch, sp, scratch); + // Check if the arguments will overflow the stack. + __ Cmp(scratch, Operand(num_args, LSL, kPointerSizeLog2)); + __ B(le, stack_overflow); + +#if defined(V8_OS_WIN) + // Simulate _chkstk to extend stack guard page on Windows ARM64. + const int kPageSize = 4096; + Label chkstk, chkstk_done; + Register probe = temps.AcquireX(); + + __ Sub(scratch, sp, Operand(num_args, LSL, kPointerSizeLog2)); + __ Mov(probe, sp); + + // Loop start of stack probe. + __ Bind(&chkstk); + __ Sub(probe, probe, kPageSize); + __ Cmp(probe, scratch); + __ B(lo, &chkstk_done); + __ Ldrb(xzr, MemOperand(probe)); + __ B(&chkstk); + + __ Bind(&chkstk_done); +#endif +} + } // namespace // The construct stub for ES5 constructor functions and ES6 class constructors. @@ -301,6 +339,19 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { // slots for the arguments. If the number of arguments was odd, the last // argument will overwrite one of the receivers pushed above. __ Bic(x10, x12, 1); + + // Check if we have enough stack space to push all arguments. + Label enough_stack_space, stack_overflow; + Generate_StackOverflowCheck(masm, x10, &stack_overflow); + __ B(&enough_stack_space); + + __ Bind(&stack_overflow); + // Restore the context from the frame. + __ Ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset)); + __ CallRuntime(Runtime::kThrowStackOverflow); + __ Unreachable(); + + __ Bind(&enough_stack_space); __ Claim(x10); // Copy the arguments. @@ -532,24 +583,6 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { } } -static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, - Label* stack_overflow) { - UseScratchRegisterScope temps(masm); - Register scratch = temps.AcquireX(); - - // Check the stack for overflow. - // We are not trying to catch interruptions (e.g. debug break and - // preemption) here, so the "real stack limit" is checked. - Label enough_stack_space; - __ LoadRoot(scratch, Heap::kRealStackLimitRootIndex); - // Make scratch the space we have left. The stack might already be overflowed - // here which will cause scratch to become negative. - __ Sub(scratch, sp, scratch); - // Check if the arguments will overflow the stack. - __ Cmp(scratch, Operand(num_args, LSL, kPointerSizeLog2)); - __ B(le, stack_overflow); -} - // Input: // x0: new.target. // x1: function. diff --git a/chromium/v8/src/builtins/ia32/builtins-ia32.cc b/chromium/v8/src/builtins/ia32/builtins-ia32.cc index d1c0a5d5fbb..550342086a0 100644 --- a/chromium/v8/src/builtins/ia32/builtins-ia32.cc +++ b/chromium/v8/src/builtins/ia32/builtins-ia32.cc @@ -133,6 +133,30 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { __ ret(0); } +void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, + Register scratch, Label* stack_overflow, + bool include_receiver = false) { + // Check the stack for overflow. We are not trying to catch + // interruptions (e.g. debug break and preemption) here, so the "real stack + // limit" is checked. + ExternalReference real_stack_limit = + ExternalReference::address_of_real_stack_limit(masm->isolate()); + // Compute the space that is left as a negative number in scratch. If + // we already overflowed, this will be a positive number. + __ mov(scratch, __ ExternalReferenceAsOperand(real_stack_limit, scratch)); + __ sub(scratch, esp); + // Add the size of the arguments. + static_assert(kPointerSize == 4, + "The next instruction assumes kPointerSize == 4"); + __ lea(scratch, Operand(scratch, num_args, times_4, 0)); + if (include_receiver) { + __ add(scratch, Immediate(kPointerSize)); + } + // See if we overflowed, i.e. scratch is positive. + __ cmp(scratch, Immediate(0)); + __ j(greater, stack_overflow); // Signed comparison. +} + } // namespace // The construct stub for ES5 constructor functions and ES6 class constructors. @@ -222,6 +246,21 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { // Set up pointer to last argument. __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); + // Check if we have enough stack space to push all arguments. + // Argument count in eax. Clobbers ecx. + Label enough_stack_space, stack_overflow; + Generate_StackOverflowCheck(masm, eax, ecx, &stack_overflow); + __ jmp(&enough_stack_space); + + __ bind(&stack_overflow); + // Restore context from the frame. + __ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset)); + __ CallRuntime(Runtime::kThrowStackOverflow); + // This should be unreachable. + __ int3(); + + __ bind(&enough_stack_space); + // Copy arguments and receiver to the expression stack. Label loop, entry; __ mov(ecx, eax); @@ -318,32 +357,6 @@ void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) { __ CallRuntime(Runtime::kThrowConstructedNonConstructable); } -static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, - Register scratch1, Register scratch2, - Label* stack_overflow, - bool include_receiver = false) { - // Check the stack for overflow. We are not trying to catch - // interruptions (e.g. debug break and preemption) here, so the "real stack - // limit" is checked. - ExternalReference real_stack_limit = - ExternalReference::address_of_real_stack_limit(masm->isolate()); - __ mov(scratch1, Operand::StaticVariable(real_stack_limit)); - // Make scratch2 the space we have left. The stack might already be overflowed - // here which will cause scratch2 to become negative. - __ mov(scratch2, esp); - __ sub(scratch2, scratch1); - // Make scratch1 the space we need for the array when it is unrolled onto the - // stack. - __ mov(scratch1, num_args); - if (include_receiver) { - __ add(scratch1, Immediate(1)); - } - __ shl(scratch1, kPointerSizeLog2); - // Check if the arguments will overflow the stack. - __ cmp(scratch2, scratch1); - __ j(less_equal, stack_overflow); // Signed comparison. -} - static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, bool is_construct) { ProfileEntryHookStub::MaybeCallEntryHook(masm); diff --git a/chromium/v8/src/builtins/x64/builtins-x64.cc b/chromium/v8/src/builtins/x64/builtins-x64.cc index 438b577af6b..1c7413722b7 100644 --- a/chromium/v8/src/builtins/x64/builtins-x64.cc +++ b/chromium/v8/src/builtins/x64/builtins-x64.cc @@ -133,6 +133,26 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { __ ret(0); } + +void Generate_StackOverflowCheck( + MacroAssembler* masm, Register num_args, Register scratch, + Label* stack_overflow, + Label::Distance stack_overflow_distance = Label::kFar) { + // Check the stack for overflow. We are not trying to catch + // interruptions (e.g. debug break and preemption) here, so the "real stack + // limit" is checked. + __ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex); + __ movp(scratch, rsp); + // Make scratch the space we have left. The stack might already be overflowed + // here which will cause scratch to become negative. + __ subp(scratch, kScratchRegister); + __ sarp(scratch, Immediate(kPointerSizeLog2)); + // Check if the arguments will overflow the stack. + __ cmpp(scratch, num_args); + // Signed comparison. + __ j(less_equal, stack_overflow, stack_overflow_distance); +} + } // namespace // The construct stub for ES5 constructor functions and ES6 class constructors. @@ -219,6 +239,21 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { // Set up pointer to last argument. __ leap(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset)); + // Check if we have enough stack space to push all arguments. + // Argument count in rax. Clobbers rcx. + Label enough_stack_space, stack_overflow; + Generate_StackOverflowCheck(masm, rax, rcx, &stack_overflow, Label::kNear); + __ jmp(&enough_stack_space, Label::kNear); + + __ bind(&stack_overflow); + // Restore context from the frame. + __ movp(rsi, Operand(rbp, ConstructFrameConstants::kContextOffset)); + __ CallRuntime(Runtime::kThrowStackOverflow); + // This should be unreachable. + __ int3(); + + __ bind(&enough_stack_space); + // Copy arguments and receiver to the expression stack. Label loop, entry; __ movp(rcx, rax); @@ -315,25 +350,6 @@ void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) { __ CallRuntime(Runtime::kThrowConstructedNonConstructable); } -static void Generate_StackOverflowCheck( - MacroAssembler* masm, Register num_args, Register scratch, - Label* stack_overflow, - Label::Distance stack_overflow_distance = Label::kFar) { - // Check the stack for overflow. We are not trying to catch - // interruptions (e.g. debug break and preemption) here, so the "real stack - // limit" is checked. - __ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex); - __ movp(scratch, rsp); - // Make scratch the space we have left. The stack might already be overflowed - // here which will cause scratch to become negative. - __ subp(scratch, kScratchRegister); - __ sarp(scratch, Immediate(kPointerSizeLog2)); - // Check if the arguments will overflow the stack. - __ cmpp(scratch, num_args); - // Signed comparison. - __ j(less_equal, stack_overflow, stack_overflow_distance); -} - static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, bool is_construct) { ProfileEntryHookStub::MaybeCallEntryHook(masm); |