• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-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 "account_file_watcher_manager.h"
17 
18 #include <dlfcn.h>
19 #include <pthread.h>
20 #include <securec.h>
21 #include <thread>
22 #include "account_hisysevent_adapter.h"
23 #include "account_log_wrapper.h"
24 #include "account_timeout_task.h"
25 #ifdef HAS_HUKS_PART
26 #include "hks_api.h"
27 #include "hks_param.h"
28 #include "hks_type.h"
29 #endif // HAS_HUKS_PART
30 #include "os_account_constants.h"
31 #include "hitrace_adapter.h"
32 
33 namespace OHOS {
34 namespace AccountSA {
35 #ifdef ENABLE_FILE_WATCHER
36 namespace {
37 constexpr uint32_t FILE_WATCHER_LIMIT = 1024 * 100;
38 constexpr uint32_t BUF_COMMON_SIZE = 1024 * 100;
39 constexpr uint32_t ALG_COMMON_SIZE = 32;
40 #ifdef HAS_HUKS_PART
41 const struct HksParam g_genSignVerifyParams[] = {
42     {
43         .tag = HKS_TAG_ALGORITHM,
44         .uint32Param = HKS_ALG_HMAC
45     }, {
46         .tag = HKS_TAG_PURPOSE,
47         .uint32Param = HKS_KEY_PURPOSE_MAC
48     }, {
49         .tag = HKS_TAG_KEY_SIZE,
50         .uint32Param = HKS_AES_KEY_SIZE_256
51     }, {
52         .tag = HKS_TAG_DIGEST,
53         .uint32Param = HKS_DIGEST_SHA256
54     }, {
55         .tag = HKS_TAG_AUTH_STORAGE_LEVEL,
56         .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE
57     }
58 };
59 constexpr int32_t TIMES = 4;
60 constexpr int32_t MAX_UPDATE_SIZE = 256 * 100;
61 constexpr int32_t MAX_OUTDATA_SIZE = MAX_UPDATE_SIZE * TIMES;
62 constexpr char ACCOUNT_KEY_ALIAS[] = "os_account_info_encryption_key";
63 const HksBlob g_keyAlias = { (uint32_t)strlen(ACCOUNT_KEY_ALIAS), (uint8_t *)ACCOUNT_KEY_ALIAS };
64 #endif // HAS_HUKS_PART
65 }
66 
67 #ifdef HAS_HUKS_PART
InitParamSet(struct HksParamSet ** paramSet,const struct HksParam * params,uint32_t paramCount)68 static int32_t InitParamSet(struct HksParamSet **paramSet, const struct HksParam *params, uint32_t paramCount)
69 {
70     int32_t ret = HksInitParamSet(paramSet);
71     if (ret != 0) {
72         ACCOUNT_LOGE("HksInitParamSet err = %{public}d", ret);
73         return ret;
74     }
75     ret = HksAddParams(*paramSet, params, paramCount);
76     if (ret != 0) {
77         ACCOUNT_LOGE("HksAddParams err = %{public}d", ret);
78         HksFreeParamSet(paramSet);
79         return ret;
80     }
81 
82     ret = HksBuildParamSet(paramSet);
83     if (ret != 0) {
84         ACCOUNT_LOGE("HksBuildParamSet err = %{public}d", ret);
85         HksFreeParamSet(paramSet);
86         return ret;
87     }
88     return ret;
89 }
90 
MallocAndCheckBlobData(struct HksBlob * blob,const uint32_t blobSize)91 static int32_t MallocAndCheckBlobData(struct HksBlob *blob, const uint32_t blobSize)
92 {
93     if (blobSize == 0) {
94         blob->data = NULL;
95         return -1;
96     }
97     blob->data = static_cast<uint8_t *>(malloc(blobSize));
98     if (blob->data == NULL) {
99         ACCOUNT_LOGE("MallocAndCheckBlobData err");
100         return -1;
101     }
102     return 0;
103 }
104 
HksUpdateOpt(const struct HksBlob * handle,const struct HksParamSet * paramSet,const struct HksBlob * inData)105 static int32_t HksUpdateOpt(
106     const struct HksBlob *handle, const struct HksParamSet *paramSet, const struct HksBlob *inData)
107 {
108     struct HksBlob inDataSeg = *inData;
109     inDataSeg.size = MAX_UPDATE_SIZE;
110 
111     uint8_t *lastPtr = inData->data + inData->size - 1;
112     struct HksBlob outDataSeg = {
113         .size = MAX_OUTDATA_SIZE,
114         .data = NULL
115     };
116 
117     bool isFinished = false;
118     while (inDataSeg.data <= lastPtr) {
119         if (inDataSeg.data + MAX_UPDATE_SIZE <= lastPtr) {
120             outDataSeg.size = MAX_OUTDATA_SIZE;
121         } else {
122             isFinished = true;
123             inDataSeg.size = lastPtr - inDataSeg.data + 1;
124             outDataSeg.size = inDataSeg.size + MAX_UPDATE_SIZE;
125         }
126         if (MallocAndCheckBlobData(&outDataSeg, outDataSeg.size) != 0) {
127             return -1;
128         }
129         int32_t ret = HksUpdate(handle, paramSet, &inDataSeg, &outDataSeg);
130         if (ret != 0) {
131             ACCOUNT_LOGE("HksUpdate err, ret = %{public}d", ret);
132             free(outDataSeg.data);
133             outDataSeg.data = NULL;
134             return -1;
135         }
136         free(outDataSeg.data);
137         outDataSeg.data = NULL;
138         if ((isFinished == false) && (inDataSeg.data + MAX_UPDATE_SIZE > lastPtr)) {
139             return 0;
140         }
141         inDataSeg.data += MAX_UPDATE_SIZE;
142     }
143     return 0;
144 }
145 
InitEncryptionKey()146 static int32_t InitEncryptionKey()
147 {
148     struct HksParamSet *genParamSet = nullptr;
149 
150     int32_t ret;
151     do {
152         ret = InitParamSet(&genParamSet, g_genSignVerifyParams, sizeof(g_genSignVerifyParams) / sizeof(HksParam));
153         if (ret != 0) {
154             ACCOUNT_LOGE("InitParamSet genParamSet err = %{public}d", ret);
155             break;
156         }
157         ret = HksGenerateKey(&g_keyAlias, genParamSet, nullptr);
158         if (ret != 0) {
159             ACCOUNT_LOGE("HksGenerateKey err = %{public}d", ret);
160             break;
161         }
162     } while (0);
163     HksFreeParamSet(&genParamSet);
164     return ret;
165 }
166 
GetDigestDataFromHuks(struct HksParamSet * genParamSet,struct HksBlob & inDataBlob,uint8_t * outData,uint32_t size)167 static int32_t GetDigestDataFromHuks(struct HksParamSet *genParamSet, struct HksBlob &inDataBlob,
168     uint8_t* outData, uint32_t size)
169 {
170     uint8_t handleTmp[sizeof(uint64_t)] = {0};
171     struct HksBlob handleGenDigest = { (uint32_t)sizeof(uint64_t), handleTmp };
172 
173     int32_t ret = HksInit(&g_keyAlias, genParamSet, &handleGenDigest, nullptr);
174     if (ret != 0) {
175         ACCOUNT_LOGE("HksInit err = %{public}d", ret);
176         return ret;
177     }
178     ret = HksUpdateOpt(&handleGenDigest, genParamSet, &inDataBlob);
179     if (ret != 0) {
180         ACCOUNT_LOGE("HksUpdateOpt err = %{public}d", ret);
181         HksAbort(&handleGenDigest, genParamSet);
182         return ret;
183     }
184     struct HksBlob finishOut = { 0, nullptr };
185     uint8_t outDataS[ALG_COMMON_SIZE] = "out";
186     struct HksBlob outDataBlob = { ALG_COMMON_SIZE, outDataS };
187     ret = HksFinish(&handleGenDigest, genParamSet, &finishOut, &outDataBlob);
188     if (ret != 0) {
189         ACCOUNT_LOGE("HksFinish failed = %{public}d", ret);
190         HksAbort(&handleGenDigest, genParamSet);
191         return ret;
192     }
193     if (memcpy_s(outData, size, outDataS, outDataBlob.size) != EOK) {
194         ACCOUNT_LOGE("Get digest failed duo to memcpy_s failed");
195         return -1;
196     }
197     return 0;
198 }
199 
GenerateAccountInfoDigest(const std::string & inData,uint8_t * outData,uint32_t size)200 int32_t GenerateAccountInfoDigest(const std::string &inData, uint8_t* outData, uint32_t size)
201 {
202     if (inData.empty()) {
203         ACCOUNT_LOGW("inData is empty.");
204         return 0;
205     }
206     size_t len = inData.size() + 1;
207     uint8_t *buffer = static_cast<uint8_t *>(malloc(len));
208     if (buffer == nullptr) {
209         ACCOUNT_LOGE("buffer malloc err");
210         return -1;
211     }
212     (void)memcpy_s(buffer, len, inData.c_str(), len);
213     struct HksBlob inDataBlob = { inData.size(), buffer };
214     struct HksParamSet *genParamSet = nullptr;
215     int32_t ret = InitParamSet(&genParamSet, g_genSignVerifyParams, sizeof(g_genSignVerifyParams) / sizeof(HksParam));
216     if (ret != 0) {
217         free(buffer);
218         ACCOUNT_LOGE("InitParamSet err = %{public}d", ret);
219         return ret;
220     }
221     ret = GetDigestDataFromHuks(genParamSet, inDataBlob, outData, size);
222     HksFreeParamSet(&genParamSet);
223     free(buffer);
224     return ret;
225 }
226 #endif // HAS_HUKS_PART
227 
AccountFileWatcherMgr()228 AccountFileWatcherMgr::AccountFileWatcherMgr()
229 {
230     std::shared_ptr<AccountTimeoutTask> task = std::make_shared<AccountTimeoutTask>();
231     bool state = task->RunTask("InitEncryptionKey", [] {
232 #ifdef HAS_HUKS_PART
233         InitEncryptionKey();
234 #endif // HAS_HUKS_PART
235     });
236     if (!state) {
237         ReportServiceStartFail(ERR_ACCOUNT_COMMON_OPERATION_TIMEOUT, "InitEncryptionKey timeout");
238     }
239     inotifyFd_ = inotify_init();
240     if (inotifyFd_ < 0) {
241         ACCOUNT_LOGE("failed to init notify, errCode:%{public}d", errno);
242     }
243     accountFileOperator_ = std::make_shared<AccountFileOperator>();
244     FD_ZERO(&fds_);
245 }
246 
GetInstance()247 AccountFileWatcherMgr &AccountFileWatcherMgr::GetInstance()
248 {
249     static AccountFileWatcherMgr *instance = new AccountFileWatcherMgr();
250     return *instance;
251 }
252 
DealWithFileEvent()253 void AccountFileWatcherMgr::DealWithFileEvent()
254 {
255     std::vector<std::pair<std::shared_ptr<FileWatcher>, uint32_t>> eventMap;
256     {
257         std::lock_guard<std::mutex> lock(fileWatcherMgrLock_);
258         char buf[BUF_COMMON_SIZE] = {0};
259         struct inotify_event *event = nullptr;
260         int len = 0;
261         int index = 0;
262         while (((len = read(inotifyFd_, &buf, sizeof(buf))) < 0) && (errno == EINTR)) {};
263         while (index < len) {
264             event = reinterpret_cast<inotify_event *>(buf + index);
265             if (event->mask & (IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF)) {
266                 if (fileNameMgrMap_.find(event->wd) != fileNameMgrMap_.end()) {
267                     std::shared_ptr<FileWatcher> fileWatcher = fileNameMgrMap_[event->wd];
268                     eventMap.emplace_back(std::make_pair(fileWatcher, event->mask));
269                 }
270             }
271             index += static_cast<int>(sizeof(struct inotify_event) + event->len);
272         }
273     }
274     for (auto it : eventMap) {
275         it.first->CheckNotifyEvent(it.second);
276     }
277 }
278 
GetNotifyEvent()279 void AccountFileWatcherMgr::GetNotifyEvent()
280 {
281     FD_SET(inotifyFd_, &fds_);
282     while (run_) {
283         if (inotifyFd_ < 0) {
284             ACCOUNT_LOGE("failed to run notify because no fd available.");
285             break;
286         }
287         if (select(inotifyFd_ + 1, &fds_, nullptr, nullptr, nullptr) <= 0) {
288             continue;
289         }
290         DealWithFileEvent();
291     }
292 }
293 
StartWatch()294 void AccountFileWatcherMgr::StartWatch() // start watcher
295 {
296     if (run_) {
297         return;
298     }
299     run_ = true;
300     auto task = [this] { this->GetNotifyEvent(); };
301     std::thread taskThread(task);
302     pthread_setname_np(taskThread.native_handle(), "fileWatcher");
303     taskThread.detach();
304 }
305 
AddFileWatcher(int32_t id,CheckNotifyEventCallbackFunc checkCallbackFunc,const std::string & filePath)306 void AccountFileWatcherMgr::AddFileWatcher(
307     int32_t id, CheckNotifyEventCallbackFunc checkCallbackFunc, const std::string &filePath)
308 {
309     if (checkCallbackFunc == nullptr) {
310         ACCOUNT_LOGE("Notify event callback is nullptr");
311         return;
312     }
313     std::lock_guard<std::mutex> lock(fileWatcherMgrLock_);
314     if (inotifyFd_ < 0) {
315         inotifyFd_ = inotify_init();
316         if (inotifyFd_ < 0) {
317             ACCOUNT_LOGE("failed to init notify, errCode:%{public}d", errno);
318             return;
319         }
320     }
321     if (fileNameMgrMap_.size() > FILE_WATCHER_LIMIT) {
322         ACCOUNT_LOGW("the fileWatcher limit has been reached, fileName = %{public}s", filePath.c_str());
323         return;
324     }
325     std::shared_ptr<FileWatcher> fileWatcher;
326     if (!filePath.empty()) {
327         fileWatcher = std::make_shared<FileWatcher>(id, filePath, checkCallbackFunc);
328     } else {
329         fileWatcher = std::make_shared<FileWatcher>(id, checkCallbackFunc);
330     }
331     if (!fileWatcher->StartNotify(inotifyFd_, IN_MODIFY | IN_DELETE_SELF| IN_MOVE_SELF)) {
332         ACCOUNT_LOGI("fileWatcher StartNotify failed, fileName = %{public}s", filePath.c_str());
333         return;
334     }
335     fileNameMgrMap_[fileWatcher->GetWd()] = fileWatcher;
336     {
337         std::unique_lock<std::shared_timed_mutex> fileLock(accountFileOperator_->fileLock_);
338         accountFileOperator_->SetValidModifyFileOperationFlag(filePath, false);
339     }
340 
341     StartWatch();
342 }
343 
RemoveFileWatcher(int32_t id,const std::string & filePath)344 void AccountFileWatcherMgr::RemoveFileWatcher(int32_t id, const std::string &filePath)
345 {
346     std::lock_guard<std::mutex> lock(fileWatcherMgrLock_);
347     int targetWd = -1;
348     for (auto it : fileNameMgrMap_) {
349         if ((it.second->GetLocalId() == id) && (it.second->GetFilePath() == filePath)) {
350             targetWd = it.second->GetWd();
351             break;
352         }
353     }
354     if (targetWd == -1) {
355         return;
356     }
357     fileNameMgrMap_[targetWd]->CloseNotify(inotifyFd_);
358     fileNameMgrMap_.erase(targetWd);
359 }
360 
GetAccountInfoDigestFromFile(const std::string & path,uint8_t * digest,uint32_t size)361 ErrCode AccountFileWatcherMgr::GetAccountInfoDigestFromFile(const std::string &path, uint8_t *digest, uint32_t size)
362 {
363     std::string accountInfoDigest;
364     std::lock_guard<std::mutex> lock(accountInfoDigestFileLock_);
365     ErrCode errCode = accountFileOperator_->GetFileContentByPath(Constants::ACCOUNT_INFO_DIGEST_FILE_PATH,
366         accountInfoDigest);
367     if (errCode != ERR_OK) {
368         ACCOUNT_LOGE("GetFileContentByPath failed! error code %{public}d.", errCode);
369         return errCode;
370     }
371     Json accountInfoDigestJson = Json::parse(accountInfoDigest, nullptr, false);
372     if (accountInfoDigestJson.is_discarded()) {
373         return ERR_ACCOUNT_COMMON_DUMP_JSON_ERROR;
374     }
375     std::vector<uint8_t> digestTmp;
376     OHOS::AccountSA::GetDataByType<std::vector<uint8_t>>(accountInfoDigestJson,
377         accountInfoDigestJson.end(), path, digestTmp, OHOS::AccountSA::JsonType::ARRAY);
378     if (memcpy_s(digest, size, digestTmp.data(), ALG_COMMON_SIZE) != EOK) {
379         ACCOUNT_LOGE("Get digest failed duo to memcpy_s failed");
380         return ERR_ACCOUNT_COMMON_INSUFFICIENT_MEMORY_ERROR;
381     }
382     return ERR_OK;
383 }
384 
GenerateAccountInfoDigestStr(const std::string & userInfoPath,const std::string & accountInfoStr,std::string & digestStr)385 ErrCode AccountFileWatcherMgr::GenerateAccountInfoDigestStr(
386     const std::string &userInfoPath, const std::string &accountInfoStr, std::string &digestStr)
387 {
388     uint8_t digestOutData[ALG_COMMON_SIZE];
389 #ifdef HAS_HUKS_PART
390     StartTraceAdapter("GenerateAccountInfoDigest Using Huks");
391     GenerateAccountInfoDigest(accountInfoStr, digestOutData, ALG_COMMON_SIZE);
392     FinishTraceAdapter();
393 #endif // HAS_HUKS_PART
394 
395     std::string accountInfoDigest;
396     std::lock_guard<std::mutex> lock(accountInfoDigestFileLock_);
397     ErrCode errCode = accountFileOperator_->GetFileContentByPath(Constants::ACCOUNT_INFO_DIGEST_FILE_PATH,
398         accountInfoDigest);
399     if (errCode != ERR_OK) {
400         ACCOUNT_LOGE("get file content failed! error code %{public}d.", errCode);
401         return errCode;
402     }
403     Json accountInfoDigestJson = Json::parse(accountInfoDigest, nullptr, false);
404     if (accountInfoDigestJson.is_discarded()) {
405         return ERR_ACCOUNT_COMMON_DUMP_JSON_ERROR;
406     }
407     accountInfoDigestJson[userInfoPath] = digestOutData;
408     try {
409         digestStr = accountInfoDigestJson.dump();
410     } catch (Json::type_error& err) {
411         ACCOUNT_LOGE("failed to dump json object, reason: %{public}s", err.what());
412         return ERR_ACCOUNT_COMMON_DUMP_JSON_ERROR;
413     }
414     return ERR_OK;
415 }
416 
AddAccountInfoDigest(const std::string accountInfo,const std::string & userInfoPath)417 ErrCode AccountFileWatcherMgr::AddAccountInfoDigest(const std::string accountInfo, const std::string &userInfoPath)
418 {
419     std::string digestStr;
420     if (GenerateAccountInfoDigestStr(userInfoPath, accountInfo, digestStr) == ERR_OK) {
421         std::lock_guard<std::mutex> lock(accountInfoDigestFileLock_);
422         return accountFileOperator_->InputFileByPathAndContent(Constants::ACCOUNT_INFO_DIGEST_FILE_PATH, digestStr);
423     }
424     return ERR_OK;
425 }
426 
DeleteAccountInfoDigest(const std::string & userInfoPath)427 ErrCode AccountFileWatcherMgr::DeleteAccountInfoDigest(const std::string &userInfoPath)
428 {
429     std::string accountInfoDigest;
430     std::lock_guard<std::mutex> lock(accountInfoDigestFileLock_);
431     ErrCode errCode = accountFileOperator_->GetFileContentByPath(Constants::ACCOUNT_INFO_DIGEST_FILE_PATH,
432         accountInfoDigest);
433     if (errCode != ERR_OK) {
434         ACCOUNT_LOGE("get file content failed! error code %{public}d.", errCode);
435         return errCode;
436     }
437     Json accountInfoDigestJson = Json::parse(accountInfoDigest, nullptr, false);
438     if (accountInfoDigestJson.is_discarded()) {
439         return ERR_ACCOUNT_COMMON_DUMP_JSON_ERROR;
440     }
441     if (accountInfoDigestJson.find(userInfoPath) == accountInfoDigestJson.end()) {
442         return ERR_OK;
443     }
444     accountInfoDigestJson.erase(userInfoPath);
445 
446     ErrCode result = accountFileOperator_->InputFileByPathAndContent(
447         Constants::ACCOUNT_INFO_DIGEST_FILE_PATH, accountInfoDigestJson.dump());
448     if (result != ERR_OK) {
449         ACCOUNT_LOGE("cannot save digest info to file, code %{public}d.", result);
450         return result;
451     }
452     return ERR_OK;
453 }
454 
FileWatcher(int32_t id,const CheckNotifyEventCallbackFunc & checkCallbackFunc)455 FileWatcher::FileWatcher(int32_t id, const CheckNotifyEventCallbackFunc &checkCallbackFunc)
456     : id_(id), eventCallbackFunc_(checkCallbackFunc)
457 {
458     filePath_ = Constants::USER_INFO_BASE + Constants::PATH_SEPARATOR + std::to_string(id) +
459         Constants::PATH_SEPARATOR + Constants::USER_INFO_FILE_NAME;
460 }
461 
FileWatcher(int32_t id,const std::string & filePath,const CheckNotifyEventCallbackFunc & checkCallbackFunc)462 FileWatcher::FileWatcher(int32_t id, const std::string &filePath,
463     const CheckNotifyEventCallbackFunc &checkCallbackFunc)
464     : id_(id), filePath_(filePath), eventCallbackFunc_(checkCallbackFunc)
465 {}
466 
~FileWatcher()467 FileWatcher::~FileWatcher()
468 {}
469 
GetFilePath() const470 std::string FileWatcher::GetFilePath() const
471 {
472     return filePath_;
473 }
474 
StartNotify(int32_t fd,const uint32_t & watchEvents)475 bool FileWatcher::StartNotify(int32_t fd, const uint32_t &watchEvents)
476 {
477     wd_ = inotify_add_watch(fd, filePath_.c_str(), watchEvents);
478     if (wd_ < 0) {
479         ACCOUNT_LOGE("failed to start notify, errCode:%{public}d", errno);
480         return false;
481     }
482     return true;
483 }
484 
CheckNotifyEvent(uint32_t event)485 bool FileWatcher::CheckNotifyEvent(uint32_t event)
486 {
487     if (eventCallbackFunc_ == nullptr) {
488         ACCOUNT_LOGW("eventCallbackFunc_ is nullptr.");
489         return false;
490     }
491     if (!eventCallbackFunc_(filePath_, id_, event)) {
492         ACCOUNT_LOGW("deal notify event failed.");
493         return false;
494     }
495     return true;
496 }
497 
GetLocalId() const498 int32_t FileWatcher::GetLocalId() const
499 {
500     return id_;
501 }
502 
GetWd() const503 int32_t FileWatcher::GetWd() const
504 {
505     return wd_;
506 }
507 
CloseNotify(int32_t fd)508 void FileWatcher::CloseNotify(int32_t fd)
509 {
510     if (inotify_rm_watch(fd, wd_) == -1) {
511         ACCOUNT_LOGE("failed to remove wd, err:%{public}d", errno);
512         if (access(filePath_.c_str(), F_OK) == 0) {
513             ACCOUNT_LOGE("file already exist");
514             return;
515         }
516     }
517     wd_ = -1;
518 }
519 #endif // ENABLE_FILE_WATCHER
520 }  // namespace AccountSA
521 }  // namespace OHOS