CVE-2024-27833
Overview
Advisory: Apple Security Advisory
Impact:
Description: Processing maliciously crafted web content may lead to arbitrary code execution
Researchers: Manfred Paul (@_manfp) working with Trend Micro Zero Day Initiative
| Attribute | Value |
|---|---|
| CVE | CVE-2024-27833 |
| Bugzilla | 271491 |
| Component | JSC |
| Bug Class | IntegerOverflow |
| Severity | critical |
| Commit | 1ea4ef8127276fd0… |
| Advisory | Apple Advisory |
Root Cause Analysis
An integer overflow was addressed with improved input validation.
Files Changed
Source Files
Source/JavaScriptCore/b3/B3LowerToAir.cpp
Test Files
JSTests/stress/sbfx-offset-overflow.js
Patch Preview
diff --git a/JSTests/stress/sbfx-offset-overflow.js b/JSTests/stress/sbfx-offset-overflow.js
new file mode 100644
index 000000000000..9d7f7cd7790a
--- /dev/null
+++ b/JSTests/stress/sbfx-offset-overflow.js
@@ -0,0 +1,16 @@
+function foo(a,b,c) { let x = a | 0; let y = b | 0; let z = c &15;
+z = (x<<y)^(x<<(y&0x10ff)); let r = z^0xf01;
+let s = z^0xf1f;
+return (((a>>>r)<<s)>>s);
+}
+let LEN = 100000000-1;
+let res = 0;
+res = foo((LEN&127),456,789);
+
+if (res != -1)
+ throw "Wrong result: " + res
+
+for (let i = 0; i <= LEN; i++) res = foo((i&127),456,789);
+
+if (res != -1)
+ throw "Wrong result: " + res
\ No newline at end of file
diff --git a/Source/JavaScriptCore/b3/B3LowerToAir.cpp b/Source/JavaScriptCore/b3/B3LowerToAir.cpp
index 33adcbd1c25a..e8ff89dc84c7 100644
--- a/Source/JavaScriptCore/b3/B3LowerToAir.cpp
+++ b/Source/JavaScriptCore/b3/B3LowerToAir.cpp
@@ -3301,7 +3301,8 @@ class LowerToAir {
return false;
uint64_t width = WTF::bitCount(mask);
uint64_t datasize = opcode == ExtractUnsignedBitfield32 ? 32 : 64;
- if (lsb + width > datasize)
+ uint64_t resultDataSize = 0;
+ if (!WTF::safeAdd(lsb, width, resultDataSize) || resultDataSize > datasize)
return false;
append(opcode, tmp(srcValue), imm(lsbValue), imm(width), tmp(m_value));
@@ -3390,9 +3391,8 @@ class LowerToAir {
uint64_t highWidth = highWidthValue->asInt();
uint64_t lowWidth = lowWidthValue->asInt();
uint64_t datasize = opcode == ExtractRegister32 ? 32 : 64;
- // Note that when `lowWidth == datasize` we cannot turn it to `MOV Rd Rn` since
- // `m >>> lowWidth` means `m >>> (lowWidth % datasize)` in JavaScript.
- if (lowWidth + highWidth != datasize || maskBitCount != lowWidth || lowWidth == datasize)
+ uint64_t resultWidth = 0;
+ if (!WTF::safeAdd(lowWidth, highWidth, resultWidth) || resultWidth != datasize || maskBitCount != lowWidth || lowWidth == datasize)
return false;
ASSERT(lowWidth < datasize);
@@ -3429,7 +3429,8 @@ class LowerToAir {
return false;
uint64_t datasize = opcode == InsertBitField32 ? 32 : 64;
uint64_t width = WTF::bitCount(mask1);
- if (lsb + width > datasize)
+ uint64_t resultDataSize = 0;
+ if (!WTF::safeAdd(lsb, width, resultDataSize) || resultDataSize > datasize)
return false;
uint64_t mask2 = maskValue2->asInt();
@@ -3479,7 +3480,8 @@ class LowerToAir {
return false;
uint64_t width = WTF::bitCount(mask1);
uint64_t datasize = opcode == ExtractInsertBitfieldAtLowEnd32 ? 32 : 64;
- if (lsb + width > datasize)
+ uint64_t resultDataSize = 0;
+ if (!WTF::safeAdd(lsb, width, resultDataSize) || resultDataSize > datasize)
return false;
uint64_t mask2 = maskValue2->asInt();
@@ -3653,7 +3655,8 @@ class LowerToAir {
uint64_t width = WTF::bitCount(mask);
uint64_t datasize = opcode == InsertUnsignedBitfieldInZero32 ? 32 : 64;
- if (lsb + width > datasize)
+ uint64_t resultDataSize = 0;
+ if (!WTF::safeAdd(lsb, width, resultDataSize) || resultDataSize > datasize)
return false;
append(opcode, tmp(nValue), imm(right), imm(width), tmp(m_value));
@@ -3715,8 +3718,13 @@ class LowerToAir {
uint64_t amount2 = amount2Value->asInt();
uint64_t lsb = lsbValue->asInt();
uint64_t datasize = opcode == InsertSignedBitfieldInZero32 ? 32 : 64;
+
+ if (amount1 >= datasize)
+ return false;
+
uint64_t width = datasize - amount1;
- if (amount1 != amount2 || !width || lsb + width > datasize)
+ uint64_t resultDataSize = 0;
+ if (!WTF::safeAdd(lsb, width, resultDataSize) || amount1 != amount2 || !width || resultDataSize > datasize)
return false;
append(opcode, tmp(srcValue), imm(lsbValue), imm(width), tmp(m_value));
@@ -3763,8 +3771,13 @@ class LowerToAir {
uint64_t amount2 = amount2Value->asInt();
uint64_t lsb = lsbValue->asInt();
uint64_t datasize = opcode == ExtractSignedBitfield32 ? 32 : 64;
+
+ if (amount1 >= datasize)