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 "fs_hvb.h"
17 #include "fs_dm.h"
18 #include "securec.h"
19 #include "fs_manager/ext4_super_block.h"
20 #include "fs_manager/erofs_super_block.h"
21 #include <stdint.h>
22 #include "beget_ext.h"
23 #include "init_utils.h"
24 #include <libhvb.h>
25 #include <libgen.h>
26 
27 #ifdef __cplusplus
28 #if __cplusplus
29 extern "C" {
30 #endif
31 #endif
32 
33 #define FS_HVB_VERITY_TARGET_MAX 512
34 #define FS_HVB_BLANK_SPACE_ASCII 32
35 #define FS_HVB_SECTOR_BYTES 512
36 #define FS_HVB_UINT64_MAX_LENGTH 64
37 #define FS_HVB_HASH_ALG_STR_MAX 32
38 
39 #define FS_HVB_DIGEST_SHA256_BYTES 32
40 #define FS_HVB_DIGEST_SHA512_BYTES 64
41 #define FS_HVB_DIGEST_MAX_BYTES FS_HVB_DIGEST_SHA512_BYTES
42 #define FS_HVB_DIGEST_STR_MAX_BYTES 128
43 #define FS_HVB_DEVPATH_MAX_LEN 128
44 #define FS_HVB_RVT_PARTITION_NAME "rvt"
45 #define FS_HVB_CMDLINE_PATH "/proc/cmdline"
46 #define FS_HVB_PARTITION_PREFIX "/dev/block/by-name/"
47 
48 #define FS_HVB_RETURN_ERR_IF_NULL(__ptr)             \
49     do {                                                \
50         if ((__ptr) == NULL) {                          \
51             BEGET_LOGE("error, %s is NULL\n", #__ptr); \
52             return -1;                                  \
53         }                                               \
54     } while (0)
55 
56 static struct hvb_verified_data *g_vd = NULL;
57 
FsHvbBinToHexChar(char octet)58 static char FsHvbBinToHexChar(char octet)
59 {
60     return octet < 10 ? '0' + octet : 'a' + (octet - 10);
61 }
62 
FsHvbHexCharToBin(char hex)63 static char FsHvbHexCharToBin(char hex)
64 {
65     return '0' <= hex && hex <= '9' ? hex - '0' : 10 + (hex - 'a');
66 }
67 
FsHvbGetHashStr(char * str,size_t size)68 static int FsHvbGetHashStr(char *str, size_t size)
69 {
70     return FsHvbGetValueFromCmdLine(str, size, HVB_CMDLINE_HASH_ALG);
71 }
72 
FsHvbGetCertDigstStr(char * str,size_t size)73 static int FsHvbGetCertDigstStr(char *str, size_t size)
74 {
75     return FsHvbGetValueFromCmdLine(str, size, HVB_CMDLINE_CERT_DIGEST);
76 }
77 
FsHvbComputeSha256(char * digest,size_t size,struct hvb_cert_data * certs,uint64_t num_certs)78 static int FsHvbComputeSha256(char *digest, size_t size, struct hvb_cert_data *certs, uint64_t num_certs)
79 {
80     int ret;
81     uint64_t n;
82     struct hash_ctx_t ctx = {0};
83 
84     if (size < FS_HVB_DIGEST_SHA256_BYTES) {
85         BEGET_LOGE("error, size=%zu", size);
86         return -1;
87     }
88 
89     ret = hash_ctx_init(&ctx, HASH_ALG_SHA256);
90     if (ret != HASH_OK) {
91         BEGET_LOGE("error 0x%x, sha256 init", ret);
92         return -1;
93     }
94 
95     for (n = 0; n < num_certs; n++) {
96         ret = hash_calc_update(&ctx, certs[n].data.addr, certs[n].data.size);
97         if (ret != HASH_OK) {
98             BEGET_LOGE("error 0x%x, sha256 update", ret);
99             return -1;
100         }
101     }
102 
103     ret = hash_calc_do_final(&ctx, NULL, 0, (uint8_t *)digest, size);
104     if (ret != HASH_OK) {
105         BEGET_LOGE("error 0x%x, sha256 final", ret);
106         return -1;
107     }
108 
109     return 0;
110 }
111 
FsHvbHexStrToBin(char * bin,size_t bin_size,char * str,size_t str_size)112 static int FsHvbHexStrToBin(char *bin, size_t bin_size, char *str, size_t str_size)
113 {
114     size_t i;
115 
116     if ((str_size & 0x1) != 0 || bin_size < (str_size >> 1)) {
117         BEGET_LOGE("error, bin_size %zu str_size %zu", bin_size, str_size);
118         return -1;
119     }
120 
121     for (i = 0; i < (str_size >> 1); i++) {
122         bin[i] = (FsHvbHexCharToBin(str[2 * i]) << 4) | FsHvbHexCharToBin(str[2 * i + 1]);
123     }
124 
125     return 0;
126 }
127 
FsHvbCheckCertChainDigest(struct hvb_cert_data * certs,uint64_t num_certs)128 static int FsHvbCheckCertChainDigest(struct hvb_cert_data *certs, uint64_t num_certs)
129 {
130     int ret;
131     size_t digest_len = 0;
132     char hashAlg[FS_HVB_HASH_ALG_STR_MAX] = {0};
133     char certDigest[FS_HVB_DIGEST_MAX_BYTES] = {0};
134     char computeDigest[FS_HVB_DIGEST_MAX_BYTES] = {0};
135     char certDigestStr[FS_HVB_DIGEST_STR_MAX_BYTES + 1] = {0};
136 
137     ret = FsHvbGetHashStr(&hashAlg[0], sizeof(hashAlg));
138     if (ret != 0) {
139         BEGET_LOGE("error 0x%x, get hash val from cmdline", ret);
140         return ret;
141     }
142 
143     ret = FsHvbGetCertDigstStr(&certDigestStr[0], sizeof(certDigestStr));
144     if (ret != 0) {
145         BEGET_LOGE("error 0x%x, get digest val from cmdline", ret);
146         return ret;
147     }
148 
149     ret = FsHvbHexStrToBin(&certDigest[0], sizeof(certDigest), &certDigestStr[0], strlen(certDigestStr));
150     if (ret != 0) {
151         return ret;
152     }
153 
154     if (strcmp(&hashAlg[0], "sha256") == 0) {
155         digest_len = FS_HVB_DIGEST_SHA256_BYTES;
156         ret = FsHvbComputeSha256(computeDigest, sizeof(computeDigest), certs, num_certs);
157     } else {
158         BEGET_LOGE("error, not support alg %s", &hashAlg[0]);
159         return -1;
160     }
161 
162     if (ret != 0) {
163         BEGET_LOGE("error 0x%x, compute hash", ret);
164         return -1;
165     }
166 
167     ret = memcmp(&certDigest[0], &computeDigest[0], digest_len);
168     if (ret != 0) {
169         BEGET_LOGE("error, cert digest not match with cmdline");
170         return -1;
171     }
172 
173     return 0;
174 }
175 
FsHvbInit(void)176 int FsHvbInit(void)
177 {
178     enum hvb_errno rc;
179 
180     // return ok if the hvb is already initialized
181     if (g_vd != NULL) {
182         BEGET_LOGI("Hvb has already been inited");
183         return 0;
184     }
185 
186     rc = hvb_chain_verify(FsHvbGetOps(), FS_HVB_RVT_PARTITION_NAME, NULL, &g_vd);
187     if (g_vd == NULL) {
188         BEGET_LOGE("error 0x%x, hvb chain verify, vd is NULL", rc);
189         return rc;
190     }
191 
192     if (rc != HVB_OK) {
193         BEGET_LOGE("error 0x%x, hvb chain verify", rc);
194         hvb_chain_verify_data_free(g_vd);
195         g_vd = NULL;
196         return rc;
197     }
198 
199     rc = FsHvbCheckCertChainDigest(g_vd->certs, g_vd->num_loaded_certs);
200     if (rc != 0) {
201         BEGET_LOGE("error 0x%x, cert chain hash", rc);
202         hvb_chain_verify_data_free(g_vd);
203         g_vd = NULL;
204         return rc;
205     }
206 
207     return 0;
208 }
209 
FsHvbGetCert(struct hvb_cert * cert,char * devName,struct hvb_verified_data * vd)210 static int FsHvbGetCert(struct hvb_cert *cert, char *devName, struct hvb_verified_data *vd)
211 {
212     enum hvb_errno hr;
213     size_t devNameLen = strlen(devName);
214     struct hvb_cert_data *p = vd->certs;
215     struct hvb_cert_data *end = p + vd->num_loaded_certs;
216 
217     for (; p < end; p++) {
218         if (devNameLen != strlen(p->partition_name)) {
219             continue;
220         }
221 
222         if (memcmp(p->partition_name, devName, devNameLen) == 0) {
223             break;
224         }
225     }
226 
227     if (p == end) {
228         BEGET_LOGE("error, can't found %s partition", devName);
229         return -1;
230     }
231 
232     hr = hvb_cert_parser(cert, &p->data);
233     if (hr != HVB_OK) {
234         BEGET_LOGE("error 0x%x, parser hvb cert", hr);
235         return -1;
236     }
237 
238     return 0;
239 }
240 
FsHvbVerityTargetAppendString(char ** p,char * end,char * str,size_t len)241 static int FsHvbVerityTargetAppendString(char **p, char *end, char *str, size_t len)
242 {
243     errno_t err;
244 
245     // check range for append string
246     if (*p + len >= end || *p + len < *p) {
247         BEGET_LOGE("error, append string overflow");
248         return -1;
249     }
250     // append string
251     err = memcpy_s(*p, end - *p, str, len);
252     if (err != EOK) {
253         BEGET_LOGE("error 0x%x, cp string fail", err);
254         return -1;
255     }
256     *p += len;
257 
258     // check range for append blank space
259     if (*p + 1 >= end || *p + 1 < *p) {
260         BEGET_LOGE("error, append blank space overflow");
261         return -1;
262     }
263     // append blank space
264     **p = FS_HVB_BLANK_SPACE_ASCII;
265     *p += 1;
266 
267     BEGET_LOGE("append string %s", str);
268 
269     return 0;
270 }
271 
FsHvbVerityTargetAppendOctets(char ** p,char * end,char * octs,size_t octs_len)272 static int FsHvbVerityTargetAppendOctets(char **p, char *end, char *octs, size_t octs_len)
273 {
274     size_t i;
275     int rc;
276     char *str = NULL;
277     size_t str_len = octs_len * 2;
278 
279     str = calloc(1, str_len + 1);
280     if (str == NULL) {
281         BEGET_LOGE("error, calloc str fail");
282         return -1;
283     }
284 
285     for (i = 0; i < octs_len; i++) {
286         str[2 * i] = FsHvbBinToHexChar((octs[i] >> 4) & 0xf);
287         str[2 * i + 1] = FsHvbBinToHexChar(octs[i] & 0xf);
288     }
289 
290     rc = FsHvbVerityTargetAppendString(p, end, str, str_len);
291     if (rc != 0) {
292         BEGET_LOGE("error 0x%x, append str fail", rc);
293     }
294     free(str);
295 
296     return rc;
297 }
298 
FsHvbVerityTargetAppendNum(char ** p,char * end,uint64_t num)299 static int FsHvbVerityTargetAppendNum(char **p, char *end, uint64_t num)
300 {
301     int rc;
302     char num_str[FS_HVB_UINT64_MAX_LENGTH] = {0};
303 
304     rc = sprintf_s(&num_str[0], sizeof(num_str), "%llu", num);
305     if (rc < 0) {
306         BEGET_LOGE("error 0x%x, calloc num_str", rc);
307         return rc;
308     }
309 
310     rc = FsHvbVerityTargetAppendString(p, end, num_str, strlen(&num_str[0]));
311     if (rc != 0) {
312         BEGET_LOGE("error 0x%x, append num_str fail", rc);
313     }
314 
315     return rc;
316 }
317 
318 #define RETURN_ERR_IF_APPEND_STRING_ERR(p, end, str, str_len)                     \
319     do {                                                                          \
320         int __ret = FsHvbVerityTargetAppendString(p, end, str, str_len);          \
321         if (__ret != 0)                                                           \
322             return __ret;                                                         \
323     } while (0)
324 
325 #define RETURN_ERR_IF_APPEND_OCTETS_ERR(p, end, octs, octs_len)                    \
326     do {                                                                          \
327         int __ret = FsHvbVerityTargetAppendOctets(p, end, octs, octs_len);          \
328         if (__ret != 0)                                                           \
329             return __ret;                                                         \
330     } while (0)
331 
332 #define RETURN_ERR_IF_APPEND_DIGIT_ERR(p, end, num)                               \
333     do {                                                                          \
334         int __ret = FsHvbVerityTargetAppendNum(p, end, num);                      \
335         if (__ret != 0)                                                           \
336             return __ret;                                                         \
337     } while (0)
338 
FsHvbGetHashAlgStr(unsigned int hash_algo)339 static char *FsHvbGetHashAlgStr(unsigned int hash_algo)
340 {
341     char *alg = NULL;
342 
343     switch (hash_algo) {
344         case 0:
345             alg = "sha256";
346             break;
347 
348         case 1:
349             alg = "sha512";
350             break;
351 
352         default:
353             alg = NULL;
354             break;
355     }
356 
357     return alg;
358 }
359 
360 /*
361  * add optional fec data if supported, format as below;
362  * <use_fec_from_device> <fec_roots><fec_blocks><fec_start>
363  */
FsHvbVerityTargetAddFecArgs(struct hvb_cert * cert,char * devPath,char ** str,char * end)364 static int FsHvbVerityTargetAddFecArgs(struct hvb_cert *cert, char *devPath, char **str, char *end)
365 {
366     FS_HVB_RETURN_ERR_IF_NULL(cert);
367     FS_HVB_RETURN_ERR_IF_NULL(devPath);
368     FS_HVB_RETURN_ERR_IF_NULL(str);
369     FS_HVB_RETURN_ERR_IF_NULL(end);
370 
371     // append <device>
372     RETURN_ERR_IF_APPEND_STRING_ERR(str, end, USE_FEC_FROM_DEVICE, strlen(USE_FEC_FROM_DEVICE));
373     RETURN_ERR_IF_APPEND_STRING_ERR(str, end, &devPath[0], strlen(devPath));
374 
375     // append <fec_roots>
376     RETURN_ERR_IF_APPEND_STRING_ERR(str, end, FEC_ROOTS, strlen(FEC_ROOTS));
377     RETURN_ERR_IF_APPEND_DIGIT_ERR(str, end, cert->fec_num_roots);
378 
379     if (cert->data_block_size == 0 || cert->hash_block_size == 0) {
380         BEGET_LOGE("error, block size is zero");
381         return -1;
382     }
383     // append <fec_blocks>
384     RETURN_ERR_IF_APPEND_STRING_ERR(str, end, FEC_BLOCKS, strlen(FEC_BLOCKS));
385     RETURN_ERR_IF_APPEND_DIGIT_ERR(str, end, cert->fec_offset / cert->hash_block_size);
386 
387     // append <fec_start>
388     RETURN_ERR_IF_APPEND_STRING_ERR(str, end, FEC_START, strlen(FEC_START));
389     RETURN_ERR_IF_APPEND_DIGIT_ERR(str, end, cert->fec_offset / cert->data_block_size);
390 
391     return 0;
392 }
393 
394 /*
395  * target->paras is verity table target, format as below;
396  * <version> <dev><hash_dev><data_block_size><hash_block_size>
397  * <num_data_blocks><hash_start_block><algorithm><digest><salt>
398  * [<#opt_params><opt_params>]
399  * exp: 1 /dev/sda1 /dev/sda1 4096 4096 262144 262144 sha256 \
400        xxxxx
401        xxxxx
402  */
403 
FsHvbConstructVerityTarget(DmVerityTarget * target,const char * devName,struct hvb_cert * cert)404 int FsHvbConstructVerityTarget(DmVerityTarget *target, const char *devName, struct hvb_cert *cert)
405 {
406     char *p = NULL;
407     char *end = NULL;
408     char *hashALgo = NULL;
409     char devPath[FS_HVB_DEVPATH_MAX_LEN] = {0};
410 
411     FS_HVB_RETURN_ERR_IF_NULL(target);
412     FS_HVB_RETURN_ERR_IF_NULL(devName);
413     FS_HVB_RETURN_ERR_IF_NULL(cert);
414 
415     target->start = 0;
416     target->length = cert->image_len / FS_HVB_SECTOR_BYTES;
417     target->paras = calloc(1, FS_HVB_VERITY_TARGET_MAX); // simple it, just calloc a big mem
418     if (target->paras == NULL) {
419         BEGET_LOGE("error, alloc target paras");
420         return -1;
421     }
422 
423     if (snprintf_s(&devPath[0], sizeof(devPath), sizeof(devPath) - 1, "%s%s",
424         ((strchr(devName, '/') == NULL) ? FS_HVB_PARTITION_PREFIX : ""), devName) == -1) {
425         BEGET_LOGE("error, snprintf_s devPath");
426         return -1;
427     }
428 
429     p = target->paras;
430     end = p + FS_HVB_VERITY_TARGET_MAX;
431 
432     // append <version>
433     RETURN_ERR_IF_APPEND_DIGIT_ERR(&p, end, 1);
434     // append <dev>
435     RETURN_ERR_IF_APPEND_STRING_ERR(&p, end, &devPath[0], strlen(devPath));
436     // append <hash_dev>
437     RETURN_ERR_IF_APPEND_STRING_ERR(&p, end, &devPath[0], strlen(devPath));
438 
439     if (cert->data_block_size == 0 || cert->hash_block_size == 0) {
440         BEGET_LOGE("error, block size is zero");
441         return -1;
442     }
443     // append <data_block_size>
444     RETURN_ERR_IF_APPEND_DIGIT_ERR(&p, end, cert->data_block_size);
445     // append <hash_block_size>
446     RETURN_ERR_IF_APPEND_DIGIT_ERR(&p, end, cert->hash_block_size);
447     // append <num_data_blocks>
448     RETURN_ERR_IF_APPEND_DIGIT_ERR(&p, end, cert->image_len / cert->data_block_size);
449     // append <hash_start_block>
450     RETURN_ERR_IF_APPEND_DIGIT_ERR(&p, end, cert->hashtree_offset / cert->hash_block_size);
451 
452     // append <algorithm>
453     hashALgo = FsHvbGetHashAlgStr(cert->hash_algo);
454     if (hashALgo == NULL) {
455         BEGET_LOGE("error, hash alg %d is invalid", cert->hash_algo);
456         return -1;
457     }
458     RETURN_ERR_IF_APPEND_STRING_ERR(&p, end, hashALgo, strlen(hashALgo));
459 
460     // append <digest>
461     RETURN_ERR_IF_APPEND_OCTETS_ERR(&p, end, (char *)cert->hash_payload.digest, cert->digest_size);
462 
463     // append <salt>
464     RETURN_ERR_IF_APPEND_OCTETS_ERR(&p, end, (char *)cert->hash_payload.salt, cert->salt_size);
465 
466     if (cert->fec_size > 0) {
467         if (FsHvbVerityTargetAddFecArgs(cert, devPath, &p, end) != 0) {
468             return -1;
469         }
470     }
471 
472     // remove last blank
473     *(p - 1) = '\0';
474 
475     target->paras_len = strlen(target->paras);
476 
477     return 0;
478 }
479 
FsHvbCreateVerityTarget(DmVerityTarget * target,char * devName,struct hvb_verified_data * vd)480 static int FsHvbCreateVerityTarget(DmVerityTarget *target, char *devName, struct hvb_verified_data *vd)
481 {
482     int rc;
483     struct hvb_cert cert = {0};
484 
485     rc = FsHvbGetCert(&cert, devName, vd);
486     if (rc != 0) {
487         return rc;
488     }
489 
490     rc = FsHvbConstructVerityTarget(target, devName, &cert);
491     if (rc != 0) {
492         BEGET_LOGE("error 0x%x, can't construct verity target", rc);
493         return rc;
494     }
495 
496     return rc;
497 }
498 
FsHvbDestoryVerityTarget(DmVerityTarget * target)499 void FsHvbDestoryVerityTarget(DmVerityTarget *target)
500 {
501     if (target != NULL && target->paras != NULL) {
502         free(target->paras);
503         target->paras = NULL;
504     }
505 }
506 
FsHvbSetupHashtree(FstabItem * fsItem)507 int FsHvbSetupHashtree(FstabItem *fsItem)
508 {
509     int rc;
510     DmVerityTarget target = {0};
511     char *dmDevPath = NULL;
512     char *devName = NULL;
513 
514     FS_HVB_RETURN_ERR_IF_NULL(fsItem);
515     FS_HVB_RETURN_ERR_IF_NULL(g_vd);
516 
517     // fsItem->deviceName is like /dev/block/platform/xxx/by-name/system
518     // we just basename system
519     devName = basename(fsItem->deviceName);
520     if (devName == NULL) {
521         BEGET_LOGE("error, get basename");
522         return -1;
523     }
524 
525     rc = FsHvbCreateVerityTarget(&target, devName, g_vd);
526     if (rc != 0) {
527         BEGET_LOGE("error 0x%x, create verity-table", rc);
528         goto exit;
529     }
530 
531     rc = FsDmCreateDevice(&dmDevPath, devName, &target);
532     if (rc != 0) {
533         BEGET_LOGE("error 0x%x, create dm-verity", rc);
534         goto exit;
535     }
536 
537     rc = FsDmInitDmDev(dmDevPath, true);
538     if (rc != 0) {
539         BEGET_LOGE("error 0x%x, create init dm dev", rc);
540         goto exit;
541     }
542 
543     free(fsItem->deviceName);
544     fsItem->deviceName = dmDevPath;
545 
546 exit:
547     FsHvbDestoryVerityTarget(&target);
548 
549     return rc;
550 }
551 
FsHvbFinal(void)552 int FsHvbFinal(void)
553 {
554     if (g_vd != NULL) {
555         hvb_chain_verify_data_free(g_vd);
556         g_vd = NULL;
557     }
558 
559     return 0;
560 }
561 
FsHvbGetValueFromCmdLine(char * val,size_t size,const char * key)562 int FsHvbGetValueFromCmdLine(char *val, size_t size, const char *key)
563 {
564     FS_HVB_RETURN_ERR_IF_NULL(val);
565     FS_HVB_RETURN_ERR_IF_NULL(key);
566 
567     return GetParameterFromCmdLine(key, val, size);
568 }
569 
CheckAndGetExt4Size(const char * headerBuf,uint64_t * imageSize,const char * image)570 bool CheckAndGetExt4Size(const char *headerBuf, uint64_t *imageSize, const char* image)
571 {
572     ext4_super_block *superBlock = (ext4_super_block *)headerBuf;
573 
574     if (headerBuf == NULL || imageSize == NULL || image == NULL) {
575         BEGET_LOGE("param is error");
576         return false;
577     }
578 
579     if (superBlock->s_magic == EXT4_SUPER_MAGIC) {
580         *imageSize = (uint64_t)superBlock->s_blocks_count_lo * BLOCK_SIZE_UNIT;
581         BEGET_LOGI("%s is ext4:[block cout]: %d, [size]: 0x%lx", image,
582             superBlock->s_blocks_count_lo, *imageSize);
583         return true;
584     }
585     return false;
586 }
587 
CheckAndGetErofsSize(const char * headerBuf,uint64_t * imageSize,const char * image)588 bool CheckAndGetErofsSize(const char *headerBuf, uint64_t *imageSize, const char* image)
589 {
590     struct erofs_super_block *superBlock = (struct erofs_super_block *)headerBuf;
591 
592     if (headerBuf == NULL || imageSize == NULL || image == NULL) {
593         BEGET_LOGE("param is error");
594         return false;
595     }
596 
597     if (superBlock->magic == EROFS_SUPER_MAGIC) {
598         *imageSize = (uint64_t)superBlock->blocks * BLOCK_SIZE_UINT;
599         BEGET_LOGI("%s is erofs:[block cout]: %d, [size]: 0x%lx", image,
600             superBlock->blocks, *imageSize);
601         return true;
602     }
603     return false;
604 }
605 
CheckAndGetExtheaderSize(const int fd,uint64_t offset,uint64_t * imageSize,const char * image)606 bool CheckAndGetExtheaderSize(const int fd, uint64_t offset,
607                               uint64_t *imageSize, const char* image)
608 {
609     ExtheaderV1 header;
610     ssize_t nbytes;
611     if (fd < 0 || imageSize == NULL || image == NULL) {
612         BEGET_LOGE("param is error");
613         return false;
614     }
615 
616     if (lseek(fd, offset, SEEK_SET) < 0) {
617         BEGET_LOGE("lseek %s failed for offset 0x%lx", image, offset);
618         return false;
619     }
620 
621     nbytes = read(fd, &header, sizeof(header));
622     if (nbytes != sizeof(header)) {
623         BEGET_LOGE("read %s failed.", image);
624         return false;
625     }
626 
627     if (header.magicNumber != EXTHDR_MAGIC) {
628         BEGET_LOGW("%s extheader doesnt match, magic is 0x%lx", image, header.magicNumber);
629         return false;
630     }
631 
632     *imageSize = header.partSize;
633     return true;
634 }
635 
636 #ifdef __cplusplus
637 #if __cplusplus
638 }
639 #endif
640 #endif
641