1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "hks_sa.h"
17
18 #include <ipc_skeleton.h>
19 #include <iservice_registry.h>
20 #include <mutex>
21 #include <string_ex.h>
22 #include <system_ability_definition.h>
23
24 #include "hks_client_service.h"
25 #include "hks_dcm_callback_handler.h"
26 #include "hks_ipc_service.h"
27 #include "hks_log.h"
28 #include "hks_mem.h"
29 #include "hks_message_handler.h"
30 #include "hks_plugin_adapter.h"
31 #include "hks_response.h"
32 #include "hks_template.h"
33 #include "hks_type_inner.h"
34 #include "hks_upgrade.h"
35 #include "hks_upgrade_lock.h"
36 #include "hks_util.h"
37 #include "huks_service_ipc_interface_code.h"
38 #include "rwlock.h"
39
40 #ifdef CONFIG_USE_JEMALLOC_DFX_INTF
41 #include "malloc.h"
42 #endif
43
44 #ifdef SUPPORT_COMMON_EVENT
45 #include <pthread.h>
46 #include <unistd.h>
47
48 #include "hks_event_observer.h"
49 #endif
50
51 #include <array>
52 #include <cinttypes>
53 #include <filesystem>
54 #include <string>
55 #include <system_error>
56
57 #ifdef HKS_USE_RKC_IN_STANDARD
58 #include <dirent.h>
59 #endif
60
61 uint32_t g_sessionId = 0;
62
63 namespace OHOS {
64 namespace Security {
65 namespace Hks {
66 REGISTER_SYSTEM_ABILITY_BY_ID(HksService, SA_ID_KEYSTORE_SERVICE, true);
67
68 std::mutex HksService::instanceLock;
69 sptr<HksService> HksService::instance;
70 const uint32_t MAX_MALLOC_LEN = 1 * 1024 * 1024; /* max malloc size 1 MB */
71 #define HUKS_IPC_THREAD_NUM 16
72 #ifdef SUPPORT_COMMON_EVENT
73 const uint32_t MAX_DELAY_TIMES = 100;
74 #endif
75
76 #ifdef SUPPORT_COMMON_EVENT
SubscribEvent()77 static void SubscribEvent()
78 {
79 for (uint32_t i = 0; i < MAX_DELAY_TIMES; ++i) {
80 if (SystemEventObserver::SubscribeEvent()) {
81 HKS_LOG_I("subscribe system event success, i = %" LOG_PUBLIC "u", i);
82 pthread_detach(pthread_self());
83 return;
84 } else {
85 HKS_LOG_E("subscribe system event failed %" LOG_PUBLIC "u times", i);
86 usleep(HKS_SLEEP_TIME_FOR_RETRY);
87 }
88 }
89 HKS_LOG_E("subscribe system event failed");
90 pthread_detach(pthread_self());
91 return;
92 }
93
HksSubscribeEvent()94 static void HksSubscribeEvent()
95 {
96 pthread_t subscribeThread;
97 if ((pthread_create(&subscribeThread, nullptr, (void *(*)(void *))SubscribEvent, nullptr)) == -1) {
98 HKS_LOG_E("create thread failed");
99 return;
100 }
101 pthread_setname_np(subscribeThread, "HUKS_SUBSCRIBE_THREAD");
102 HKS_LOG_I("create thread success");
103 }
104 #endif
105
IsInvalidLength(uint32_t length)106 static inline bool IsInvalidLength(uint32_t length)
107 {
108 return (length == 0) || (length > MAX_MALLOC_LEN);
109 }
110
ProcessMessage(uint32_t code,uint32_t outSize,const struct HksBlob & srcData,MessageParcel & reply)111 static int32_t ProcessMessage(uint32_t code, uint32_t outSize, const struct HksBlob &srcData, MessageParcel &reply)
112 {
113 uint32_t size = sizeof(HKS_IPC_MESSAGE_HANDLER) / sizeof(HKS_IPC_MESSAGE_HANDLER[0]);
114 for (uint32_t i = 0; i < size; ++i) {
115 if (code == HKS_IPC_MESSAGE_HANDLER[i].msgId) {
116 HKS_IPC_MESSAGE_HANDLER[i].handler(reinterpret_cast<const struct HksBlob *>(&srcData),
117 reinterpret_cast<const uint8_t *>(&reply));
118 return HKS_SUCCESS;
119 }
120 }
121
122 if (outSize > MAX_MALLOC_LEN) {
123 HKS_LOG_E("outSize is invalid, size:%" LOG_PUBLIC "u", outSize);
124 return HKS_ERROR_INVALID_ARGUMENT;
125 }
126
127 size = sizeof(HKS_IPC_THREE_STAGE_HANDLER) / sizeof(HKS_IPC_THREE_STAGE_HANDLER[0]);
128 for (uint32_t i = 0; i < size; ++i) {
129 if (code == HKS_IPC_THREE_STAGE_HANDLER[i].msgId) {
130 struct HksBlob outData = { 0, nullptr };
131 if (outSize != 0) {
132 outData.size = outSize;
133 outData.data = static_cast<uint8_t *>(HksMalloc(outData.size));
134 HKS_IF_NULL_LOGE_RETURN(outData.data, HKS_ERROR_MALLOC_FAIL, "Malloc outData failed.")
135 }
136 HKS_IPC_THREE_STAGE_HANDLER[i].handler(reinterpret_cast<const struct HksBlob *>(&srcData), &outData,
137 reinterpret_cast<const uint8_t *>(&reply));
138 HKS_FREE_BLOB(outData);
139 break;
140 }
141 }
142 return HKS_SUCCESS;
143 }
144
HksService(int saId,bool runOnCreate=true)145 HksService::HksService(int saId, bool runOnCreate = true)
146 : SystemAbility(saId, runOnCreate), registerToService_(false), runningState_(STATE_NOT_START)
147 {
148 HKS_LOG_D("HksService");
149 }
150
~HksService()151 HksService::~HksService()
152 {
153 HKS_LOG_D("~HksService");
154 }
155
GetInstance()156 sptr<HksService> HksService::GetInstance()
157 {
158 std::lock_guard<std::mutex> autoLock(instanceLock);
159 if (instance == nullptr) {
160 instance = new (std::nothrow) HksService(SA_ID_KEYSTORE_SERVICE, true);
161 }
162
163 return instance;
164 }
165
Init()166 bool HksService::Init()
167 {
168 HKS_LOG_I("HksService::Init Ready to init");
169 if (registerToService_) {
170 HKS_LOG_I("HksService::Init already finished.");
171 return true;
172 }
173
174 int32_t ret = HksServiceInitialize();
175 HKS_IF_NOT_SUCC_LOGE_RETURN(ret, false, "Init hks service failed!")
176 sptr<HksService> ptrInstance = HksService::GetInstance();
177 HKS_IF_NULL_LOGE_RETURN(ptrInstance, false, "HksService::Init GetInstance Failed")
178 if (!Publish(ptrInstance)) {
179 HKS_LOG_E("HksService::Init Publish Failed");
180 return false;
181 }
182 HKS_LOG_I("HksService::Init Publish service success");
183 registerToService_ = true;
184
185 HKS_LOG_I("HksService::Init success.");
186 return true;
187 }
188
HksInitMemPolicy(void)189 static void HksInitMemPolicy(void)
190 {
191 #ifdef CONFIG_USE_JEMALLOC_DFX_INTF
192 // disable mem cache and delay free because the size of mem data in HUKS is associated with caller tasks and
193 // changeable, which is not suitable for this case
194 (void)mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
195 (void)mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
196 #endif
197 }
198
ProcessAttestOrNormalMessage(uint32_t code,MessageParcel & data,uint32_t outSize,const struct HksBlob & srcData,MessageParcel & reply)199 static int32_t ProcessAttestOrNormalMessage(
200 uint32_t code, MessageParcel &data, uint32_t outSize, const struct HksBlob &srcData, MessageParcel &reply)
201 {
202 // Since we have wrote a HksStub instance in client side, we can now read it if it is anonymous attestation.
203 if (code == HKS_MSG_ATTEST_KEY) {
204 HksIpcServiceAttestKey(reinterpret_cast<const HksBlob *>(&srcData),
205 reinterpret_cast<const uint8_t *>(&reply), nullptr);
206 return HKS_SUCCESS;
207 } else if (code == HKS_MSG_ATTEST_KEY_ASYNC_REPLY) {
208 auto ptr = data.ReadRemoteObject();
209 if (ptr == nullptr) {
210 // ReadRemoteObject will fail if huks_service has no selinux permission to call the client side.
211 HKS_LOG_E("ReadRemoteObject ptr failed");
212 return HKS_ERROR_IPC_INIT_FAIL;
213 }
214
215 HksIpcServiceAttestKey(reinterpret_cast<const HksBlob *>(&srcData),
216 reinterpret_cast<const uint8_t *>(&reply), reinterpret_cast<const uint8_t *>(ptr.GetRefPtr()));
217 return HKS_SUCCESS;
218 } else {
219 return ProcessMessage(code, outSize, srcData, reply);
220 }
221 }
222
ProcessRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply)223 static void ProcessRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply)
224 {
225 uint32_t outSize = static_cast<uint32_t>(data.ReadUint32());
226 struct HksBlob srcData = { 0, nullptr };
227 int32_t ret = HKS_SUCCESS;
228 do {
229 ret = HksPluginOnLocalRequest(CODE_UPGRADE, NULL, NULL);
230 HKS_IF_NOT_SUCC_BREAK(ret, "Failed to handle local request. ret = %" LOG_PUBLIC "d", ret);
231
232 srcData.size = static_cast<uint32_t>(data.ReadUint32());
233 if (IsInvalidLength(srcData.size)) {
234 HKS_LOG_E("srcData size is invalid, size:%" LOG_PUBLIC "u", srcData.size);
235 ret = HKS_ERROR_INVALID_ARGUMENT;
236 break;
237 }
238
239 srcData.data = static_cast<uint8_t *>(HksMalloc(srcData.size));
240 if (srcData.data == nullptr) {
241 HKS_LOG_E("Malloc srcData failed.");
242 ret = HKS_ERROR_MALLOC_FAIL;
243 break;
244 }
245
246 const uint8_t *pdata = data.ReadBuffer(static_cast<size_t>(srcData.size));
247 if (pdata == nullptr) {
248 ret = HKS_ERROR_IPC_MSG_FAIL;
249 break;
250 }
251 (void)memcpy_s(srcData.data, srcData.size, pdata, srcData.size);
252 ret = ProcessAttestOrNormalMessage(code, data, outSize, srcData, reply);
253 } while (0);
254
255 HKS_FREE_BLOB(srcData);
256
257 if (ret != HKS_SUCCESS) {
258 HKS_LOG_E("handle ipc msg failed!");
259 HksSendResponse(reinterpret_cast<const uint8_t *>(&reply), ret, nullptr);
260 }
261 }
262
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)263 int HksService::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
264 {
265 HksInitMemPolicy();
266
267 uint64_t enterTime = 0;
268 (void)HksElapsedRealTime(&enterTime);
269 g_sessionId++;
270 HKS_LOG_I("OnRemoteRequest code:%" LOG_PUBLIC "d, sessionId = %" LOG_PUBLIC "u", code, g_sessionId);
271
272 // judge whether is upgrading, wait for upgrade finished
273 if (HksWaitIfPowerOnUpgrading() != HKS_SUCCESS) {
274 HKS_LOG_E("wait on upgrading failed.");
275 return HW_SYSTEM_ERROR;
276 }
277 OHOS::Utils::UniqueReadGuard<OHOS::Utils::RWLock> readGuard(g_upgradeOrRequestLock);
278
279 if (code < HksIpcInterfaceCode::HKS_MSG_BASE || code >= HksIpcInterfaceCode::HKS_MSG_MAX) {
280 int32_t ret = RetryLoadPlugin();
281 if (ret != HKS_SUCCESS) {
282 HksSendResponse(reinterpret_cast<const uint8_t *>(&reply), ret, nullptr);
283 return HKS_SUCCESS; // send error code by IPC.
284 }
285 return HksPluginOnRemoteRequest(code, &data, &reply, &option);
286 }
287 // this is the temporary version which comments the descriptor check
288 if (HksService::GetDescriptor() != data.ReadInterfaceToken()) {
289 HKS_LOG_E("descriptor is diff.");
290 return HW_SYSTEM_ERROR;
291 }
292
293 ProcessRemoteRequest(code, data, reply);
294
295 uint64_t leaveTime = 0;
296 (void)HksElapsedRealTime(&leaveTime);
297 HKS_LOG_I("finish code:%" LOG_PUBLIC "d, total cost %" LOG_PUBLIC PRIu64 " ms, sessionId = %"
298 LOG_PUBLIC "u", code, leaveTime - enterTime, g_sessionId);
299
300 return NO_ERROR;
301 }
302
303 #define OLD_PATH "/data/service/el2/public/huks_service/maindata"
304 #define NEW_PATH "/data/service/el1/public/huks_service/maindata"
305
306 #ifdef HKS_USE_RKC_IN_STANDARD
307 #define OLD_MINE_PATH "/data/data/huks_service/maindata"
308 #define INTERMEDIATE_MINE_RKC_PATH "/data/service/el1/public/huks_service/maindata/hks_client"
309 #define NEW_MINE_RKC_PATH "/data/data/huks_service/maindata/hks_client"
310
311 #define DEFAULT_PATH_LEN 1024
312 #endif
313
314 #ifdef HKS_USE_RKC_IN_STANDARD
MoveMineOldFile(const char * oldDir,const char * newDir)315 void MoveMineOldFile(const char *oldDir, const char *newDir)
316 {
317 auto dir = opendir(oldDir);
318 HKS_IF_NULL_LOGE_RETURN_VOID(dir, "open old dir failed!")
319 struct dirent *ptr;
320 while ((ptr = readdir(dir)) != NULL) {
321 // move dir expect hks_client, for it is the rkc root key and should be in same position
322 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0 || strcmp(ptr->d_name, "hks_client") == 0) {
323 continue;
324 }
325 char curPath[DEFAULT_PATH_LEN] = { 0 };
326 if (strcpy_s(curPath, DEFAULT_PATH_LEN, oldDir) != EOK) {
327 break;
328 }
329 if (strcat_s(curPath, DEFAULT_PATH_LEN, "/") != EOK) {
330 break;
331 }
332 if (strcat_s(curPath, DEFAULT_PATH_LEN, ptr->d_name) != EOK) {
333 break;
334 }
335 char newPath[DEFAULT_PATH_LEN] = { 0 };
336 if (strcpy_s(newPath, DEFAULT_PATH_LEN, newDir) != EOK) {
337 break;
338 }
339 if (strcat_s(newPath, DEFAULT_PATH_LEN, "/") != EOK) {
340 break;
341 }
342 if (strcat_s(newPath, DEFAULT_PATH_LEN, ptr->d_name) != EOK) {
343 break;
344 }
345 std::error_code errCode{};
346 std::filesystem::create_directory(newDir, errCode);
347 if (errCode.value() != 0) {
348 HKS_LOG_E("create_directory %" LOG_PUBLIC "s failed %" LOG_PUBLIC "s", newPath, errCode.message().c_str());
349 }
350 std::filesystem::copy(curPath, newPath,
351 std::filesystem::copy_options::recursive | std::filesystem::copy_options::overwrite_existing, errCode);
352 if (errCode.value() != 0) {
353 HKS_LOG_E("copy %" LOG_PUBLIC "s to %" LOG_PUBLIC "s failed %" LOG_PUBLIC "s",
354 curPath, newPath, errCode.message().c_str());
355 break;
356 }
357 std::filesystem::remove_all(curPath, errCode);
358 if (errCode.value() != 0) {
359 HKS_LOG_E("remove_all %" LOG_PUBLIC "s failed %" LOG_PUBLIC "s", curPath, errCode.message().c_str());
360 }
361 }
362 closedir(dir);
363 }
364 #endif
365
MoveDirectoryTree(const char * oldDir,const char * newDir)366 void MoveDirectoryTree(const char *oldDir, const char *newDir)
367 {
368 std::error_code errCode{};
369 std::filesystem::create_directory(newDir, errCode);
370 if (errCode.value() != 0) {
371 HKS_LOG_E("create_directory %" LOG_PUBLIC "s failed %" LOG_PUBLIC "s", newDir, errCode.message().c_str());
372 } else {
373 HKS_LOG_I("create_directory %" LOG_PUBLIC "s ok!", newDir);
374 }
375 std::filesystem::copy(oldDir, newDir,
376 std::filesystem::copy_options::recursive | std::filesystem::copy_options::overwrite_existing, errCode);
377 if (errCode.value() != 0) {
378 HKS_LOG_E("copy %" LOG_PUBLIC "s to %" LOG_PUBLIC "s failed %" LOG_PUBLIC "s",
379 oldDir, newDir, errCode.message().c_str());
380 return;
381 }
382 HKS_LOG_I("copy %" LOG_PUBLIC "s to %" LOG_PUBLIC "s ok!", oldDir, newDir);
383 std::filesystem::remove_all(oldDir, errCode);
384 if (errCode.value() != 0) {
385 HKS_LOG_E("remove_all %" LOG_PUBLIC "s failed %" LOG_PUBLIC "s", oldDir, errCode.message().c_str());
386 return;
387 }
388 HKS_LOG_I("remove_all %" LOG_PUBLIC "s ok!", oldDir);
389 }
390
OnStart()391 void HksService::OnStart()
392 {
393 HKS_LOG_I("HksService OnStart");
394 std::lock_guard<std::mutex> lock(runningStateLock);
395 if (std::atomic_load(&runningState_) == STATE_RUNNING) {
396 HKS_LOG_I("HksService has already started");
397 return;
398 }
399 MoveDirectoryTree(OLD_PATH, NEW_PATH);
400 #ifdef HKS_USE_RKC_IN_STANDARD
401 // the intermediate mine's rkc is located in INTERMEDIATE_MINE_RKC_PATH, normal keys is located in NEW_PATH
402 MoveDirectoryTree(INTERMEDIATE_MINE_RKC_PATH, NEW_MINE_RKC_PATH);
403 // the original mine's rkc and normal keys are both located in OLD_MINE_PATH, should move all expect for rkc files
404 MoveMineOldFile(OLD_MINE_PATH, NEW_PATH);
405 #endif
406
407 if (HksProcessConditionCreate() != HKS_SUCCESS) {
408 HKS_LOG_E("create process condition on init failed.");
409 return;
410 }
411
412 // lock before huks init, for the upgrading will be thread safe.
413 #ifdef HUKS_ENABLE_UPGRADE_KEY_STORAGE_SECURE_LEVEL
414 {
415 OHOS::Utils::UniqueWriteGuard<OHOS::Utils::RWLock> writeGuard(g_upgradeOrRequestLock);
416 #endif
417
418 if (!Init()) {
419 HKS_LOG_E("Failed to init HksService");
420 return;
421 }
422
423 #ifdef SUPPORT_COMMON_EVENT
424 (void)AddSystemAbilityListener(COMMON_EVENT_SERVICE_ID);
425 #endif
426
427 // this should be excuted after huks published and listener added.
428 HksUpgradeOnPowerOn();
429 #ifdef HUKS_ENABLE_UPGRADE_KEY_STORAGE_SECURE_LEVEL
430 }
431 HksUpgradeOnPowerOnDoneNotifyAll();
432 #endif
433
434 std::atomic_store(&runningState_, STATE_RUNNING);
435 IPCSkeleton::SetMaxWorkThreadNum(HUKS_IPC_THREAD_NUM);
436 HKS_LOG_I("HksService start success.");
437 }
438
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)439 void HksService::OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
440 {
441 HKS_LOG_I("systemAbilityId is %" LOG_PUBLIC "d!", systemAbilityId);
442 #ifdef SUPPORT_COMMON_EVENT
443 HksSubscribeEvent();
444 #endif
445 }
446
OnRemoveSystemAbility(int32_t systemAbilityId,const std::string & deviceId)447 void HksService::OnRemoveSystemAbility(int32_t systemAbilityId, const std::string& deviceId)
448 {
449 HKS_LOG_I("systemAbilityId is %" LOG_PUBLIC "d!", systemAbilityId);
450 }
451
OnStop()452 void HksService::OnStop()
453 {
454 HKS_LOG_I("HksService Service OnStop");
455 std::lock_guard<std::mutex> lock(runningStateLock);
456 std::atomic_store(&runningState_, STATE_NOT_START);
457 registerToService_ = false;
458 #ifndef HKS_UNTRUSTED_RUNNING_ENV
459 HksCloseDcmFunction();
460 #endif // HKS_UNTRUSTED_RUNNING_ENV
461 }
462 } // namespace Hks
463 } // namespace Security
464 } // namespace OHOS
465