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)