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
27 #ifdef __cplusplus
28 #if __cplusplus
29 extern "C" {
30 #endif
31 #endif
32
33 #define PARTITION_PATH_PREFIX "/dev/block/by-name/"
34 #define MAX_EXT_HVB_PARTITION_NUM 1
35 #define FS_HVB_LOCK_STATE_STR_MAX 32
36
37 static const ExtHvbVerifiedDev g_extVerifiedDev[] = {
38 {
39 .partitionName = "module_update",
40 .pathName = "/data/module_update/active/ModuleTrain/module.img"
41 },
42 };
43
GetImageSizeForHVB(const int fd,const char * image)44 static int64_t GetImageSizeForHVB(const int fd, const char* image)
45 {
46 char headerBuf[SZ_2KB] = {0};
47 ssize_t nbytes;
48 uint64_t fileSysSize;
49 uint64_t realFileSize;
50
51 if (fd < 0) {
52 BEGET_LOGE("param is error");
53 return -1;
54 }
55
56 lseek64(fd, 0, SEEK_SET);
57 nbytes = read(fd, &headerBuf, sizeof(headerBuf));
58 if (nbytes != sizeof(headerBuf)) {
59 BEGET_LOGE("read file system header fail");
60 return -1;
61 }
62
63 if (CheckAndGetErofsSize(&headerBuf[SZ_1KB], &fileSysSize, image) &&
64 CheckAndGetExtheaderSize(fd, fileSysSize, &realFileSize, image)) {
65 BEGET_LOGI("get %s size from erofs and extheader, size=0x%lx", image, realFileSize);
66 return realFileSize;
67 } else if (CheckAndGetExt4Size(&headerBuf[SZ_1KB], &fileSysSize, image) &&
68 CheckAndGetExtheaderSize(fd, fileSysSize, &realFileSize, image)) {
69 BEGET_LOGI("get %s size from ext4 and extheader, size=0x%lx", image, realFileSize);
70 return realFileSize;
71 } else {
72 BEGET_LOGI("read %s file extheader fail, use the actual img size", image);
73 }
74
75 return lseek64(fd, 0, SEEK_END);
76 }
77
IsExtHvbVerifiedPtn(const char * ptn,size_t ptnLen,size_t * outIndex)78 static bool IsExtHvbVerifiedPtn(const char *ptn, size_t ptnLen, size_t *outIndex)
79 {
80 int index;
81 if (ptn == NULL || outIndex == NULL) {
82 BEGET_LOGE("error, invalid ptn");
83 return false;
84 }
85
86 for (index = 0; index < MAX_EXT_HVB_PARTITION_NUM; index++) {
87 if (strncmp(g_extVerifiedDev[index].partitionName, ptn, ptnLen) == 0) {
88 *outIndex = index;
89 return true;
90 }
91 }
92
93 return false;
94 }
95
GetExtHvbVerifiedPath(size_t index)96 static char *GetExtHvbVerifiedPath(size_t index)
97 {
98 char *tmpPath = NULL;
99
100 if (index >= MAX_EXT_HVB_PARTITION_NUM) {
101 BEGET_LOGE("error, invalid index");
102 return NULL;
103 }
104
105 size_t pathLen = strnlen(g_extVerifiedDev[index].pathName, FS_HVB_MAX_PATH_LEN);
106 if (pathLen >= FS_HVB_MAX_PATH_LEN) {
107 BEGET_LOGE("error, invalid path");
108 return tmpPath;
109 }
110 tmpPath = malloc(pathLen + 1);
111 if (tmpPath == NULL) {
112 BEGET_LOGE("error, fail to malloc");
113 return NULL;
114 }
115
116 (void)memset_s(tmpPath, pathLen + 1, 0, pathLen + 1);
117 if (memcpy_s(tmpPath, pathLen + 1, g_extVerifiedDev[index].pathName, pathLen) != 0) {
118 free(tmpPath);
119 BEGET_LOGE("error, fail to copy");
120 return NULL;
121 }
122 return tmpPath;
123 }
124
HvbGetPartitionPath(const char * partition)125 static char *HvbGetPartitionPath(const char *partition)
126 {
127 int rc;
128 size_t pathLen;
129 char *path = NULL;
130 size_t index;
131 size_t ptnLen = strnlen(partition, HVB_MAX_PARTITION_NAME_LEN);
132 if (ptnLen >= HVB_MAX_PARTITION_NAME_LEN) {
133 BEGET_LOGE("error, invalid ptn name");
134 return NULL;
135 }
136 if (IsExtHvbVerifiedPtn(partition, ptnLen, &index)) {
137 return GetExtHvbVerifiedPath(index);
138 }
139
140 pathLen = strlen(PARTITION_PATH_PREFIX) + ptnLen;
141 path = calloc(1, pathLen + 1);
142 if (path == NULL) {
143 BEGET_LOGE("error, calloc fail");
144 return NULL;
145 }
146 rc = snprintf_s(path, pathLen + 1, pathLen, "%s%s", PARTITION_PATH_PREFIX,
147 partition);
148 if (rc < 0) {
149 BEGET_LOGE("error, snprintf_s fail, ret = %d", rc);
150 free(path);
151 return NULL;
152 }
153 return path;
154 }
155
HvbReadFromPartition(struct hvb_ops * ops,const char * partition,int64_t offset,uint64_t numBytes,void * buf,uint64_t * outNumRead)156 static enum hvb_io_errno HvbReadFromPartition(struct hvb_ops* ops,
157 const char* partition,
158 int64_t offset, uint64_t numBytes,
159 void* buf, uint64_t* outNumRead)
160 {
161 int fd = -1;
162 char *path = NULL;
163 enum hvb_io_errno ret = HVB_IO_ERROR_IO;
164
165 if (ops == NULL || partition == NULL ||
166 buf == NULL || outNumRead == NULL) {
167 BEGET_LOGE("error, invalid parameter");
168 return HVB_IO_ERROR_IO;
169 }
170
171 /* get and malloc img path */
172 path = HvbGetPartitionPath(partition);
173 if (path == NULL) {
174 BEGET_LOGE("error, get partition path");
175 ret = HVB_IO_ERROR_OOM;
176 goto exit;
177 }
178
179 fd = open(path, O_RDONLY | O_CLOEXEC);
180 if (fd < 0) {
181 BEGET_LOGE("error, Failed to open %s, errno = %d", path, errno);
182 ret = HVB_IO_ERROR_IO;
183 goto exit;
184 }
185
186 if (offset < 0) {
187 int64_t total_size = GetImageSizeForHVB(fd, partition);
188 if (total_size == -1) {
189 BEGET_LOGE("Failed to get the size of the partition %s", partition);
190 ret = HVB_IO_ERROR_IO;
191 goto exit;
192 }
193 offset = total_size + offset;
194 }
195
196 lseek64(fd, offset, SEEK_SET);
197
198 ssize_t numRead = read(fd, buf, numBytes);
199 if (numRead < 0 || (size_t)numRead != numBytes) {
200 BEGET_LOGE("Failed to read %lld bytes from %s offset %lld", numBytes,
201 path, offset);
202 ret = HVB_IO_ERROR_IO;
203 goto exit;
204 }
205
206 *outNumRead = numRead;
207
208 ret = HVB_IO_OK;
209
210 exit:
211
212 if (path != NULL) {
213 free(path);
214 }
215
216 if (fd >= 0) {
217 close(fd);
218 }
219 return ret;
220 }
221
HvbWriteToPartition(struct hvb_ops * ops,const char * partition,int64_t offset,uint64_t numBytes,const void * buf)222 static enum hvb_io_errno HvbWriteToPartition(struct hvb_ops* ops,
223 const char* partition,
224 int64_t offset, uint64_t numBytes,
225 const void* buf)
226 {
227 return HVB_IO_OK;
228 }
229
HvbInvaldateKey(struct hvb_ops * ops,const uint8_t * publicKeyData,uint64_t publicKeyLength,const uint8_t * publicKeyMetadata,uint64_t publicKeyMetadataLength,bool * outIsTrusted)230 static enum hvb_io_errno HvbInvaldateKey(struct hvb_ops* ops,
231 const uint8_t* publicKeyData,
232 uint64_t publicKeyLength,
233 const uint8_t* publicKeyMetadata,
234 uint64_t publicKeyMetadataLength,
235 bool* outIsTrusted)
236 {
237 if (outIsTrusted == NULL) {
238 return HVB_IO_ERROR_IO;
239 }
240
241 *outIsTrusted = true;
242
243 return HVB_IO_OK;
244 }
245
HvbReadRollbackIdx(struct hvb_ops * ops,uint64_t rollBackIndexLocation,uint64_t * outRollbackIndex)246 static enum hvb_io_errno HvbReadRollbackIdx(struct hvb_ops* ops,
247 uint64_t rollBackIndexLocation,
248 uint64_t* outRollbackIndex)
249 {
250 if (outRollbackIndex == NULL) {
251 return HVB_IO_ERROR_IO;
252 }
253
254 // return 0 as we only need to set up HVB HASHTREE partitions
255 *outRollbackIndex = 0;
256
257 return HVB_IO_OK;
258 }
259
HvbWriteRollbackIdx(struct hvb_ops * ops,uint64_t rollBackIndexLocation,uint64_t rollbackIndex)260 static enum hvb_io_errno HvbWriteRollbackIdx(struct hvb_ops* ops,
261 uint64_t rollBackIndexLocation,
262 uint64_t rollbackIndex)
263 {
264 return HVB_IO_OK;
265 }
266
FsHvbGetLockStateStr(char * str,size_t size)267 static int FsHvbGetLockStateStr(char *str, size_t size)
268 {
269 return FsHvbGetValueFromCmdLine(str, size, HVB_CMDLINE_DEV_STATE);
270 }
271
HvbReadLockState(struct hvb_ops * ops,bool * locked)272 static enum hvb_io_errno HvbReadLockState(struct hvb_ops *ops,
273 bool *locked)
274 {
275 char lockState[FS_HVB_LOCK_STATE_STR_MAX] = {0};
276 if (ops == NULL || locked == NULL) {
277 BEGET_LOGE("Invalid lock state parameter");
278 return HVB_IO_ERROR_IO;
279 }
280
281 int ret = FsHvbGetLockStateStr(&lockState[0], sizeof(lockState));
282 if (ret != 0) {
283 BEGET_LOGE("error 0x%x, get lock state from cmdline", ret);
284 return HVB_IO_ERROR_NO_SUCH_VALUE;
285 }
286
287 if (strncmp(&lockState[0], "locked", FS_HVB_LOCK_STATE_STR_MAX) == 0) {
288 *locked = true;
289 } else if (strncmp(&lockState[0], "unlocked", FS_HVB_LOCK_STATE_STR_MAX) == 0) {
290 *locked = false;
291 } else {
292 BEGET_LOGE("Invalid lock state");
293 return HVB_IO_ERROR_NO_SUCH_VALUE;
294 }
295
296 return HVB_IO_OK;
297 }
298
HvbGetSizeOfPartition(struct hvb_ops * ops,const char * partition,uint64_t * size)299 static enum hvb_io_errno HvbGetSizeOfPartition(struct hvb_ops* ops,
300 const char* partition,
301 uint64_t* size)
302 {
303 if (size == NULL) {
304 return HVB_IO_ERROR_IO;
305 }
306
307 // The function is for bootloader to load entire content of HVB HASH
308 // partitions. In user-space, return 0 as we only need to set up HVB
309 // HASHTREE partitions.
310 *size = 0;
311 return HVB_IO_OK;
312 }
313
314 static struct hvb_ops g_hvb_ops = {
315 .user_data = &g_hvb_ops,
316 .read_partition = HvbReadFromPartition,
317 .write_partition = HvbWriteToPartition,
318 .valid_rvt_key = HvbInvaldateKey,
319 .read_rollback = HvbReadRollbackIdx,
320 .write_rollback = HvbWriteRollbackIdx,
321 .read_lock_state = HvbReadLockState,
322 .get_partiton_size = HvbGetSizeOfPartition,
323 };
324
FsHvbGetOps(void)325 struct hvb_ops* FsHvbGetOps(void)
326 {
327 return &g_hvb_ops;
328 }
329
330 #ifdef __cplusplus
331 #if __cplusplus
332 }
333 #endif
334 #endif
335