diff --git a/src/js_native_api_v8.cpp b/src/js_native_api_v8.cpp index 166d472e8912b77d6d1968e54695451ff0ec3928..598daa4222a40edc5dbe88c493fc0f566ba44745 100644 --- a/src/js_native_api_v8.cpp +++ b/src/js_native_api_v8.cpp @@ -4789,6 +4789,7 @@ JSVM_Status OH_JSVM_RetainScript(JSVM_Env env, JSVM_Script script) jsvmData->taggedPointer = v8::Global(env->isolate, jsvmData->ToV8Local(env->isolate)); + env->RetainJsvmData(jsvmData); jsvmData->isGlobal = true; return ClearLastError(env); } diff --git a/src/jsvm_env.h b/src/jsvm_env.h index 7f28702de8345b8a70d178f8ac3ac921d90af95a..3032048d8322b67594a919a7fa48bf9f3c1cc8e0 100644 --- a/src/jsvm_env.h +++ b/src/jsvm_env.h @@ -16,6 +16,7 @@ #ifndef JSVM_ENV_H #define JSVM_ENV_H #include +#include #include #include @@ -133,25 +134,37 @@ public: template JSVM_Script_Data__* NewJsvmData(T srcPtr, JSVM_Script_Data__::DataType type = JSVM_Script_Data__::kJsvmScript) { - if (dataStack.empty() || openHandleScopes != dataStack.top().first) { - dataStack.emplace(openHandleScopes, std::vector()); + if (dataStack.size() == 0 || openHandleScopes != dataStack.back().first) { + dataStack.emplace_back(openHandleScopes, std::list()); } auto newData = new JSVM_Script_Data__(srcPtr, false, type); - dataStack.top().second.push_back(newData); + dataStack.back().second.push_back(newData); return newData; } void ReleaseJsvmData() { - if (dataStack.empty() || openHandleScopes != dataStack.top().first) { + if (dataStack.size() == 0 || openHandleScopes != dataStack.back().first) { return; } - for (auto data : dataStack.top().second) { + for (auto data : dataStack.back().second) { if (!data->isGlobal) { delete data; } } - dataStack.pop(); + dataStack.pop_back(); + } + + void RetainJsvmData(JSVM_Script_Data__* data) + { + for (auto iter = dataStack.rbegin(); iter != dataStack.rend(); ++iter) { + auto& current = iter->second; + auto globalData = std::find(current.begin(), current.end(), data); + if (globalData != current.end()) { + current.erase(globalData); + break; + } + } } void CreateScopeTracker() @@ -183,7 +196,7 @@ public: JSVM_ExtendedErrorInfo lastError; // Store v8::Data - std::stack>> dataStack; + std::vector>> dataStack; // Store external instance data void* instanceData = nullptr; diff --git a/test/unittest/test_jsvm.cpp b/test/unittest/test_jsvm.cpp index dd8af68a8b874cce33ab23d518809479a2ec0a45..b9876b189f257a170c03ca922b828d26ac9eecb9 100644 --- a/test/unittest/test_jsvm.cpp +++ b/test/unittest/test_jsvm.cpp @@ -1609,4 +1609,26 @@ HWTEST_F(JSVMTest, test_set_debug_option3, TestSize.Level1) OH_JSVM_CloseHandleScope(env, handleScope); auto status2 = OH_JSVM_SetDebugOption(env, JSVM_SCOPE_CHECK, false); ASSERT_TRUE(status2 == JSVM_OK); +} + +HWTEST_F(JSVMTest, JSVMCloseHandleScopeUAF, TestSize.Level1) +{ + JSVM_HandleScope handle = nullptr; + JSVMTEST_CALL(OH_JSVM_OpenHandleScope(env, &handle)); + + JSVM_Value jsSrc = nullptr; + JSVMTEST_CALL(OH_JSVM_CreateStringUtf8(env, srcProf.c_str(), srcProf.size(), &jsSrc)); + + bool cacheRejected = true; + JSVM_Script script = nullptr; + JSVMTEST_CALL(OH_JSVM_CompileScript(env, jsSrc, nullptr, 0, true, &cacheRejected, &script)); + + JSVMTEST_CALL(OH_JSVM_RetainScript(env, script)); + JSVMTEST_CALL(OH_JSVM_ReleaseScript(env, script)); + + const int length = 32; + char* data = new((char *)script) char[length]; + memset(data, 0, length); + + JSVMTEST_CALL(OH_JSVM_CloseHandleScope(env, handle)); } \ No newline at end of file