1 /*
2 * Copyright (c) 2022-2025 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 "cert_manager_file_operator.h"
17
18 #include <dirent.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24
25 #include "securec.h"
26
27 #include "cert_manager_mem.h"
28 #include "cert_manager_storage.h"
29 #include "cert_manager_updateflag.h"
30 #include "cm_log.h"
31
GetFileName(const char * path,const char * fileName,char * fullFileName,uint32_t fullFileNameLen)32 static int32_t GetFileName(const char *path, const char *fileName, char *fullFileName, uint32_t fullFileNameLen)
33 {
34 if (path != NULL && strlen(path) > 0) {
35 if (strncpy_s(fullFileName, fullFileNameLen, path, strlen(path)) != EOK) {
36 return CMR_ERROR_MEM_OPERATION_PRINT;
37 }
38
39 if (path[strlen(path) - 1] != '/') {
40 if (strncat_s(fullFileName, fullFileNameLen, "/", strlen("/")) != EOK) {
41 return CMR_ERROR_MEM_OPERATION_PRINT;
42 }
43 }
44
45 if (strncat_s(fullFileName, fullFileNameLen, fileName, strlen(fileName)) != EOK) {
46 return CMR_ERROR_MEM_OPERATION_PRINT;
47 }
48 } else {
49 if (strncpy_s(fullFileName, fullFileNameLen, fileName, strlen(fileName)) != EOK) {
50 return CMR_ERROR_MEM_OPERATION_PRINT;
51 }
52 }
53 return CMR_OK;
54 }
55
GetFullFileName(const char * path,const char * fileName,char ** fullFileName)56 static int32_t GetFullFileName(const char *path, const char *fileName, char **fullFileName)
57 {
58 uint32_t nameLen = CM_MAX_FILE_NAME_LEN;
59 char *tmpFileName = (char *)CMMalloc(nameLen);
60 if (tmpFileName == NULL) {
61 return CMR_ERROR_MALLOC_FAIL;
62 }
63 (void)memset_s(tmpFileName, nameLen, 0, nameLen);
64
65 int32_t ret = GetFileName(path, fileName, tmpFileName, nameLen);
66 if (ret != CMR_OK) {
67 CM_LOG_E("get full fileName failed");
68 CM_FREE_PTR(tmpFileName);
69 return ret;
70 }
71 *fullFileName = tmpFileName;
72
73 return CMR_OK;
74 }
75
IsFileExist(const char * fileName)76 static int32_t IsFileExist(const char *fileName)
77 {
78 if (access(fileName, F_OK) != 0) {
79 return CMR_ERROR_NOT_EXIST;
80 }
81
82 return CMR_OK;
83 }
84
CmIsDirExist(const char * path)85 int32_t CmIsDirExist(const char *path)
86 {
87 if (path == NULL) {
88 return CMR_ERROR_NULL_POINTER;
89 }
90 return IsFileExist(path);
91 }
92
FileRead(const char * fileName,uint32_t offset,uint8_t * buf,uint32_t len)93 static uint32_t FileRead(const char *fileName, uint32_t offset, uint8_t *buf, uint32_t len)
94 {
95 (void)offset;
96 if (IsFileExist(fileName) != CMR_OK) {
97 return 0;
98 }
99 if (strstr(fileName, "../") != NULL) {
100 CM_LOG_E("invalid filePath");
101 return 0;
102 }
103
104 char filePath[PATH_MAX + 1] = {0};
105 if (realpath(fileName, filePath) == NULL) {
106 CM_LOG_E("invalid filepath: %s", fileName);
107 return 0;
108 }
109
110 FILE *fp = fopen(filePath, "rb");
111 if (fp == NULL) {
112 CM_LOG_E("failed to open file");
113 return 0;
114 }
115
116 uint32_t size = fread(buf, 1, len, fp);
117 if (fclose(fp) < 0) {
118 CM_LOG_E("failed to close file");
119 return 0;
120 }
121
122 return size;
123 }
124
FileSize(const char * fileName)125 static uint32_t FileSize(const char *fileName)
126 {
127 if (IsFileExist(fileName) != CMR_OK) {
128 return 0;
129 }
130
131 struct stat fileStat;
132 (void)memset_s(&fileStat, sizeof(fileStat), 0, sizeof(fileStat));
133
134 if (stat(fileName, &fileStat) != 0) {
135 CM_LOG_E("file stat fail.");
136 return 0;
137 }
138
139 return (uint32_t)fileStat.st_size;
140 }
141
CreateFdsanOwnTag(void * addr)142 static uint64_t CreateFdsanOwnTag(void* addr)
143 {
144 uint64_t tag = 0;
145 if (addr != NULL) {
146 tag = fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, (uint64_t)addr);
147 }
148 return tag;
149 }
150
FileWrite(const char * fileName,uint32_t offset,const uint8_t * buf,uint32_t len,bool isWriteBakFile)151 static int32_t FileWrite(const char *fileName, uint32_t offset, const uint8_t *buf, uint32_t len, bool isWriteBakFile)
152 {
153 (void)offset;
154 char filePath[PATH_MAX + 1] = {0};
155 if (memcpy_s(filePath, sizeof(filePath) - 1, fileName, strlen(fileName)) != EOK) {
156 return CMR_ERROR_MEM_OPERATION_COPY;
157 }
158 if (strstr(filePath, "../") != NULL) {
159 CM_LOG_E("invalid filePath");
160 return CMR_ERROR_NOT_EXIST;
161 }
162 /* Ignore return value: realpath will return null in musl c when the file does not exist */
163 (void)realpath(fileName, filePath);
164
165 int32_t fd;
166 if (isWriteBakFile) {
167 fd = open(filePath, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
168 } else {
169 fd = open(filePath, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
170 }
171 if (fd < 0) {
172 CM_LOG_E("open file failed, errno = 0x%x", errno);
173 return CMR_ERROR_OPEN_FILE_FAIL;
174 }
175 uint64_t new_tag = CreateFdsanOwnTag(&fd);
176 fdsan_exchange_owner_tag(fd, 0, new_tag);
177
178 if (write(fd, buf, len) < 0) {
179 CM_LOG_E("write file failed, errno = 0x%x", errno);
180 fdsan_close_with_tag(fd, new_tag);
181 return CMR_ERROR_WRITE_FILE_FAIL;
182 }
183 if (fsync(fd) < 0) {
184 CM_LOG_E("sync file failed");
185 fdsan_close_with_tag(fd, new_tag);
186 return CMR_ERROR_WRITE_FILE_FAIL;
187 }
188 fdsan_close_with_tag(fd, new_tag);
189 return CMR_OK;
190 }
191
FileRemove(const char * fileName)192 static int32_t FileRemove(const char *fileName)
193 {
194 int32_t ret = IsFileExist(fileName);
195 if (ret != CMR_OK) {
196 return CMR_OK; /* if file not exist, return ok */
197 }
198
199 struct stat tmp;
200 if (stat(fileName, &tmp) != 0) {
201 return CMR_ERROR_FILE_STAT;
202 }
203
204 if (S_ISDIR(tmp.st_mode)) {
205 return CMR_ERROR_INVALID_ARGUMENT;
206 }
207
208 if ((unlink(fileName) != 0) && (errno != ENOENT)) {
209 CM_LOG_E("failed to remove file: errno = 0x%x", errno);
210 return CMR_ERROR_REMOVE_FILE_FAIL;
211 }
212
213 return CMR_OK;
214 }
215
CmFileRemove(const char * path,const char * fileName)216 int32_t CmFileRemove(const char *path, const char *fileName)
217 {
218 if (fileName == NULL) {
219 return CMR_ERROR_INVALID_ARGUMENT;
220 }
221
222 int32_t ret = CmIsFileExist(path, fileName);
223 if (ret != CMR_OK) {
224 CM_LOG_E("target file not exist");
225 return ret;
226 }
227
228 char *fullFileName = NULL;
229 ret = GetFullFileName(path, fileName, &fullFileName);
230 if (ret != CMR_OK) {
231 return ret;
232 }
233
234 ret = FileRemove(fullFileName);
235 CM_FREE_PTR(fullFileName);
236 return ret;
237 }
238
CmMakeDir(const char * path)239 int32_t CmMakeDir(const char *path)
240 {
241 if ((access(path, F_OK)) != -1) {
242 return CMR_OK;
243 }
244
245 if (mkdir(path, S_IRWXU) == 0) {
246 return CMR_OK;
247 } else {
248 if (errno == EEXIST || errno == EAGAIN) {
249 return CMR_ERROR_ALREADY_EXISTS;
250 } else {
251 return CMR_ERROR_MAKE_DIR_FAIL;
252 }
253 }
254 }
255
CmUserBakupMakeDir(const char * path,const mode_t * mode)256 int32_t CmUserBakupMakeDir(const char *path, const mode_t *mode)
257 {
258 mode_t modeTmp = S_IRWXU | S_IROTH | S_IXOTH; /* The default directory permission is 0705 */
259
260 if ((access(path, F_OK)) != -1) {
261 return CMR_OK;
262 }
263
264 if (mode != NULL) {
265 modeTmp = *mode;
266 }
267 if (mkdir(path, modeTmp) == 0) {
268 return CMR_OK;
269 } else {
270 if (errno == EEXIST || errno == EAGAIN) {
271 return CMR_ERROR_ALREADY_EXISTS;
272 } else {
273 return CMR_ERROR_MAKE_DIR_FAIL;
274 }
275 }
276 }
277
CmOpenDir(const char * path)278 void *CmOpenDir(const char *path)
279 {
280 return (void *)opendir(path);
281 }
282
CmCloseDir(void * dirp)283 int32_t CmCloseDir(void *dirp)
284 {
285 return closedir((DIR *)dirp);
286 }
287
CmGetDirFile(void * dirp,struct CmFileDirentInfo * direntInfo)288 int32_t CmGetDirFile(void *dirp, struct CmFileDirentInfo *direntInfo)
289 {
290 DIR *dir = (DIR *)dirp;
291 struct dirent *dire = readdir(dir);
292
293 while (dire != NULL) {
294 if (dire->d_type != DT_REG) { /* only care about files. */
295 dire = readdir(dir);
296 continue;
297 }
298
299 uint32_t len = strlen(dire->d_name);
300 if (memcpy_s(direntInfo->fileName, sizeof(direntInfo->fileName) - 1, dire->d_name, len) != EOK) {
301 return CMR_ERROR_MEM_OPERATION_COPY;
302 }
303 direntInfo->fileName[len] = '\0';
304 return CMR_OK;
305 }
306
307 return CMR_ERROR_NOT_EXIST;
308 }
309
CmFileRead(const char * path,const char * fileName,uint32_t offset,uint8_t * buf,uint32_t len)310 uint32_t CmFileRead(const char *path, const char *fileName, uint32_t offset, uint8_t *buf, uint32_t len)
311 {
312 if ((fileName == NULL) || (buf == NULL) || (len == 0)) {
313 return 0;
314 }
315
316 char *fullFileName = NULL;
317 int32_t ret = GetFullFileName(path, fileName, &fullFileName);
318 if (ret != CMR_OK) {
319 return 0;
320 }
321
322 uint32_t size = FileRead(fullFileName, offset, buf, len);
323 CM_FREE_PTR(fullFileName);
324 return size;
325 }
326
CmFileWrite(const char * path,const char * fileName,uint32_t offset,const uint8_t * buf,uint32_t len)327 int32_t CmFileWrite(const char *path, const char *fileName, uint32_t offset, const uint8_t *buf, uint32_t len)
328 {
329 if ((fileName == NULL) || (buf == NULL) || (len == 0)) {
330 return CMR_ERROR_INVALID_ARGUMENT;
331 }
332
333 char *fullFileName = NULL;
334 int32_t ret = GetFullFileName(path, fileName, &fullFileName);
335 if (ret != CMR_OK) {
336 return ret;
337 }
338
339 ret = FileWrite(fullFileName, offset, buf, len, false);
340 CM_FREE_PTR(fullFileName);
341 return ret;
342 }
343
CmUserBackupFileWrite(const char * path,const char * fileName,uint32_t offset,const uint8_t * buf,uint32_t len)344 int32_t CmUserBackupFileWrite(const char *path, const char *fileName, uint32_t offset, const uint8_t *buf, uint32_t len)
345 {
346 if ((fileName == NULL) || (buf == NULL) || (len == 0)) {
347 return CMR_ERROR_INVALID_ARGUMENT;
348 }
349
350 char *fullFileName = NULL;
351 int32_t ret = GetFullFileName(path, fileName, &fullFileName);
352 if (ret != CMR_OK) {
353 return ret;
354 }
355
356 ret = FileWrite(fullFileName, offset, buf, len, true);
357 CM_FREE_PTR(fullFileName);
358 return ret;
359 }
360
CmFileSize(const char * path,const char * fileName)361 uint32_t CmFileSize(const char *path, const char *fileName)
362 {
363 if (fileName == NULL) {
364 CM_LOG_E("fileName is NULL");
365 return 0;
366 }
367
368 char *fullFileName = NULL;
369 int32_t ret = GetFullFileName(path, fileName, &fullFileName);
370 if (ret != CMR_OK) {
371 CM_LOG_E("GetFullFileName failed");
372 return 0;
373 }
374
375 uint32_t size = FileSize(fullFileName);
376 CM_FREE_PTR(fullFileName);
377 return size;
378 }
379
CmUidLayerGetFileNames(const char * filePath,struct CmBlob * fileNames,const uint32_t arraySize,uint32_t count)380 static int32_t CmUidLayerGetFileNames(const char *filePath, struct CmBlob *fileNames,
381 const uint32_t arraySize, uint32_t count)
382 {
383 if (count >= arraySize) {
384 return CMR_ERROR_BUFFER_TOO_SMALL;
385 }
386 uint32_t filePathLen = strlen(filePath);
387 if (filePathLen >= CM_MAX_FILE_NAME_LEN) {
388 CM_LOG_E("CmUidLayerGetFileNames filePathLen:%u", filePathLen);
389 return CMR_ERROR_BUFFER_TOO_SMALL;
390 }
391
392 fileNames[count].data = (uint8_t *)CMMalloc(filePathLen + 1);
393 if (fileNames[count].data == NULL) {
394 return CMR_ERROR_MALLOC_FAIL;
395 }
396 (void)memset_s(fileNames[count].data, filePathLen + 1, 0, filePathLen + 1);
397 if (memcpy_s(fileNames[count].data, CM_MAX_FILE_NAME_LEN, filePath, filePathLen) != EOK) {
398 /* fileNames memory free in top layer function */
399 return CMR_ERROR_BUFFER_TOO_SMALL;
400 }
401 fileNames[count].size = filePathLen + 1; /* include '\0' at end */
402 return CM_SUCCESS;
403 }
404
CmUidLayerGetFileCountAndNames(const char * path,struct CmBlob * fileNames,const uint32_t arraySize,uint32_t * fileCount)405 int32_t CmUidLayerGetFileCountAndNames(const char *path, struct CmBlob *fileNames,
406 const uint32_t arraySize, uint32_t *fileCount)
407 {
408 /* do nothing when dir is not exist */
409 if (CmIsDirExist(path) != CMR_OK) {
410 CM_LOG_D("Uid layer dir is not exist");
411 return CM_SUCCESS;
412 }
413 DIR *dir = opendir(path);
414 if (dir == NULL) {
415 CM_LOG_E("open uid layer dir failed");
416 return CMR_ERROR_FILE_OPEN_DIR;
417 }
418
419 int32_t ret = CM_SUCCESS;
420 uint32_t count = *fileCount;
421 struct dirent *dire = readdir(dir);
422 while (dire != NULL) {
423 char uidPath[CM_MAX_FILE_NAME_LEN] = {0};
424 if (strncpy_s(uidPath, sizeof(uidPath), path, strlen(path)) != EOK) {
425 ret = CMR_ERROR_MEM_OPERATION_COPY;
426 break;
427 }
428
429 if (uidPath[strlen(uidPath) - 1] != '/') {
430 if (strncat_s(uidPath, sizeof(uidPath), "/", strlen("/")) != EOK) {
431 ret = CMR_ERROR_MEM_OPERATION_COPY;
432 break;
433 }
434 }
435
436 if (strncat_s(uidPath, sizeof(uidPath), dire->d_name, strlen(dire->d_name)) != EOK) {
437 ret = CMR_ERROR_MEM_OPERATION_COPY;
438 break;
439 }
440
441 if ((dire->d_type == DT_REG) && (strcmp("..", dire->d_name) != 0) && (strcmp(".", dire->d_name) != 0)) {
442 ret = CmUidLayerGetFileNames(uidPath, fileNames, arraySize, count);
443 if (ret != CM_SUCCESS) {
444 break;
445 }
446 count++;
447 }
448 dire = readdir(dir);
449 }
450 *fileCount = count;
451 closedir(dir);
452 return ret;
453 }
454
CmUserIdLayerGetFileCountAndNames(const char * path,struct CmBlob * fileNames,const uint32_t arraySize,uint32_t * fileCount)455 int32_t CmUserIdLayerGetFileCountAndNames(const char *path, struct CmBlob *fileNames,
456 const uint32_t arraySize, uint32_t *fileCount)
457 {
458 char userIdPath[CM_MAX_FILE_NAME_LEN] = { 0 };
459 /* do nothing when dir is not exist */
460 if (CmIsDirExist(path) != CMR_OK) {
461 CM_LOG_D("UserId layer dir is not exist");
462 return CM_SUCCESS;
463 }
464 DIR *dir = opendir(path);
465 if (dir == NULL) {
466 CM_LOG_E("open userId layer dir failed");
467 return CMR_ERROR_FILE_OPEN_DIR;
468 }
469 struct dirent *dire = readdir(dir);
470 while (dire != NULL) {
471 (void)memset_s(userIdPath, CM_MAX_FILE_NAME_LEN, 0, CM_MAX_FILE_NAME_LEN);
472 if (strncpy_s(userIdPath, sizeof(userIdPath), path, strlen(path)) != EOK) {
473 closedir(dir);
474 return CMR_ERROR_MEM_OPERATION_COPY;
475 }
476
477 if (userIdPath[strlen(userIdPath) - 1] != '/') {
478 if (strncat_s(userIdPath, sizeof(userIdPath), "/", strlen("/")) != EOK) {
479 closedir(dir);
480 return CMR_ERROR_MEM_OPERATION_COPY;
481 }
482 }
483
484 if (strncat_s(userIdPath, sizeof(userIdPath), dire->d_name, strlen(dire->d_name)) != EOK) {
485 closedir(dir);
486 return CMR_ERROR_MEM_OPERATION_COPY;
487 }
488
489 if ((dire->d_type == DT_DIR) && (strcmp("..", dire->d_name) != 0) && (strcmp(".", dire->d_name) != 0)) {
490 if (CmUidLayerGetFileCountAndNames(userIdPath, fileNames, arraySize, fileCount) != CM_SUCCESS) {
491 CM_LOG_E("CmUidLayerGetFileCountAndNames faild");
492 closedir(dir);
493 return CM_FAILURE;
494 }
495 } else if (dire->d_type != DT_DIR) {
496 (void)remove(userIdPath);
497 }
498 dire = readdir(dir);
499 }
500 closedir(dir);
501 return CM_SUCCESS;
502 }
503
CmIsFileExist(const char * path,const char * fileName)504 int32_t CmIsFileExist(const char *path, const char *fileName)
505 {
506 if (fileName == NULL) {
507 CM_LOG_E("fileName is NULL");
508 return CMR_ERROR_INVALID_ARGUMENT;
509 }
510
511 char *fullFileName = NULL;
512 int32_t ret = GetFullFileName(path, fileName, &fullFileName);
513 if (ret != CM_SUCCESS) {
514 CM_LOG_E("GetFullFileName failed");
515 return ret;
516 }
517
518 ret = IsFileExist(fullFileName);
519 CM_FREE_PTR(fullFileName);
520 return ret;
521 }
522
CmGetSubDir(void * dirp,struct CmFileDirentInfo * direntInfo)523 int32_t CmGetSubDir(void *dirp, struct CmFileDirentInfo *direntInfo)
524 {
525 DIR *dir = (DIR *)dirp;
526 struct dirent *dire = readdir(dir);
527
528 while (dire != NULL) {
529 if ((dire->d_type != DT_DIR) || (strcmp(dire->d_name, ".") == 0) ||
530 (strcmp(dire->d_name, "..") == 0)) {
531 dire = readdir(dir);
532 continue;
533 }
534
535 uint32_t dirLen = strlen(dire->d_name);
536 if (memcpy_s(direntInfo->fileName, sizeof(direntInfo->fileName) - 1, dire->d_name, dirLen) != EOK) {
537 return CMR_ERROR_MEM_OPERATION_COPY;
538 }
539 direntInfo->fileName[dirLen] = '\0';
540 return CMR_OK;
541 }
542
543 return CMR_ERROR_NOT_EXIST;
544 }
545
DirRemove(const char * path)546 static int32_t DirRemove(const char *path)
547 {
548 if (access(path, F_OK) != 0) {
549 return CMR_ERROR_NOT_EXIST;
550 }
551
552 struct stat tmp;
553 if (stat(path, &tmp) != 0) {
554 return CMR_ERROR_FILE_STAT;
555 }
556
557 if (S_ISDIR(tmp.st_mode)) {
558 uint32_t i = 0;
559 struct dirent *dire = NULL;
560 DIR *dirp = opendir(path);
561 if (dirp == NULL) {
562 CM_LOG_E("open dir failed");
563 return CMR_ERROR_OPEN_FILE_FAIL;
564 }
565 while ((dire = readdir(dirp)) != NULL) {
566 if ((strcmp(dire->d_name, ".") == 0) || (strcmp(dire->d_name, "..") == 0)) {
567 continue;
568 }
569 i++;
570 }
571 closedir(dirp);
572
573 if (i != 0) {
574 CM_LOG_E("Dir is not empty");
575 return CMR_ERROR_INVALID_ARGUMENT;
576 }
577 rmdir(path);
578 return CMR_OK;
579 }
580 return CMR_ERROR_INVALID_ARGUMENT;
581 }
582
CmDirRemove(const char * path)583 int32_t CmDirRemove(const char *path)
584 {
585 if (path == NULL) {
586 return CMR_ERROR_INVALID_ARGUMENT;
587 }
588
589 return DirRemove(path);
590 }
591