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