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 <ishell@chromium.org>
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 <ishell@chromium.org>
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Auto-Submit: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
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