|
| 1 | +#include "qjs_sanitizer.h" |
| 2 | + |
| 3 | +#include "blook/hook.h" |
| 4 | +#include "quickjs.h" |
| 5 | +#include <blook/blook.h> |
| 6 | +#include <mutex> |
| 7 | +#include <string> |
| 8 | +#include <unordered_map> |
| 9 | +#include <thread> |
| 10 | + |
| 11 | +#define FN(name) {#name, (void *)&name} |
| 12 | +static const std::unordered_map<std::string, void *> func_to_hook = { |
| 13 | + FN(JS_NewObject), |
| 14 | + FN(JS_NewArray), |
| 15 | + FN(JS_NewCFunction), |
| 16 | + FN(JS_NewCFunctionData), |
| 17 | + FN(JS_NewPromiseCapability), |
| 18 | + FN(JS_NewString), |
| 19 | + FN(JS_NewObjectProto), |
| 20 | + FN(JS_NewArrayBuffer), |
| 21 | + FN(JS_NewDate), |
| 22 | + FN(JS_NewSymbol), |
| 23 | + FN(JS_NewArrayBufferCopy), |
| 24 | + FN(JS_NewTypedArray), |
| 25 | + FN(JS_NewUint8Array), |
| 26 | + FN(JS_NewUint8ArrayCopy), |
| 27 | + FN(JS_NewCFunction2), |
| 28 | + FN(JS_NewCFunction3), |
| 29 | + FN(JS_NewCFunctionData2), |
| 30 | + FN(JS_NewCModule), |
| 31 | + FN(JS_ParseJSON), |
| 32 | + FN(JS_JSONStringify), |
| 33 | + FN(JS_WriteObject), |
| 34 | + FN(JS_ReadObject), |
| 35 | + FN(JS_EvalFunction), |
| 36 | + FN(JS_LoadModule), |
| 37 | + FN(JS_SetConstructor), |
| 38 | + FN(JS_SetPropertyFunctionList), |
| 39 | + FN(JS_AddModuleExport), |
| 40 | + FN(JS_AddModuleExportList), |
| 41 | + FN(JS_SetModuleExport), |
| 42 | + FN(JS_SetModuleExportList), |
| 43 | + FN(JS_FreeContext), |
| 44 | + FN(JS_DupContext), |
| 45 | + FN(JS_SetContextOpaque), |
| 46 | + FN(JS_GetContextOpaque), |
| 47 | + FN(JS_GetRuntime), |
| 48 | + FN(JS_SetClassProto), |
| 49 | + FN(JS_GetClassProto), |
| 50 | + FN(JS_GetFunctionProto), |
| 51 | + FN(JS_AddIntrinsicBaseObjects), |
| 52 | + FN(JS_AddIntrinsicDate), |
| 53 | + FN(JS_AddIntrinsicEval), |
| 54 | + FN(JS_AddIntrinsicRegExpCompiler), |
| 55 | + FN(JS_AddIntrinsicRegExp), |
| 56 | + FN(JS_AddIntrinsicJSON), |
| 57 | + FN(JS_AddIntrinsicProxy), |
| 58 | + FN(JS_AddIntrinsicMapSet), |
| 59 | + FN(JS_AddIntrinsicTypedArrays), |
| 60 | + FN(JS_AddIntrinsicPromise), |
| 61 | + FN(JS_AddIntrinsicBigInt), |
| 62 | + FN(JS_AddIntrinsicWeakRef), |
| 63 | + FN(JS_AddPerformance), |
| 64 | + FN(JS_AddIntrinsicDOMException), |
| 65 | + FN(JS_IsEqual), |
| 66 | + FN(JS_IsStrictEqual), |
| 67 | + FN(JS_IsSameValue), |
| 68 | + FN(JS_IsSameValueZero), |
| 69 | + FN(JS_Throw), |
| 70 | + FN(JS_GetException), |
| 71 | + FN(JS_HasException), |
| 72 | + FN(JS_SetUncatchableError), |
| 73 | + FN(JS_ClearUncatchableError), |
| 74 | + FN(JS_ResetUncatchableError), |
| 75 | + FN(JS_NewError), |
| 76 | + FN(JS_NewInternalError), |
| 77 | + FN(JS_NewPlainError), |
| 78 | + FN(JS_NewRangeError), |
| 79 | + FN(JS_NewReferenceError), |
| 80 | + FN(JS_NewSyntaxError), |
| 81 | + FN(JS_NewTypeError), |
| 82 | + FN(JS_ThrowInternalError), |
| 83 | + FN(JS_ThrowPlainError), |
| 84 | + FN(JS_ThrowRangeError), |
| 85 | + FN(JS_ThrowReferenceError), |
| 86 | + FN(JS_ThrowSyntaxError), |
| 87 | + FN(JS_ThrowTypeError), |
| 88 | + FN(JS_ThrowDOMException), |
| 89 | + FN(JS_ThrowOutOfMemory), |
| 90 | + FN(JS_FreeValue), |
| 91 | + FN(JS_DupValue), |
| 92 | + FN(JS_ToBool), |
| 93 | + FN(JS_ToNumber), |
| 94 | + FN(JS_ToInt32), |
| 95 | + FN(JS_ToInt64), |
| 96 | + FN(JS_ToIndex), |
| 97 | + FN(JS_ToFloat64), |
| 98 | + FN(JS_ToBigInt64), |
| 99 | + FN(JS_ToBigUint64), |
| 100 | + FN(JS_ToInt64Ext), |
| 101 | + FN(JS_NewStringLen), |
| 102 | + FN(JS_NewTwoByteString), |
| 103 | + FN(JS_NewAtomString), |
| 104 | + FN(JS_ToString), |
| 105 | + FN(JS_ToPropertyKey), |
| 106 | + FN(JS_ToCStringLen2), |
| 107 | + FN(JS_FreeCString), |
| 108 | + FN(JS_NewObjectProtoClass), |
| 109 | + FN(JS_NewObjectClass), |
| 110 | + FN(JS_NewObjectFrom), |
| 111 | + FN(JS_NewObjectFromStr), |
| 112 | + FN(JS_ToObject), |
| 113 | + FN(JS_ToObjectString), |
| 114 | + FN(JS_IsFunction), |
| 115 | + FN(JS_IsConstructor), |
| 116 | + FN(JS_SetConstructorBit), |
| 117 | + FN(JS_NewArrayFrom), |
| 118 | + FN(JS_GetProxyTarget), |
| 119 | + FN(JS_GetProxyHandler), |
| 120 | + FN(JS_GetProperty), |
| 121 | + FN(JS_GetPropertyUint32), |
| 122 | + FN(JS_GetPropertyInt64), |
| 123 | + FN(JS_GetPropertyStr), |
| 124 | + FN(JS_SetProperty), |
| 125 | + FN(JS_SetPropertyUint32), |
| 126 | + FN(JS_SetPropertyInt64), |
| 127 | + FN(JS_SetPropertyStr), |
| 128 | + FN(JS_HasProperty), |
| 129 | + FN(JS_IsExtensible), |
| 130 | + FN(JS_PreventExtensions), |
| 131 | + FN(JS_DeleteProperty), |
| 132 | + FN(JS_SetPrototype), |
| 133 | + FN(JS_GetPrototype), |
| 134 | + FN(JS_GetLength), |
| 135 | + FN(JS_SetLength), |
| 136 | + FN(JS_SealObject), |
| 137 | + FN(JS_FreezeObject), |
| 138 | + FN(JS_GetOwnPropertyNames), |
| 139 | + FN(JS_GetOwnProperty), |
| 140 | + FN(JS_FreePropertyEnum), |
| 141 | + FN(JS_Call), |
| 142 | + FN(JS_Invoke), |
| 143 | + FN(JS_CallConstructor), |
| 144 | + FN(JS_CallConstructor2), |
| 145 | + FN(JS_Eval), |
| 146 | + FN(JS_Eval2), |
| 147 | + FN(JS_EvalThis), |
| 148 | + FN(JS_EvalThis2), |
| 149 | + FN(JS_GetGlobalObject), |
| 150 | + FN(JS_IsInstanceOf), |
| 151 | + FN(JS_DefineProperty), |
| 152 | + FN(JS_DefinePropertyValue), |
| 153 | + FN(JS_DefinePropertyValueUint32), |
| 154 | + FN(JS_DefinePropertyValueStr), |
| 155 | + FN(JS_DefinePropertyGetSet), |
| 156 | + FN(JS_GetOpaque2), |
| 157 | + FN(JS_DetachArrayBuffer), |
| 158 | + FN(JS_GetArrayBuffer), |
| 159 | + FN(JS_GetUint8Array), |
| 160 | + FN(JS_GetTypedArrayBuffer), |
| 161 | + FN(JS_PromiseState), |
| 162 | + FN(JS_PromiseResult), |
| 163 | + FN(JS_SetIsHTMLDDA), |
| 164 | + FN(JS_GetImportMeta), |
| 165 | + FN(JS_GetModuleName), |
| 166 | + FN(JS_GetModuleNamespace), |
| 167 | + FN(JS_EnqueueJob), |
| 168 | + FN(JS_WriteObject2), |
| 169 | + FN(JS_ReadObject2), |
| 170 | + FN(JS_ResolveModule), |
| 171 | + FN(JS_GetScriptOrModuleName), |
| 172 | +}; |
| 173 | + |
| 174 | +static std::mutex thread_context_map_mutex; |
| 175 | +static std::unordered_map<JSContext *, std::thread::id> thread_context_map; |
| 176 | + |
| 177 | +void mb_shell::qjs_sanitizer_enable() { |
| 178 | + for (const auto &[name, addr] : func_to_hook) { |
| 179 | + blook::VEHHookManager::instance().add_breakpoint( |
| 180 | + blook::VEHHookManager::SoftwareBreakpoint { |
| 181 | + .address = addr |
| 182 | + }, [name](blook::VEHHookManager::VEHHookContext &ctx) { |
| 183 | + std::lock_guard lock(thread_context_map_mutex); |
| 184 | + auto js_ctx = reinterpret_cast<JSContext *>(ctx.exception_info->ContextRecord->Rcx); |
| 185 | + if (thread_context_map.find(js_ctx) == thread_context_map.end()) { |
| 186 | + thread_context_map[js_ctx] = std::this_thread::get_id(); |
| 187 | + } else { |
| 188 | + auto existing_thread_id = thread_context_map[js_ctx]; |
| 189 | + if (existing_thread_id != std::this_thread::get_id()) { |
| 190 | + // Detected cross-thread JS context access |
| 191 | + std::cerr << "Detected cross-thread access to JSContext in function " << name << std::endl; |
| 192 | + } |
| 193 | + } |
| 194 | + } |
| 195 | + ); |
| 196 | + } |
| 197 | +} |
0 commit comments