• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 2
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