1 /*
2  * Copyright (c) 2024-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_file_transfer.h"
17 
18 #include "hks_cfi.h"
19 #include "hks_config_parser.h"
20 #include "hks_file_operator.h"
21 #include "hks_log.h"
22 #include "hks_mem.h"
23 #include "hks_template.h"
24 #include "hks_type_inner.h"
25 
26 #include "hks_storage_utils.h"
27 #include "hisysevent_wrapper.h"
28 
29 #include <errno.h>
30 #include <ftw.h>
31 #include <stdio.h>
32 #include <string.h>
33 
34 #define OPEN_FDS 64
35 
36 uint32_t g_frontUserId = 100;
37 
GetStoreMaterial(const struct HksBlob * alias,const struct HksUpgradeFileTransferInfo * info,struct HksStoreMaterial * outMaterial)38 static int32_t GetStoreMaterial(const struct HksBlob *alias, const struct HksUpgradeFileTransferInfo *info,
39     struct HksStoreMaterial *outMaterial)
40 {
41     outMaterial->pathType = info->needDe ? DE_PATH : CE_PATH;
42     outMaterial->keyAliasPath = (char *)HksMalloc(HKS_MAX_FILE_NAME_LEN);
43     if (outMaterial->keyAliasPath == NULL) {
44         return HKS_ERROR_MALLOC_FAIL;
45     }
46     int32_t ret = ConstructName(alias, outMaterial->keyAliasPath, HKS_MAX_FILE_NAME_LEN);
47     HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "construct key alias name failed.")
48 
49     outMaterial->uidPath = (char *)HksMalloc(HKS_MAX_DIRENT_FILE_LEN);
50     HKS_IF_NULL_RETURN(outMaterial->uidPath, HKS_ERROR_MALLOC_FAIL);
51 
52     struct HksBlob uidBlob = { .data = (uint8_t *)&info->uid, .size = sizeof(info->uid) };
53     ret = ConstructPlainName(&uidBlob, outMaterial->uidPath, HKS_MAX_DIRENT_FILE_LEN);
54     HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "construct uid path failed.")
55 
56     outMaterial->userIdPath = (char *)HksMalloc(HKS_MAX_DIRENT_FILE_LEN);
57     HKS_IF_NULL_RETURN(outMaterial->userIdPath, HKS_ERROR_MALLOC_FAIL);
58 
59     struct HksBlob userIdBlob = { 0 };
60 
61     if (info->needFrontUser) {
62         userIdBlob.data = (uint8_t *)&g_frontUserId;
63         userIdBlob.size = sizeof(g_frontUserId);
64     } else {
65         userIdBlob.data = (uint8_t *)&info->userId;
66         userIdBlob.size = sizeof(info->userId);
67     }
68 
69     ret = ConstructPlainName(&userIdBlob, outMaterial->userIdPath, HKS_MAX_DIRENT_FILE_LEN);
70     HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "construct user id path failed.")
71 
72     outMaterial->storageTypePath = (char *)HksMalloc(sizeof(HKS_KEY_STORE_KEY_PATH) + 1);
73     HKS_IF_NULL_RETURN(outMaterial->storageTypePath, HKS_ERROR_MALLOC_FAIL);
74 
75     (void)memcpy_s(outMaterial->storageTypePath, sizeof(HKS_KEY_STORE_KEY_PATH),
76         HKS_KEY_STORE_KEY_PATH, sizeof(HKS_KEY_STORE_KEY_PATH));
77 
78     return ret;
79 }
80 
ConstructNewFilePath(const char * alias,const struct HksUpgradeFileTransferInfo * info,char ** newPath)81 static int32_t ConstructNewFilePath(const char *alias, const struct HksUpgradeFileTransferInfo *info,
82     char **newPath)
83 {
84     int32_t ret;
85 #ifdef SUPPORT_STORAGE_BACKUP
86     struct HksStoreFileInfo fileInfo = { { 0 }, { 0 } };
87 #else
88     struct HksStoreFileInfo fileInfo = { { 0 } };
89 #endif
90     struct HksStoreMaterial storeMaterial = { DE_PATH, 0 };
91     struct HksBlob aliasBlob = { .data = (uint8_t *)alias, .size = strlen(alias) };
92     do {
93         ret = GetStoreMaterial(&aliasBlob, info, &storeMaterial);
94         HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "get store material failed.")
95 
96         ret = HksGetFileInfo(&storeMaterial, &fileInfo);
97         if (ret != HKS_SUCCESS) {
98             HKS_LOG_E("get file info failed.");
99             break;
100         };
101         *newPath = (char *)HksMalloc(strlen(fileInfo.mainPath.path) + 1);
102         if (*newPath == NULL) {
103             HKS_LOG_E("malloc newPath->data failed.");
104             ret = HKS_ERROR_MALLOC_FAIL;
105             break;
106         }
107         (void)memcpy_s(*newPath, strlen(fileInfo.mainPath.path),
108             fileInfo.mainPath.path, strlen(fileInfo.mainPath.path));
109     } while (false);
110     FileInfoFree(&fileInfo);
111     HKS_FREE(storeMaterial.userIdPath);
112     HKS_FREE(storeMaterial.uidPath);
113     HKS_FREE(storeMaterial.storageTypePath);
114     HKS_FREE(storeMaterial.keyAliasPath);
115     return ret;
116 }
117 
TransferFile(const char * alias,const char * oldPath,const struct HksBlob * fileContent,const struct HksUpgradeFileTransferInfo * info)118 static int32_t TransferFile(const char *alias, const char *oldPath, const struct HksBlob *fileContent,
119     const struct HksUpgradeFileTransferInfo *info)
120 {
121     int32_t ret;
122     char *newPath = NULL;
123     do {
124         ret = ConstructNewFilePath(alias, info, &newPath);
125         if (ret != HKS_SUCCESS) {
126             HKS_LOG_E("construct new file path failed.");
127             break;
128         }
129 
130         // Check if the alias is of rdb key file. If it is, skip the checking of duplicate to overwrite key file.
131         if (HksIsRdbDeKey(alias) && info->needDe) {
132             HKS_LOG_I("Remove rbd key file in de path, to accept the old file.");
133             ret = HksFileRemove(newPath, alias);
134             if (ret != HKS_SUCCESS) {
135                 HKS_LOG_E("remove DE rdb file in %" LOG_PUBLIC "s write failed.", newPath);
136                 break;
137             }
138         } else {
139             ret = HksIsFileExist(newPath, alias);
140             if (ret == HKS_SUCCESS) {
141                 HKS_LOG_E("file in %" LOG_PUBLIC "s already exists.", newPath);
142                 // try remove old key file, it is ok if fails.
143                 (void)HksFileRemove(oldPath, alias);
144                 break;
145             }
146         }
147 
148         ret = HksMakeFullDir(newPath);
149         if (ret != HKS_SUCCESS) {
150             HKS_LOG_E("make dir %" LOG_PUBLIC "s writefailed.", newPath);
151             break;
152         }
153 
154         // The result of the info record dose not need to take into consideration.
155         (void)RecordKeyOperation(KEY_OPERATION_SAVE, newPath, alias);
156 
157         ret = HksFileWrite(newPath, alias, 0, fileContent->data, fileContent->size);
158         if (ret != HKS_SUCCESS) {
159             HKS_LOG_E("file %" LOG_PUBLIC "s write failed.", newPath);
160             break;
161         }
162 
163         ret = HksFileRemove(oldPath, alias);
164         if (ret != HKS_SUCCESS) {
165             HKS_LOG_E("file in %" LOG_PUBLIC "s remove failed.", oldPath);
166             // remove new file in case of old file removing fails, for avoiding double backup problem
167             if (HksFileRemove(newPath, alias) != HKS_SUCCESS) {
168                 HKS_LOG_E("try remove new file in %" LOG_PUBLIC "s failed.", newPath);
169             } else {
170                 HKS_LOG_I("remove new file success.");
171             }
172         }
173     } while (false);
174     HKS_FREE(newPath);
175 
176     return ret;
177 }
178 
SplitPath(const char * filePath,const struct FTW * ftw,char ** path,char ** alias)179 static int32_t SplitPath(const char *filePath, const struct FTW *ftw, char **path, char **alias)
180 {
181     *alias = (char *)HksMalloc(strlen(filePath) + 1 - ftw->base);
182     if (*alias == NULL) {
183         return HKS_ERROR_MALLOC_FAIL;
184     }
185     (void)memcpy_s(*alias, strlen(filePath) - ftw->base, filePath + ftw->base, strlen(filePath) - ftw->base);
186 
187     *path = (char *)HksMalloc(ftw->base + 1);
188     if (*path == NULL) {
189         return HKS_ERROR_MALLOC_FAIL;
190     }
191     (void)memcpy_s(*path, ftw->base, filePath, ftw->base);
192 
193     HKS_LOG_I("path is %" LOG_PUBLIC "s.", *path);
194 
195     return HKS_SUCCESS;
196 }
197 
GetFileContent(const char * path,const char * alias,struct HksBlob * fileContent)198 static int32_t GetFileContent(const char *path, const char *alias, struct HksBlob *fileContent)
199 {
200     uint32_t size = HksFileSize(path, alias);
201     if (size == 0) {
202         return HKS_ERROR_FILE_SIZE_FAIL;
203     }
204     fileContent->data = (uint8_t *)HksMalloc(size);
205     HKS_IF_NULL_RETURN(fileContent->data, HKS_ERROR_MALLOC_FAIL)
206 
207     fileContent->size = size;
208     return HksFileRead(path, alias, 0, fileContent, &fileContent->size);
209 }
210 
ProcessFileUpgrade(const char * filePath,const struct stat * st,int typeFlag,struct FTW * ftw)211 static int ProcessFileUpgrade(const char *filePath, const struct stat *st, int typeFlag, struct FTW *ftw)
212 {
213     (void)st;
214     if (typeFlag != FTW_F) {
215         HKS_LOG_D("%" LOG_PUBLIC "s not a file", filePath);
216         return 0;
217     }
218     char *alias = NULL;
219     char *path = NULL;
220     struct HksBlob fileContent = { 0 };
221     int32_t ret;
222     do {
223         ret = SplitPath(filePath, ftw, &path, &alias);
224         HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "split filePath failed.")
225 
226         ret = GetFileContent(path, alias, &fileContent);
227         HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "get file content failed.")
228 
229         struct HksUpgradeFileTransferInfo info = { 0 };
230         ret = HksParseConfig(alias, &fileContent, &info);
231         if (ret != HKS_SUCCESS) {
232             HKS_LOG_E("HksParseConfig failed, path is %" LOG_PUBLIC "s", filePath);
233             break;
234         }
235         if (info.skipTransfer) {
236             HKS_LOG_I("file %" LOG_PUBLIC "s should skip transfer.", filePath);
237             break;
238         }
239         HKS_IF_NOT_SUCC_LOGE(TransferFile(alias, path, &fileContent, &info), "TransferFile failed!")
240     } while (false);
241     HKS_FREE(path);
242     HKS_FREE(alias);
243     HKS_FREE_BLOB(fileContent);
244 
245     // continue to traverse files
246     return 0;
247 }
248 
ENABLE_CFI(int32_t UpgradeFileTransfer (void))249 ENABLE_CFI(int32_t UpgradeFileTransfer(void))
250 {
251     // depth first and ignore soft link
252     int nftwRet = nftw(HKS_KEY_STORE_TMP_PATH, ProcessFileUpgrade, OPEN_FDS, FTW_DEPTH | FTW_PHYS);
253     HKS_LOG_I("call nftw result is %" LOG_PUBLIC "d.", nftwRet);
254 
255     return HKS_SUCCESS;
256 }
257 
CopyDeToTmpPathIfNeed(void)258 static int32_t CopyDeToTmpPathIfNeed(void)
259 {
260     if (HksIsDirExist(HKS_KEY_STORE_TMP_PATH) == HKS_SUCCESS) {
261         return HKS_SUCCESS;
262     }
263     int32_t ret = rename(HKS_KEY_STORE_PATH, HKS_KEY_STORE_TMP_PATH);
264     if (ret != 0) {
265         HKS_LOG_E("move de file path to old file path failed, error code is %" LOG_PUBLIC "d.", errno);
266         return HKS_ERROR_MAKE_DIR_FAIL;
267     }
268     ret = HksMakeDir(HKS_KEY_STORE_PATH);
269     if (ret != HKS_SUCCESS) {
270         HKS_LOG_E("create de path failed, error code is %" LOG_PUBLIC "d.", ret);
271         return HKS_ERROR_MAKE_DIR_FAIL;
272     }
273     HKS_LOG_I("move de file path to old file path");
274     return HKS_SUCCESS;
275 }
276 
HksUpgradeFileTransferOnPowerOn(void)277 int32_t HksUpgradeFileTransferOnPowerOn(void)
278 {
279     WritePerformanceEvent(HUKS_TRANSFER_KEY);
280     CopyDeToTmpPathIfNeed();
281     return UpgradeFileTransfer();
282 }
283 
HksUpgradeFileTransferOnUserUnlock(uint32_t userId)284 int32_t HksUpgradeFileTransferOnUserUnlock(uint32_t userId)
285 {
286     g_frontUserId = userId;
287     return HksUpgradeFileTransferOnPowerOn();
288 }
289