Chrome · V8
CVE-2026-14407
Logic Error in V8
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifsrc/codegen/arm64/macro-assembler-arm64.cc |
modified |
Files Changed
src/codegen/arm64/assembler-arm64.ccsrc/codegen/arm64/constants-arm64.hsrc/codegen/arm64/macro-assembler-arm64.ccsrc/codegen/arm64/reglist-arm64.hsrc/compiler/backend/arm64/code-generator-arm64.cc
Patch
From a769cf1ffbec4beb7d8a3f8a6e72a425cb08f3cc Mon Sep 17 00:00:00 2001 From: Igor Sheludko <[email protected]> Date: Wed, 27 May 2026 11:11:29 +0200 Subject: [PATCH] [arm64] Split Callee/CallerSaved FP register lists into D and V lists ... representing double and quad (128-bit SIMD) FP registers. This CL makes sure that SIMD registers are not corrupted by a call to C++ code by unconditionally saving/restoring them when Wasm support is enabled. TAG=agy Fixed: 513586956 Change-Id: I45d656a5851db72ca20bb98c0b9d25d4c00f4d36 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7876383 Commit-Queue: Igor Sheludko <[email protected]> Commit-Queue: Nico Hartmann <[email protected]> Auto-Submit: Igor Sheludko <[email protected]> Reviewed-by: Nico Hartmann <[email protected]> Cr-Commit-Position: refs/heads/main@{#107584} --- diff --git a/src/codegen/arm64/assembler-arm64.cc b/src/codegen/arm64/assembler-arm64.cc index bbfb671..f3309d3 100644 --- a/src/codegen/arm64/assembler-arm64.cc +++ b/src/codegen/arm64/assembler-arm64.cc @@ -232,28 +232,41 @@ DCHECK_EQ(Count() % 2, 0); } -CPURegList CPURegList::GetCalleeSaved(int size) { - return CPURegList(CPURegister::kRegister, size, 19, 28); +CPURegList CPURegList::GetCalleeSaved() { + return CPURegList(CPURegister::kRegister, kXRegSizeInBits, 19, 28); } -CPURegList CPURegList::GetCalleeSavedV(int size) { - return CPURegList(CPURegister::kVRegister, size, 8, 15); +CPURegList CPURegList::GetCalleeSavedD() { + // AAPCS64 only requires the callee to preserve d8-d15 which are the + // *lower* 64 bits of v8-v15. + return CPURegList(CPURegister::kVRegister, kDRegSizeInBits, 8, 15); } -CPURegList CPURegList::GetCallerSaved(int size) { +CPURegList CPURegList::GetCalleeSavedV() { + return CPURegList(kQRegSizeInBits, Simd128RegList{}); +} + +CPURegList CPURegList::GetCallerSaved() { // x18 is the platform register and is reserved for the use of platform ABIs. // Registers x0-x17 are caller-saved. - CPURegList list = CPURegList(CPURegister::kRegister, size, 0, 17); + CPURegList list = CPURegList(CPURegister::kRegister, kXRegSizeInBits, 0, 17); return list; } -CPURegList CPURegList::GetCallerSavedV(int size) { +CPURegList CPURegList::GetCallerSavedD() { // Registers d0-d7 and d16-d31 are caller-saved. - CPURegList list = CPURegList(CPURegister::kVRegister, size, 0, 7); - list.Combine(CPURegList(CPURegister::kVRegister, size, 16, 31)); + CPURegList list = CPURegList(CPURegister::kVRegister, kDRegSizeInBits, 0, 7); + list.Combine(CPURegList(CPURegister::kVRegister, kDRegSizeInBits, 16, 31)); return list; } +CPURegList CPURegList::GetCallerSavedV() { + // AAPCS64 only requires the callee to preserve the *lower* 64 bits of v8-v15 + // (which are essentially the d8-d15 registers), thus all V registers are + // caller-saved. + return CPURegList(CPURegister::kVRegister, kQRegSizeInBits, 0, 31); +} + // ----------------------------------------------------------------------------- // Implementation of RelocInfo diff --git a/src/codegen/arm64/constants-arm64.h b/src/codegen/arm64/constants-arm64.h index ed9531d..6417831 100644 --- a/src/codegen/arm64/constants-arm64.h +++ b/src/codegen/arm64/constants-arm64.h @@ -44,7 +44,11 @@ // Callee saved registers are x19-x28. constexpr int kNumberOfCalleeSavedRegisters = 10; // Callee saved FP registers are d8-d15. -constexpr int kNumberOfCalleeSavedVRegisters = 8; +constexpr int kNumberOfCalleeSavedDRegisters = 8; +// AAPCS64 only requires the callee to preserve the *lower* 64 bits of v8-v15 +// (which are essentially the d8-d15 registers), thus none of the 128-bit +// V registers are callee-saved. +constexpr int kNumberOfCalleeSavedVRegisters = 0; constexpr int kWRegSizeInBits = 32; constexpr int kWRegSizeInBitsLog2 = 5; constexpr int kWRegSize = kWRegSizeInBits >> 3; diff --git a/src/codegen/arm64/macro-assembler-arm64.cc b/src/codegen/arm64/macro-assembler-arm64.cc index 398aa35..9d4ae75 100644 --- a/src/codegen/arm64/macro-assembler-arm64.cc +++ b/src/codegen/arm64/macro-assembler-arm64.cc @@ -49,9 +49,9 @@ // For WebAssembly we care about the full floating point register. If we are not // running Wasm, we can get away with saving half of those registers. #if V8_ENABLE_WEBASSEMBLY -constexpr int kStackSavedSavedFPSizeInBits = kQRegSizeInBits; +constexpr bool kSaveFullFPRegistersOnStack = true; #else -constexpr int kStackSavedSavedFPSizeInBits = kDRegSizeInBits; +constexpr bool kSaveFullFPRegistersOnStack = false; #endif // V8_ENABLE_WEBASSEMBLY } // namespace @@ -147,7 +147,11 @@ int bytes = list.TotalSizeInBytes(); if (fp_mode == SaveFPRegsMode::kSave) { - auto fp_list = CPURegList::GetCallerSavedV(kStackSavedSavedFPSizeInBits); + // TODO(all): consider splitting SaveFPRegsMode::kSave into kSaveFPOnly + // and kSaveFPAndSIMD. The former is useful for those functions that don't + // use SIMD registers. + auto fp_list = kSaveFullFPRegistersOnStack ? CPURegList::GetCallerSavedV() + : CPURegList::GetCallerSavedD(); DCHECK_EQ(fp_list.Count() % 2, 0); bytes += fp_list.TotalSizeInBytes(); } @@ -166,7 +170,11 @@ int bytes = list.TotalSizeInBytes(); if (fp_mode == SaveFPRegsMode::kSave) { - auto fp_list = CPURegList::GetCallerSavedV(kStackSavedSavedFPSizeInBits); + // TODO(all): consider splitting SaveFPRegsMode::kSave into kSaveFPOnly + // and kSaveFPAndSIMD. The former is useful for those functions that don't + // use SIMD registers. + auto fp_list = kSaveFullFPRegistersOnStack ? CPURegList::GetCallerSavedV() + : CPURegList::GetCallerSavedD(); DCHECK_EQ(fp_list.Count() % 2, 0); PushCPURegList(fp_list); bytes += fp_list.TotalSizeInBytes(); @@ -178,7 +186,11 @@ ASM_CODE_COMMENT(this); int bytes = 0; if (fp_mode == SaveFPRegsMode::kSave) { - auto fp_list = CPURegList::GetCallerSavedV(kStackSavedSavedFPSizeInBits); + // TODO(all): consider splitting SaveFPRegsMode::kSave into kSaveFPOnly + // and kSaveFPAndSIMD. The former is useful for those functions that don't + // use SIMD registers. + auto fp_list = kSaveFullFPRegistersOnStack ? CPURegList::GetCallerSavedV() + : CPURegList::GetCallerSavedD(); DCHECK_EQ(fp_list.Count() % 2, 0); PopCPURegList(fp_list); bytes += fp_list.TotalSizeInBytes(); diff --git a/src/codegen/arm64/reglist-arm64.h b/src/codegen/arm64/reglist-arm64.h index 64a3fb2..9af1f83 100644 --- a/src/codegen/arm64/reglist-arm64.h +++ b/src/codegen/arm64/reglist-arm64.h @@ -99,14 +99,19 @@ CPURegister PopHighestIndex(); // AAPCS64 callee-saved registers. - static CPURegList GetCalleeSaved(int size = kXRegSizeInBits); - static CPURegList GetCalleeSavedV(int size = kDRegSizeInBits); + static CPURegList GetCalleeSaved(); + // Note that D registers are the lower 64-bit parts of respective V + // registers. + static CPURegList GetCalleeSavedD(); + static CPURegList GetCalleeSavedV(); // AAPCS64 caller-saved registers. Note that this includes lr. - // TODO(all): Determine how we handle d8-d15 being callee-saved, but the top - // 64-bits being caller-saved. - static CPURegList GetCallerSaved(int size = kXRegSizeInBits); - static CPURegList GetCallerSavedV(int size = kDRegSizeInBits); + static CPURegList GetCallerSaved(); + // Note that D registers are the lower 64-bit parts of respective V + // registers. Thus there's no need to save both D and V registers, saving + // just V registers is enough. + static CPURegList GetCallerSavedD(); + static CPURegList GetCallerSavedV(); bool IsEmpty() const { return list_ == 0; } @@ -163,10 +168,12 @@ // AAPCS64 callee-saved registers. #define kCalleeSaved CPURegList::GetCalleeSaved() +#define kCalleeSavedD CPURegList::GetCalleeSavedD() #define kCalleeSavedV CPURegList::GetCalleeSavedV() // AAPCS64 caller-saved registers. Note that this includes lr. #define kCallerSaved CPURegList::GetCallerSaved() +#define kCallerSavedD CPURegList::GetCallerSavedD() #define kCallerSavedV CPURegList::GetCallerSavedV() } // namespace internal diff --git a/src/compiler/backend/arm64/code-generator-arm64.cc b/src/compiler/backend/arm64/code-generator-arm64.cc index 3354b5e..4c750a6 100644 --- a/src/compiler/backend/arm64/code-generator-arm64.cc +++ b/src/compiler/backend/arm64/code-generator-arm64.cc @@ -4255,7 +4255,9 @@ CPURegList(kDRegSizeInBits, call_descriptor->CalleeSavedFPRegisters()); int saved_count = saves_fp.Count();
Loading diff…
Original Bug Report
The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.
References
On This Page