diff --git a/frameworks/native/runtime/js_runtime.cpp b/frameworks/native/runtime/js_runtime.cpp index 0bf227ee2b..0059900285 100644 --- a/frameworks/native/runtime/js_runtime.cpp +++ b/frameworks/native/runtime/js_runtime.cpp @@ -1464,15 +1464,18 @@ void JsRuntime::InitWorkerModule(const Options& options) { CHECK_POINTER(jsEnv_); std::shared_ptr workerInfo = std::make_shared(); - workerInfo->codePath = options.codePath; + // workerInfo->codePath = options.codePath; + workerInfo->codePath = JsEnv::StringPacProtect(options.codePath); workerInfo->isDebugVersion = options.isDebugVersion; workerInfo->isBundle = options.isBundle; workerInfo->packagePathStr = options.packagePathStr; workerInfo->assetBasePathStr = options.assetBasePathStr; - workerInfo->hapPath = options.hapPath; + // workerInfo->hapPath = options.hapPath; + workerInfo->hapPath = JsEnv::StringPacProtect(options.hapPath); workerInfo->isStageModel = options.isStageModel; workerInfo->moduleName = options.moduleName; - workerInfo->apiTargetVersion = options.apiTargetVersion; + // workerInfo->apiTargetVersion = options.apiTargetVersion; + workerInfo->apiTargetVersion = JsEnv::DataProtect(static_cast(options.apiTargetVersion)); if (options.isJsFramework) { SetJsFramework(); } diff --git a/frameworks/native/runtime/js_worker.cpp b/frameworks/native/runtime/js_worker.cpp index 3ef23282e5..44817e9b40 100644 --- a/frameworks/native/runtime/js_worker.cpp +++ b/frameworks/native/runtime/js_worker.cpp @@ -211,7 +211,7 @@ void AssetHelper::operator()(const std::string& uri, uint8_t** buff, size_t* buf if (!workerInfo_->isStageModel) { GetAmi(ami, filePath); } else { - ami = workerInfo_->codePath + filePath; + ami = (workerInfo_->codePath).GetOriginString() + filePath; } TAG_LOGD(AAFwkTag::JSRUNTIME, "Get asset, ami: %{private}s", ami.c_str()); @@ -252,10 +252,11 @@ void AssetHelper::operator()(const std::string& uri, uint8_t** buff, size_t* buf filePath = NormalizedFileName(realPath); // for safe reason, filePath must starts with 'abcs/' in restricted env - if (isRestricted && filePath.find(RESTRICTED_PREFIX_PATH) && workerInfo_->apiTargetVersion >= API12) { + if (isRestricted && filePath.find(RESTRICTED_PREFIX_PATH) + && (static_cast(workerInfo_->apiTargetVersion.GetOriginPointer())) >= API12) { filePath = RESTRICTED_PREFIX_PATH + filePath; } - ami = workerInfo_->codePath + filePath; + ami = (workerInfo_->codePath).GetOriginString() + filePath; TAG_LOGD(AAFwkTag::JSRUNTIME, "Get asset, ami: %{private}s", ami.c_str()); if (ami.find(CACHE_DIRECTORY) != std::string::npos) { if (!ReadAmiData(ami, buff, buffSize, content, useSecureMem, isRestricted)) { @@ -316,9 +317,10 @@ bool AssetHelper::ReadAmiData(const std::string& ami, uint8_t** buff, size_t* bu bool& useSecureMem, bool isRestricted) { // Current function is a private, validity of workerInfo_ has been checked by caller. - bool apiSatisfy = workerInfo_->apiTargetVersion == 0 || workerInfo_->apiTargetVersion > API8; + int32_t apiTargetVersion = static_cast(workerInfo_->apiTargetVersion.GetOriginPointer()); + bool apiSatisfy = apiTargetVersion == 0 || apiTargetVersion > API8; if (workerInfo_->isStageModel && !isRestricted && apiSatisfy) { - if (workerInfo_->apiTargetVersion >= API12) { + if (apiTargetVersion >= API12) { useSecureMem = true; return GetSafeData(ami, buff, buffSize); } else if (GetSafeData(ami, buff, buffSize)) { @@ -383,7 +385,7 @@ bool AssetHelper::ReadFilePathData(const std::string& filePath, uint8_t** buff, std::string newHapPath; size_t pos = filePath.find('/'); if (!workerInfo_->isStageModel) { - newHapPath = workerInfo_->hapPath; + newHapPath = (workerInfo_->hapPath).GetOriginString(); } else { for (auto hapModuleInfo : bundleInfo.hapModuleInfos) { if (hapModuleInfo.moduleName == filePath.substr(0, pos)) { @@ -420,11 +422,12 @@ bool AssetHelper::ReadFilePathData(const std::string& filePath, uint8_t** buff, } else { realfilePath = filePath.substr(pos + 1); TAG_LOGD(AAFwkTag::JSRUNTIME, "realfilePath: %{private}s", realfilePath.c_str()); - bool apiSatisfy = workerInfo_->apiTargetVersion == 0 || workerInfo_->apiTargetVersion > API8; + int32_t apiTargetVersion = static_cast(workerInfo_->apiTargetVersion.GetOriginPointer()); + bool apiSatisfy = apiTargetVersion == 0 || apiTargetVersion > API8; if (workerInfo_->isStageModel && !isRestricted && apiSatisfy && !extractor->IsHapCompress(realfilePath)) { TAG_LOGD(AAFwkTag::JSRUNTIME, "Use secure mem."); auto safeData = extractor->GetSafeData(realfilePath); - if (workerInfo_->apiTargetVersion >= API12) { + if (apiTargetVersion >= API12) { useSecureMem = true; if (safeData == nullptr) { TAG_LOGE(AAFwkTag::JSRUNTIME, "Get secure mem failed, file %{private}s.", filePath.c_str()); @@ -464,7 +467,7 @@ void AssetHelper::GetAmi(std::string& ami, const std::string& filePath) std::string fileName = filePath.substr(slashPos + 1); std::string path = filePath.substr(0, slashPos + 1); - std::string loadPath = ExtractorUtil::GetLoadFilePath(workerInfo_->hapPath); + std::string loadPath = ExtractorUtil::GetLoadFilePath((workerInfo_->hapPath).GetOriginString()); bool newCreate = false; std::shared_ptr extractor = ExtractorUtil::GetExtractor(loadPath, newCreate); if (extractor == nullptr) { @@ -509,7 +512,7 @@ void AssetHelper::GetAmi(std::string& ami, const std::string& filePath) std::string filePathName = basePath + targetFilePath; bool hasFile = extractor->HasEntry(filePathName); if (hasFile) { - ami = workerInfo_->hapPath + "/" + filePathName; + ami = (workerInfo_->hapPath).GetOriginString() + "/" + filePathName; return; } } diff --git a/frameworks/native/runtime/js_worker.h b/frameworks/native/runtime/js_worker.h index d9cd7a6a05..12bf1de9bf 100644 --- a/frameworks/native/runtime/js_worker.h +++ b/frameworks/native/runtime/js_worker.h @@ -35,8 +35,11 @@ class AssetHelper final { public: explicit AssetHelper(std::shared_ptr workerInfo) : workerInfo_(workerInfo) { - if (!(workerInfo_->codePath).empty() && (workerInfo->codePath).back() != '/') { - (workerInfo_->codePath).append("/"); + JsEnv::StringPacProtect codePath = JsEnv::StringPacProtect(workerInfo_->codePath); + if (!(codePath.GetOriginString()).empty() && (codePath.GetOriginString()).back() != '/') { + // (workerInfo_->codePath).append("/"); + // workerInfo_->codePath = StringPacProtect(codePath.append("/")); + (workerInfo_->codePath).Append("/"); } } diff --git a/frameworks/native/runtime/native_runtime_impl.cpp b/frameworks/native/runtime/native_runtime_impl.cpp index 1eccd3c66c..e50a3e0d4d 100644 --- a/frameworks/native/runtime/native_runtime_impl.cpp +++ b/frameworks/native/runtime/native_runtime_impl.cpp @@ -315,12 +315,14 @@ void NativeRuntimeImpl::InitWorkerModule(const Options& options, const std::shar } std::shared_ptr workerInfo = std::make_shared(); - workerInfo->codePath = options.codePath; + // workerInfo->codePath = options.codePath; + workerInfo->codePath = JsEnv::StringPacProtect(options.codePath); workerInfo->isDebugVersion = options.isDebugVersion; workerInfo->isBundle = options.isBundle; workerInfo->packagePathStr = options.packagePathStr; workerInfo->assetBasePathStr = options.assetBasePathStr; - workerInfo->hapPath = options.hapPath; + // workerInfo->hapPath = options.hapPath; + workerInfo->hapPath = JsEnv::StringPacProtect(options.hapPath); workerInfo->isStageModel = options.isStageModel; workerInfo->moduleName = options.moduleName; if (options.isJsFramework) { diff --git a/frameworks/native/runtime/ohos_js_environment_impl.cpp b/frameworks/native/runtime/ohos_js_environment_impl.cpp index 1936f15a87..d44ee7e0a0 100644 --- a/frameworks/native/runtime/ohos_js_environment_impl.cpp +++ b/frameworks/native/runtime/ohos_js_environment_impl.cpp @@ -172,7 +172,7 @@ void OHOSJsEnvironmentImpl::InitWorkerModule(NativeEngine* engine, std::shared_p engine->SetInitWorkerFunc(InitWorkerFunc); engine->SetOffWorkerFunc(OffWorkerFunc); engine->SetGetAssetFunc(AssetHelper(workerInfo)); - engine->SetApiVersion(workerInfo->apiTargetVersion); + engine->SetApiVersion(static_cast(workerInfo->apiTargetVersion.GetOriginPointer())); engine->SetGetContainerScopeIdFunc(GetContainerId); engine->SetInitContainerScopeFunc(UpdateContainerScope); diff --git a/interfaces/inner_api/runtime/BUILD.gn b/interfaces/inner_api/runtime/BUILD.gn index 6c5033cfde..db9fab0f49 100644 --- a/interfaces/inner_api/runtime/BUILD.gn +++ b/interfaces/inner_api/runtime/BUILD.gn @@ -33,6 +33,8 @@ config("runtime_config") { } include_dirs = [] + + cflags_cc = [ "-march=armv8.3a" ] } config("runtime_public_config") { diff --git a/js_environment/frameworks/js_environment/BUILD.gn b/js_environment/frameworks/js_environment/BUILD.gn index 177d74f080..c97574f375 100644 --- a/js_environment/frameworks/js_environment/BUILD.gn +++ b/js_environment/frameworks/js_environment/BUILD.gn @@ -17,6 +17,7 @@ import("../../js_environment.gni") config("js_environment_config") { include_dirs = [ "${inner_api_path}" ] + cflags_cc = [ "-march=armv8.3a" ] } config("public_js_environment_config") { @@ -29,6 +30,7 @@ config("public_js_environment_config") { ohos_shared_library("js_environment") { sources = [ + "${utils_path}/src/data_protect.cpp", "${utils_path}/src/js_env_logger.cpp", "src/js_environment.cpp", "src/source_map.cpp", diff --git a/js_environment/frameworks/utils/include/data_protect.h b/js_environment/frameworks/utils/include/data_protect.h new file mode 100644 index 0000000000..fb4a0e2601 --- /dev/null +++ b/js_environment/frameworks/utils/include/data_protect.h @@ -0,0 +1,305 @@ +/** + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBPANDAFILE_DATA_PROTECT_H +#define LIBPANDAFILE_DATA_PROTECT_H + +#include +#include +#include +#include +#include + +namespace OHOS { +namespace JsEnv { + +class DataProtect { +public: + DataProtect() : protect_pointer_(0) {} + explicit DataProtect(const uintptr_t pointer) + { + if (pointer == 0) { + protect_pointer_ = 0; + return; + } + protect_pointer_ = DataProtectPac(pointer, reinterpret_cast(&protect_pointer_)); + } + + ~DataProtect() = default; + + static bool CheckPacSupport(); + + static inline uintptr_t DataProtectAut(const uintptr_t pointer, + [[maybe_unused]]const uintptr_t address) + { +#if defined(PANDA_TARGET_ARM64) + // todo: print t1, t2 + if (!isSupportPacA_) { + return pointer; + } + void *t1 = reinterpret_cast(pointer); + void *t2 = reinterpret_cast(address); +#ifdef PAC_DFI_PTR_BKEY + __asm__ __volatile__("autdb %0, %1":"+r"(t1):"r"(t2):); +#else + __asm__ __volatile__("autda %0, %1":"+r"(t1):"r"(t2):); +#endif + return reinterpret_cast(t1); +#else + return pointer; +#endif + } + + static inline uintptr_t DataProtectPac(const uintptr_t pointer, + [[maybe_unused]]const uintptr_t address) + { +#if defined(PANDA_TARGET_ARM64) + if (!isSupportPacA_) { + return pointer; + } + void *t1 = reinterpret_cast(pointer); + void *t2 = reinterpret_cast(address); +#ifdef PAC_DFI_PTR_BKEY + __asm__ __volatile__("pacdb %0, %1":"+r"(t1):"r"(t2):); +#else + __asm__ __volatile__("pacda %0, %1":"+r"(t1):"r"(t2):); +#endif + return reinterpret_cast(t1); +#else + return pointer; +#endif + } + + static bool isSupportPacA_; + +private: + void Update(const uintptr_t pointer) + { + if (pointer == 0) { + protect_pointer_ = 0; + return; + } + protect_pointer_ = DataProtectPac(pointer, reinterpret_cast(&protect_pointer_)); + } + + uintptr_t GetOriginPointer() const + { + if (protect_pointer_ == 0) { + return protect_pointer_; + } + return DataProtectAut(protect_pointer_, reinterpret_cast(&protect_pointer_)); + } + + uintptr_t protect_pointer_; +}; + +class StringPacProtect : public DataProtect { +public: + + enum Shift : uint8_t { + SHIFT8 = 8, + SHIFT16 = 16, + SHIFT24 = 24 + }; + + StringPacProtect() : data(std::vector()), originLength(0) {} + + explicit StringPacProtect(std::string_view strData) + { + Update(strData); + } + + ~StringPacProtect() + { + Clear(); + } + + // replace data by pac(strData) + void Update(std::string_view strData) + { + Clear(); + AppendWithoutCheckBack(strData); + } + + void Append(char ch) + { + constexpr uint32_t step = 4; + if (originLength % step > 0) { + // Filling back empty + uint32_t emptyCount = step - (originLength % step); + auto lastData = DataProtectAut(data.back(), reinterpret_cast(&data)); + data.pop_back(); + uint8_t shift = (SHIFT8 * (emptyCount - 1)); + lastData |= ch << shift; + data.push_back(DataProtectPac(lastData, reinterpret_cast(&data))); + } else { + uintptr_t tempData = uintptr_t(ch); + tempData <<= SHIFT24; + data.push_back(DataProtectPac(tempData, reinterpret_cast(&data))); + } + originLength ++; + } + + // data += pac(strData) + void Append(std::string_view strData) + { + if (strData.empty()) { + return; + } + constexpr uint32_t step = 4; + + auto str = reinterpret_cast(strData.data()); + auto len = strData.length(); + if (originLength % step != 0) { + // Filling back empty + uint32_t iter = 0; + uint32_t emptyCount = step - (originLength % step); + auto lastData = DataProtectAut(data.back(), reinterpret_cast(&data)); + data.pop_back(); + + lastData >>= SHIFT8 * emptyCount; + while (iter < emptyCount) { + lastData <<= SHIFT8; + lastData += (iter < len ? str[iter] : 0); + iter++; + } + data.push_back(DataProtectPac(lastData, reinterpret_cast(&data))); + originLength += (emptyCount < len ? emptyCount : len); + if (emptyCount < len) { + AppendWithoutCheckBack(strData.substr(emptyCount)); + } + } else { + AppendWithoutCheckBack(strData); + } + } + + // return string(aut(data)) + std::string GetOriginString() const + { + if (data.empty()) { + return ""; + } + std::string res = ""; + + constexpr uintptr_t mask = (1 << SHIFT8) - 1; + int32_t iter = data.size() - 1; + uint32_t dataCount = originLength % 4; + // need to delete back empty + if (dataCount != 0) { + uintptr_t tempData = DataProtectAut(data[iter], reinterpret_cast(&data)); + constexpr uint32_t step = 4; + uint32_t emptyCount = step - dataCount; + tempData >>= SHIFT8 * emptyCount; + while (dataCount > 0) { + res.push_back(char(tempData & mask)); + tempData >>= SHIFT8; + --dataCount; + } + --iter; + } + + for (; iter >= 0; --iter) { + uintptr_t tempData = DataProtectAut(data[iter], reinterpret_cast(&data)); + res.push_back(char(tempData & mask)); + tempData >>= SHIFT8; + res.push_back(char(tempData & mask)); + tempData >>= SHIFT8; + res.push_back(char(tempData & mask)); + tempData >>= SHIFT8; + res.push_back(char(tempData & mask)); + tempData >>= SHIFT8; + } + std::reverse(res.begin(), res.end()); + return res; + } + + // Compare strData with Paced data, return true if equal + bool CompareStringWithPacedString(std::string_view strData) + { + auto len = strData.length(); + constexpr uint32_t step = 4; + if (len != originLength) { + return false; + } + auto str = reinterpret_cast(strData.data()); + + auto dataPtr = data.begin(); + for (uint32_t left = 0; left < len; left += step) { + uint32_t right = (len > left + step ? left + step : len); + uintptr_t tempData = 0; + + for (uint32_t iter = left; iter < right; ++iter) { + tempData += str[iter]; + tempData <<= SHIFT8; + } + auto res = DataProtectPac(tempData, reinterpret_cast(&data)); + if (res != *dataPtr) { + return false; + } + ++dataPtr; + } + return true; + } + + void Clear() + { + std::vector().swap(data); + originLength = 0; + } + + // PacDataSize = ceil(StrLength / 4) + uint32_t PacDataSize() + { + return data.size(); + } + + // Original String Length Before Pac + uint32_t StrLength() + { + return originLength; + } + +private: + + void AppendWithoutCheckBack(std::string_view strData) + { + if (strData.empty()) { + return; + } + auto str = reinterpret_cast(strData.data()); + auto len = strData.length(); + + constexpr uint32_t step = 4; + // uint32 = char << 24 | char << 16 | char << 8 | char + // compress 4 char => 1 uint32 => PAC(uint32) => uintptr_t + for (uint32_t left = 0; left < len; left += step) { + uint32_t right = left + step; + uintptr_t tempData = 0; + + for (uint32_t iter = left; iter < right; ++iter) { + tempData <<= SHIFT8; + tempData += (iter < len ? str[iter] : 0); + } + data.push_back(DataProtectPac(tempData, reinterpret_cast(&data))); + } + originLength += strData.length(); + } + + std::vectordata; + uint32_t originLength; +}; +} +} +#endif // LIBPANDAFILE_DATA_PROTECT_H diff --git a/js_environment/frameworks/utils/src/data_protect.cpp b/js_environment/frameworks/utils/src/data_protect.cpp new file mode 100644 index 0000000000..f870dc8d93 --- /dev/null +++ b/js_environment/frameworks/utils/src/data_protect.cpp @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "data_protect.h" + +#if defined(PANDA_TARGET_ARM64) + #include + #include +#endif +namespace OHOS { +namespace JsEnv { + bool DataProtect::isSupportPacA_ = CheckPacSupport(); + + bool DataProtect::CheckPacSupport() + { +#if defined(PANDA_TARGET_ARM64) && defined(HWCAP_PACA) + uint64_t hwcaps = getauxval(AT_HWCAP); + return hwcaps & HWCAP_PACA; +#else + return false; +#endif + } +} +} \ No newline at end of file diff --git a/js_environment/interfaces/inner_api/js_environment_impl.h b/js_environment/interfaces/inner_api/js_environment_impl.h index ebba2ab012..87d76e5f4b 100644 --- a/js_environment/interfaces/inner_api/js_environment_impl.h +++ b/js_environment/interfaces/inner_api/js_environment_impl.h @@ -22,18 +22,23 @@ #include "native_engine/native_engine.h" +#include "data_protect.h" + namespace OHOS { namespace JsEnv { struct WorkerInfo { - std::string codePath; + // std::string codePath; + StringPacProtect codePath; bool isDebugVersion = false; bool isBundle = true; std::string packagePathStr; std::vector assetBasePathStr; - std::string hapPath; + // std::string hapPath; + StringPacProtect hapPath; bool isStageModel = true; std::string moduleName; - int32_t apiTargetVersion = 0; + // int32_t apiTargetVersion = 0; + DataProtect apiTargetVersion = DataProtect(); }; class JsEnvironmentImpl {