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