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