• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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 <errno.h>
17 #include <fcntl.h>
18 #include <hvb_cmdline.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 
22 #include "beget_ext.h"
23 #include "fs_dm.h"
24 #include "fs_hvb.h"
25 #include "securec.h"
26 #include "init_utils.h"
27 #include "hookmgr.h"
28 #include "bootstage.h"
29 #include "fs_manager.h"
30 #include "list.h"
31 
32 #ifdef __cplusplus
33 #if __cplusplus
34 extern "C" {
35 #endif
36 #endif
37 
38 #define PARTITION_PATH_PREFIX "/dev/block/by-name/"
39 #define SNAPSHOT_PATH_PREFIX "/dev/block/"
40 #define MAX_EXT_HVB_PARTITION_NUM 1
41 #define FS_HVB_LOCK_STATE_STR_MAX 32
42 
43 static const ExtHvbVerifiedDev g_extVerifiedDev[] = {
44     {
45         .partitionName = "module_update",
46         .pathName = "/data/module_update/active/ModuleTrain/module.img"
47     },
48 };
49 
GetImageSizeForHVB(const int fd,const char * image)50 static int64_t GetImageSizeForHVB(const int fd, const char* image)
51 {
52     char headerBuf[SZ_2KB] = {0};
53     ssize_t nbytes;
54     uint64_t fileSysSize;
55     uint64_t realFileSize;
56 
57     if (fd < 0) {
58         BEGET_LOGE("param is error");
59         return -1;
60     }
61 
62     lseek64(fd, 0, SEEK_SET);
63     nbytes = read(fd, &headerBuf, sizeof(headerBuf));
64     if (nbytes != sizeof(headerBuf)) {
65         BEGET_LOGE("read file system header fail");
66         return -1;
67     }
68 
69     if (CheckAndGetErofsSize(&headerBuf[SZ_1KB], &fileSysSize, image) &&
70         CheckAndGetExtheaderSize(fd, fileSysSize, &realFileSize, image)) {
71         BEGET_LOGI("get %s size from erofs and extheader, size=0x%lx", image, realFileSize);
72         return realFileSize;
73     } else if (CheckAndGetExt4Size(&headerBuf[SZ_1KB], &fileSysSize, image) &&
74         CheckAndGetExtheaderSize(fd, fileSysSize, &realFileSize, image)) {
75         BEGET_LOGI("get %s size from ext4 and extheader, size=0x%lx", image, realFileSize);
76         return realFileSize;
77     } else {
78         BEGET_LOGI("read %s file extheader fail, use the actual img size", image);
79     }
80 
81     return lseek64(fd, 0, SEEK_END);
82 }
83 
IsExtHvbVerifiedPtn(const char * ptn,size_t ptnLen,size_t * outIndex)84 static bool IsExtHvbVerifiedPtn(const char *ptn, size_t ptnLen, size_t *outIndex)
85 {
86     int index;
87     if (ptn == NULL || outIndex == NULL) {
88         BEGET_LOGE("error, invalid ptn");
89         return false;
90     }
91 
92     for (index = 0; index < MAX_EXT_HVB_PARTITION_NUM; index++) {
93         if (strncmp(g_extVerifiedDev[index].partitionName, ptn, ptnLen) == 0) {
94             *outIndex = index;
95             return true;
96         }
97     }
98 
99     return false;
100 }
101 
GetExtHvbVerifiedPath(size_t index)102 static char *GetExtHvbVerifiedPath(size_t index)
103 {
104     char *tmpPath = NULL;
105 
106     if (index >= MAX_EXT_HVB_PARTITION_NUM) {
107         BEGET_LOGE("error, invalid index");
108         return NULL;
109     }
110 
111     size_t pathLen = strnlen(g_extVerifiedDev[index].pathName, FS_HVB_MAX_PATH_LEN);
112     if (pathLen >= FS_HVB_MAX_PATH_LEN) {
113         BEGET_LOGE("error, invalid path");
114         return tmpPath;
115     }
116     tmpPath = malloc(pathLen + 1);
117     if (tmpPath == NULL) {
118         BEGET_LOGE("error, fail to malloc");
119         return NULL;
120     }
121 
122     (void)memset_s(tmpPath, pathLen + 1, 0, pathLen + 1);
123     if (memcpy_s(tmpPath, pathLen + 1, g_extVerifiedDev[index].pathName, pathLen) != 0) {
124         free(tmpPath);
125         BEGET_LOGE("error, fail to copy");
126         return NULL;
127     }
128     return tmpPath;
129 }
130 
HvbGetABPartitionPath(const size_t pathLen,const char * partition)131 static char *HvbGetABPartitionPath(const size_t pathLen, const char *partition)
132 {
133     /* Check if there are multiple partitions */
134     char *path = NULL;
135     int bootSlots = GetBootSlots();
136     if (bootSlots <= 1) {
137         BEGET_LOGE("invalid bootSlots: %d", bootSlots);
138         goto err;
139     }
140 
141     /* Confirm partition information */
142     /* slot = 1 is partition a */
143     /* slot = 2 is partition b */
144     int slot = GetCurrentSlot();
145     if (slot <= 0 || slot > MAX_SLOT) {
146         BEGET_LOGW("invalid slot [%d], defaulting to 1", slot);
147         slot = 1;
148     }
149 
150     size_t abPathLen = pathLen + FS_HVB_AB_SUFFIX_LEN;
151     path = calloc(1, abPathLen + 1);
152     if (path == NULL) {
153         BEGET_LOGE("error, calloc fail");
154         goto err;
155     }
156 
157     /* Concatenate partition names */
158     const char suffix = 'a' + slot - 1;
159     int rc = snprintf_s(path, abPathLen + 1, abPathLen, "%s%s_%c",
160                         PARTITION_PATH_PREFIX, partition, suffix);
161     if (rc < 0) {
162         BEGET_LOGE("snprintf_s fail, ret = %d", rc);
163         goto err;
164     }
165     if (access(path, F_OK) != 0) {
166         BEGET_LOGE("still can not access %s, abort verify", path);
167         goto err;
168     }
169 
170     BEGET_LOGW("AB path generated: %s", path);
171     return path;
172 
173 err:
174     if (path != NULL) {
175         free(path);
176     }
177 
178     return NULL;
179 }
180 
HvbGetSnapshotPath(const char * partition,char * out,size_t outLen)181 static int HvbGetSnapshotPath(const char *partition, char *out, size_t outLen)
182 {
183     int rc;
184     HvbDeviceParam devPara = {};
185     HOOK_EXEC_OPTIONS options = {};
186     if (memcpy_s(devPara.partName, sizeof(devPara.partName), partition, strlen(partition)) != 0) {
187         BEGET_LOGE("error, fail to copy partition");
188         return HVB_IO_ERROR_IO;
189     }
190     devPara.reverse = 0;
191     devPara.len = (int)sizeof(devPara.value);
192     options.flags = TRAVERSE_STOP_WHEN_ERROR;
193     options.preHook = NULL;
194     options.postHook = NULL;
195 
196     rc = HookMgrExecute(GetBootStageHookMgr(), INIT_VAB_HVBCHECK, (void *)&devPara, &options);
197     BEGET_LOGW("check snapshot path for partition %s, ret = %d", partition, rc);
198     if (rc != 0) {
199         BEGET_LOGE("error 0x%x, trans vab for %s", rc, partition);
200         return rc;
201     }
202     BEGET_LOGW("snapshot path exists for partition %s", partition);
203     rc = snprintf_s(out, outLen, outLen - 1, "%s%s", SNAPSHOT_PATH_PREFIX,
204                     devPara.value);
205     if (rc < 0) {
206         BEGET_LOGE("error, snprintf_s snapshot path fail, ret = %d", rc);
207         return rc;
208     }
209     return 0;
210 }
211 
HvbGetPartitionPath(const char * partition)212 static char *HvbGetPartitionPath(const char *partition)
213 {
214     int rc;
215     size_t pathLen;
216     char *path = NULL;
217     size_t index;
218     size_t ptnLen = strnlen(partition, HVB_MAX_PARTITION_NAME_LEN);
219     if (ptnLen >= HVB_MAX_PARTITION_NAME_LEN) {
220         BEGET_LOGE("error, invalid ptn name");
221         return NULL;
222     }
223     if (IsExtHvbVerifiedPtn(partition, ptnLen, &index)) {
224         return GetExtHvbVerifiedPath(index);
225     }
226 
227     pathLen = strlen(PARTITION_PATH_PREFIX) + HVB_MAX_PARTITION_NAME_LEN - 1;
228     path = calloc(1, pathLen + 1);
229     if (path == NULL) {
230         BEGET_LOGE("error, calloc fail");
231         return NULL;
232     }
233 
234     if (HvbGetSnapshotPath(partition, path, pathLen) == 0) {
235         return path;
236     }
237 
238     rc = snprintf_s(path, pathLen + 1, pathLen, "%s%s", PARTITION_PATH_PREFIX,
239                     partition);
240     if (rc < 0) {
241         BEGET_LOGE("error, snprintf_s fail, ret = %d", rc);
242         free(path);
243         return NULL;
244     }
245 
246     if (access(path, F_OK) != 0) {
247         BEGET_LOGW("Adapting to AB partition");
248         free(path);
249         return HvbGetABPartitionPath(pathLen, partition);
250     }
251 
252     return path;
253 }
254 
HvbReadFromPartition(struct hvb_ops * ops,const char * partition,int64_t offset,uint64_t numBytes,void * buf,uint64_t * outNumRead)255 static enum hvb_io_errno HvbReadFromPartition(struct hvb_ops* ops,
256                                               const char* partition,
257                                               int64_t offset, uint64_t numBytes,
258                                               void* buf, uint64_t* outNumRead)
259 {
260     int fd = -1;
261     char *path = NULL;
262     enum hvb_io_errno ret = HVB_IO_ERROR_IO;
263 
264     if (ops == NULL || partition == NULL ||
265         buf == NULL || outNumRead == NULL) {
266         BEGET_LOGE("error, invalid parameter");
267         return HVB_IO_ERROR_IO;
268     }
269 
270     /* get and malloc img path */
271     path = HvbGetPartitionPath(partition);
272     if (path == NULL) {
273         BEGET_LOGE("error, get partition path");
274         ret = HVB_IO_ERROR_OOM;
275         goto exit;
276     }
277 
278     fd = open(path, O_RDONLY | O_CLOEXEC);
279     if (fd < 0) {
280         BEGET_LOGE("error, Failed to open %s, errno = %d", path, errno);
281         ret = HVB_IO_ERROR_IO;
282         goto exit;
283     }
284 
285     if (offset < 0) {
286         int64_t total_size = GetImageSizeForHVB(fd, partition);
287         if (total_size == -1) {
288             BEGET_LOGE("Failed to get the size of the partition %s", partition);
289             ret = HVB_IO_ERROR_IO;
290             goto exit;
291         }
292         offset = total_size + offset;
293     }
294 
295     lseek64(fd, offset, SEEK_SET);
296 
297     ssize_t numRead = read(fd, buf, numBytes);
298     if (numRead < 0 || (size_t)numRead != numBytes) {
299         BEGET_LOGE("Failed to read %lld bytes from %s offset %lld", numBytes,
300                    path, offset);
301         ret = HVB_IO_ERROR_IO;
302         goto exit;
303     }
304 
305     *outNumRead = numRead;
306 
307     ret = HVB_IO_OK;
308 
309 exit:
310 
311     if (path != NULL) {
312         free(path);
313     }
314 
315     if (fd >= 0) {
316         close(fd);
317     }
318     return ret;
319 }
320 
HvbWriteToPartition(struct hvb_ops * ops,const char * partition,int64_t offset,uint64_t numBytes,const void * buf)321 static enum hvb_io_errno HvbWriteToPartition(struct hvb_ops* ops,
322                                              const char* partition,
323                                              int64_t offset, uint64_t numBytes,
324                                              const void* buf)
325 {
326     return HVB_IO_OK;
327 }
328 
HvbInvaldateKey(struct hvb_ops * ops,const uint8_t * publicKeyData,uint64_t publicKeyLength,const uint8_t * publicKeyMetadata,uint64_t publicKeyMetadataLength,bool * outIsTrusted)329 static enum hvb_io_errno HvbInvaldateKey(struct hvb_ops* ops,
330                                          const uint8_t* publicKeyData,
331                                          uint64_t publicKeyLength,
332                                          const uint8_t* publicKeyMetadata,
333                                          uint64_t publicKeyMetadataLength,
334                                          bool* outIsTrusted)
335 {
336     if (outIsTrusted == NULL) {
337         return HVB_IO_ERROR_IO;
338     }
339 
340     *outIsTrusted = true;
341 
342     return HVB_IO_OK;
343 }
344 
HvbReadRollbackIdx(struct hvb_ops * ops,uint64_t rollBackIndexLocation,uint64_t * outRollbackIndex)345 static enum hvb_io_errno HvbReadRollbackIdx(struct hvb_ops* ops,
346                                             uint64_t rollBackIndexLocation,
347                                             uint64_t* outRollbackIndex)
348 {
349     if (outRollbackIndex == NULL) {
350         return HVB_IO_ERROR_IO;
351     }
352 
353     // return 0 as we only need to set up HVB HASHTREE partitions
354     *outRollbackIndex = 0;
355 
356     return HVB_IO_OK;
357 }
358 
HvbWriteRollbackIdx(struct hvb_ops * ops,uint64_t rollBackIndexLocation,uint64_t rollbackIndex)359 static enum hvb_io_errno HvbWriteRollbackIdx(struct hvb_ops* ops,
360                                              uint64_t rollBackIndexLocation,
361                                              uint64_t rollbackIndex)
362 {
363     return HVB_IO_OK;
364 }
365 
FsHvbGetLockStateStr(char * str,size_t size)366 static int FsHvbGetLockStateStr(char *str, size_t size)
367 {
368     return FsHvbGetValueFromCmdLine(str, size, HVB_CMDLINE_DEV_STATE);
369 }
370 
HvbReadLockState(struct hvb_ops * ops,bool * locked)371 static enum hvb_io_errno HvbReadLockState(struct hvb_ops *ops,
372                                           bool *locked)
373 {
374     char lockState[FS_HVB_LOCK_STATE_STR_MAX] = {0};
375     if (ops == NULL || locked == NULL) {
376         BEGET_LOGE("Invalid lock state parameter");
377         return HVB_IO_ERROR_IO;
378     }
379 
380     int ret = FsHvbGetLockStateStr(&lockState[0], sizeof(lockState));
381     if (ret != 0) {
382         BEGET_LOGE("error 0x%x, get lock state from cmdline", ret);
383         return HVB_IO_ERROR_NO_SUCH_VALUE;
384     }
385 
386     if (strncmp(&lockState[0], "locked", FS_HVB_LOCK_STATE_STR_MAX) == 0) {
387         *locked = true;
388     } else if (strncmp(&lockState[0], "unlocked", FS_HVB_LOCK_STATE_STR_MAX) == 0) {
389         *locked = false;
390     } else {
391         BEGET_LOGE("Invalid lock state");
392         return HVB_IO_ERROR_NO_SUCH_VALUE;
393     }
394 
395     return HVB_IO_OK;
396 }
397 
HvbGetSizeOfPartition(struct hvb_ops * ops,const char * partition,uint64_t * size)398 static enum hvb_io_errno HvbGetSizeOfPartition(struct hvb_ops* ops,
399                                                const char* partition,
400                                                uint64_t* size)
401 {
402     if (size == NULL) {
403         return HVB_IO_ERROR_IO;
404     }
405 
406     // The function is for bootloader to load entire content of HVB HASH
407     // partitions. In user-space, return 0 as we only need to set up HVB
408     // HASHTREE partitions.
409     *size = 0;
410     return HVB_IO_OK;
411 }
412 
413 static struct hvb_ops g_hvb_ops = {
414     .user_data = &g_hvb_ops,
415     .read_partition = HvbReadFromPartition,
416     .write_partition = HvbWriteToPartition,
417     .valid_rvt_key = HvbInvaldateKey,
418     .read_rollback = HvbReadRollbackIdx,
419     .write_rollback = HvbWriteRollbackIdx,
420     .read_lock_state = HvbReadLockState,
421     .get_partiton_size = HvbGetSizeOfPartition,
422 };
423 
FsHvbGetOps(void)424 struct hvb_ops* FsHvbGetOps(void)
425 {
426     return &g_hvb_ops;
427 }
428 
429 #ifdef __cplusplus
430 #if __cplusplus
431 }
432 #endif
433 #endif
434