blob: 368a4f1cadd19cf744b41be06749db84cd3eabb6 [file] [log] [blame]
Sachin Sundar1ed5f5b2017-03-28 17:34:42 +05301/*
2 * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <sysupgrade.h>
15
16#define SBL_VERSION_FILE "sbl_version"
17#define TZ_VERSION_FILE "tz_version"
18#define HLOS_VERSION_FILE "hlos_version"
19#define APPSBL_VERSION_FILE "appsbl_version"
20#define RPM_VERSION_FILE "rpm_version"
21#define VERSION_FILE_BASENAME "/sys/devices/system/qfprom/qfprom0/"
22#define AUTHENTICATE_FILE "/sys/devices/system/qfprom/qfprom0/authenticate"
23#define TEMP_KERNEL_PATH "/tmp/tmp_kernel.bin"
24#define MAX_SBL_VERSION 11
25#define MAX_HLOS_VERSION 32
26#define MAX_TZ_VERSION 14
27#define MAX_APPSBL_VERSION 14
28#define MAX_RPM_VERSION 8
29#define HASH_P_FLAG 0x02200000
30#define TMP_FILE_DIR "/tmp/"
31#define CERT_SIZE 2048
32#define PRESENT 1
33#define MBN_HDR_SIZE 40
34#define SIG_SIZE 256
35#define NOT_PRESENT 0
36#define SIG_CERT_2_SIZE 4352
37#define SIG_CERT_3_SIZE 6400
38#define SBL_NAND_PREAMBLE 10240
39#define SBL_HDR_RESERVED 12
40#define UBI_EC_HDR_MAGIC 0x55424923
41#define UBI_VID_HDR_MAGIC 0x55424921
42
43#define ARRAY_SIZE(array) sizeof(array)/sizeof(array[0])
44
45struct image_section sections[] = {
46 {
47 .section_type = UBOOT_TYPE,
48 .type = "u-boot",
49 .max_version = MAX_APPSBL_VERSION,
50 .file = TMP_FILE_DIR,
51 .version_file = APPSBL_VERSION_FILE,
52 .is_present = NOT_PRESENT,
53 },
54 {
55 .section_type = HLOS_TYPE,
56 .type = "hlos",
57 .max_version = MAX_HLOS_VERSION,
58 .file = TMP_FILE_DIR,
59 .version_file = HLOS_VERSION_FILE,
60 .is_present = NOT_PRESENT,
61 },
62 {
63 .section_type = HLOS_TYPE,
64 .type = "ubi",
65 .tmp_file = TMP_FILE_DIR,
66 .pre_op = extract_kernel_binary,
67 .max_version = MAX_HLOS_VERSION,
68 .file = TEMP_KERNEL_PATH,
69 .version_file = HLOS_VERSION_FILE,
70 .is_present = NOT_PRESENT,
71 },
72 {
73 .section_type = TZ_TYPE,
74 .type = "tz",
75 .max_version = MAX_TZ_VERSION,
76 .file = TMP_FILE_DIR,
77 .version_file = TZ_VERSION_FILE,
78 .is_present = NOT_PRESENT,
79 },
80 {
81 .section_type = SBL_TYPE,
82 .type = "sbl1",
83 .max_version = MAX_SBL_VERSION,
84 .file = TMP_FILE_DIR,
85 .version_file = SBL_VERSION_FILE,
86 .is_present = NOT_PRESENT,
87 },
88 {
89 .section_type = SBL_TYPE,
90 .type = "sbl2",
91 .max_version = MAX_SBL_VERSION,
92 .file = TMP_FILE_DIR,
93 .version_file = SBL_VERSION_FILE,
94 .is_present = NOT_PRESENT,
95 },
96 {
97 .section_type = SBL_TYPE,
98 .type = "sbl3",
99 .max_version = MAX_SBL_VERSION,
100 .file = TMP_FILE_DIR,
101 .version_file = SBL_VERSION_FILE,
102 .is_present = NOT_PRESENT,
103 },
104 {
105 .section_type = RPM_TYPE,
106 .type = "rpm",
107 .max_version = MAX_RPM_VERSION,
108 .file = TMP_FILE_DIR,
109 .version_file = RPM_VERSION_FILE,
110 .is_present = NOT_PRESENT,
111 },
112};
113
114#define NO_OF_SECTIONS ARRAY_SIZE(sections)
115int src_size;
116
117int check_mbn_elf(struct image_section **sec)
118{
119 int fd = open((*sec)->file, O_RDONLY);
120 struct stat sb;
121 uint8_t *fp;
122 Elf32_Ehdr *elf;
123
124 if (fd < 0) {
125 perror((*sec)->file);
126 return 0;
127 }
128
Gokul Sriram Palanisamy767b4572017-09-01 16:02:50 +0530129 memset(&sb, 0, sizeof(struct stat));
Sachin Sundar1ed5f5b2017-03-28 17:34:42 +0530130 if (fstat(fd, &sb) == -1) {
131 perror("fstat");
132 close(fd);
133 return 0;
134 }
135
136 fp = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
137 if (fp == MAP_FAILED) {
138 perror("mmap");
139 close(fd);
140 return 0;
141 }
142
143 elf = (Elf32_Ehdr *)fp;
144 if (!strncmp((char *)&(elf->e_ident[1]), "ELF", 3)) {
145 (*sec)->get_sw_id = get_sw_id_from_component_bin_elf;
146 (*sec)->split_components = split_code_signature_cert_from_component_bin_elf;
147 } else if (!strncmp((char *)&(((Elf32_Ehdr *)(fp + SBL_NAND_PREAMBLE))->e_ident[1]), "ELF", 3)) {
148 (*sec)->get_sw_id = get_sw_id_from_component_bin_elf;
149 (*sec)->split_components = split_code_signature_cert_from_component_bin_elf;
150 } else {
151 (*sec)->get_sw_id = get_sw_id_from_component_bin;
152 (*sec)->split_components = split_code_signature_cert_from_component_bin;
153 }
154
155 return 1;
156}
157
158int get_sections(void)
159{
160 DIR *dir = opendir(TMP_FILE_DIR);
161 struct dirent *file;
162 int i;
163 struct image_section *sec;
164
165 if (dir == NULL) {
166 printf("Error accessing the image directory\n");
167 return 0;
168 }
169
170 while ((file = readdir(dir)) != NULL) {
171 for (i = 0, sec = &sections[0]; i < NO_OF_SECTIONS; i++, sec++) {
172 if (strstr(file->d_name, sec->type)) {
173 if (sec->pre_op) {
174 strncat(sec->tmp_file, file->d_name,
175 sizeof(sec->tmp_file));
176 if (!sec->pre_op(sec)) {
177 printf("Error extracting kernel from ubi\n");
178 return 0;
179 }
180 } else {
181 strncat(sec->file, file->d_name,
182 sizeof(sec->file));
183 }
184 if (!check_mbn_elf(&sec)) {
185 closedir(dir);
186 return 0;
187 }
188 if (!sec->get_sw_id(sec)) {
189 closedir(dir);
190 return 0;
191 }
192 get_local_image_version(sec);
193 sec->is_present = PRESENT;
194 break;
195 }
196 }
197 }
198 closedir(dir);
199 return 1;
200}
201
202/**
203 * is_authentication_check_enabled() - checks whether installed image is
204 * secure(1) or not(0)
205 *
206 */
207int is_authentication_check_enabled(void)
208{
209 int fd = open(AUTHENTICATE_FILE, O_RDONLY);
210 char authenticate_string[4];
211 int len;
212
213 if (fd == -1) {
214 perror(AUTHENTICATE_FILE);
215 return 0;
216 }
217
218 len = read(fd, authenticate_string, 1);
219 close(fd);
220
221 if (len > 0 && authenticate_string[0] == '0') {
222 return 0;
223 }
224
225 return 1;
226}
227
228/**
229 * get_local_image_version() check the version file & if it exists, read the
230 * value & save it into global variable local_version
231 *
232 */
233int get_local_image_version(struct image_section *section)
234{
235 int len, fd;
236 char local_version_string[16], version_file[64];
237 struct stat st;
238
239 snprintf(version_file, sizeof(version_file), "%s%s", VERSION_FILE_BASENAME, section->version_file);
240 fd = open(version_file, O_RDONLY);
241 if (fd == -1) {
242 perror(version_file);
243 return 0;
244 }
245
Gokul Sriram Palanisamy767b4572017-09-01 16:02:50 +0530246 memset(&st, 0, sizeof(struct stat));
Sachin Sundar1ed5f5b2017-03-28 17:34:42 +0530247 fstat(fd, &st);
248
249 len = st.st_size < sizeof(local_version_string) - 1 ? st.st_size :
250 sizeof(local_version_string) - 1;
251 if (read(fd, local_version_string, len) == -1) {
252 close(fd);
253 return 0;
254 }
255 local_version_string[len] = '\0';
256 close(fd);
257
258 section->local_version = atoi(local_version_string);
259 printf("Local image version:%s\n", local_version_string);
260
261 return 1;
262}
263
264/**
265 * set_local_image_version() update the version of the image by writing the version
266 * to the version file
267 *
268 */
269int set_local_image_version(struct image_section *section)
270{
271 int fd;
272 char version_string[16], version_file[64];
273 int len;
274
275 snprintf(version_file, sizeof(version_file), "%s%s", TMP_FILE_DIR, section->version_file);
276 fd = open(version_file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
277 if (fd == -1) {
278 perror(version_file);
279 return 0;
280 }
281
282 len = snprintf(version_string, 8, "%d", section->img_version);
Gokul Sriram Palanisamy767b4572017-09-01 16:02:50 +0530283 if (len < 0) {
284 printf("Error in formatting the version string");
285 return 0;
286 }
287
Sachin Sundar1ed5f5b2017-03-28 17:34:42 +0530288 printf("Version to be updated:%s\n", version_string);
289 if (write(fd, version_string, len) == -1) {
290 printf("Error writing version to %s\n", version_file);
291 close(fd);
292 return 0;
293 }
294
295 close(fd);
296 return 1;
297}
298
299/**
300 * is_version_check_enabled() checks whether version check is
301 * enabled(non-zero value) or not
302 *
303 */
304int is_version_check_enabled()
305{
306 if (get_local_image_version(&sections[0]) != -1) {
307 printf("Returning 1 from is_version_check_enabled because local_version_string is non-ZERO\n");
308 return 1;
309 }
310
311 return 0;
312}
313
314char *find_value(char *buffer, char *search, int size)
315{
316 char *value = malloc(size * sizeof(char));
317 int i, j;
318
319 if (value == NULL) {
320 return NULL;
321 }
322
323 for (i = 0; i < CERT_SIZE; i++) {
324 for (j = 0; search[j] && (buffer[i + j] == search[j]); j++);
325 if (search[j] == '\0') {
326 strncpy(value, &buffer[i - size], size);
327 value[size - 1] = '\0';
328 return value;
329 }
330 }
331 free(value);
332 return NULL;
333}
334
335/**
336 * get_sw_id_from_component_bin() parses the MBN header & checks image size v/s
337 * code size. If both differ, it means signature & certificates are
338 * appended at end.
339 * Extract the attestation certificate & read the Subject & retreive the SW_ID.
340 *
341 * @bin_file: struct image_section *
342 */
343int get_sw_id_from_component_bin(struct image_section *section)
344{
345 Mbn_Hdr *mbn_hdr;
346 int fd = open(section->file, O_RDONLY);
347 struct stat sb;
348 uint8_t *fp;
349 int cert_offset;
350 char *sw_version;
351 int sig_cert_size;
352
353 if (fd == -1) {
354 perror(section->file);
355 return 0;
356 }
357
Gokul Sriram Palanisamy767b4572017-09-01 16:02:50 +0530358 memset(&sb, 0, sizeof(struct stat));
Sachin Sundar1ed5f5b2017-03-28 17:34:42 +0530359 if (fstat(fd, &sb) == -1) {
360 perror("fstat");
361 close(fd);
362 return 0;
363 }
364
365 fp = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
366 if (fp == MAP_FAILED) {
367 perror("mmap");
368 close(fd);
369 return 0;
370 }
371
372 mbn_hdr = (Mbn_Hdr *)fp;
373 if (strstr(section->file, sections[4].type)) {
374 uint32_t preamble = sections[2].is_present ? SBL_NAND_PREAMBLE : 0;
375
376 mbn_hdr = (Mbn_Hdr *)(fp + preamble + SBL_HDR_RESERVED);
377 }
378 sig_cert_size = mbn_hdr->image_size - mbn_hdr->code_size;
379 if (sig_cert_size != SIG_CERT_2_SIZE && sig_cert_size != SIG_CERT_3_SIZE) {
380 printf("Error: Image without version information\n");
381 close(fd);
382 return 0;
383 }
384
385 cert_offset = mbn_hdr->cert_ptr - mbn_hdr->image_dest_ptr + 40;
386 printf("Image with version information\n");
387 sw_version = find_value((char *)(fp + cert_offset), "SW_ID", 17);
388 if (sw_version != NULL) {
389 sw_version[8] = '\0';
390 sscanf(sw_version, "%x", &section->img_version);
391 printf("SW ID:%d\n", section->img_version);
392 free(sw_version);
393 }
394
395 close(fd);
396 return 1;
397}
398
399int process_elf(char *bin_file, uint8_t **fp, Elf32_Ehdr **elf, Elf32_Phdr **phdr, Mbn_Hdr **mbn_hdr)
400{
401 int fd = open(bin_file, O_RDONLY);
402 struct stat sb;
403 int version = 0;
404 int i = 0;
405
406 if (fd < 0) {
407 perror(bin_file);
408 return 0;
409 }
410
Gokul Sriram Palanisamy767b4572017-09-01 16:02:50 +0530411 memset(&sb, 0, sizeof(struct stat));
Sachin Sundar1ed5f5b2017-03-28 17:34:42 +0530412 if (fstat(fd, &sb) == -1) {
413 perror("fstat");
414 close(fd);
415 return 0;
416 }
417
418 *fp = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
419 if (*fp == MAP_FAILED) {
420 perror("mmap");
421 close(fd);
422 return 0;
423 }
424
425 *elf = (Elf32_Ehdr *)*fp;
426 while (strncmp((char *)&((*elf)->e_ident[1]), "ELF", 3)) {
427 *fp = (uint8_t *)((char *)(*fp) + SBL_NAND_PREAMBLE);
428 *elf = (Elf32_Ehdr *)*fp;
429 }
430
431 *phdr = (Elf32_Phdr *)(*fp + (*elf)->e_phoff);
432 for (i = 0; i < (*elf)->e_phnum; i++, (*phdr)++) {
433 if ((*phdr)->p_flags == HASH_P_FLAG) {
434 *mbn_hdr = (Mbn_Hdr *)(*fp + (*phdr)->p_offset);
435 if ((*mbn_hdr)->image_size != (*mbn_hdr)->code_size) {
436 version = 1;
437 break;
438 } else {
439 printf("Error: Image without version information\n");
440 close(fd);
441 return 0;
442 }
443 }
444 }
445
446 if (version != 1) {
447 printf("Error: Image without version information\n");
448 return 0;
449 }
450
451 close(fd);
452 return 1;
453}
454
455/**
456 * get_sw_id_from_component_bin_elf() parses the ELF header to get the MBN header
457 * of the hash table segment. Parses the MBN header of hash table segment & checks
458 * total size v/s actual component size. If both differ, it means signature &
459 * certificates are appended at end.
460 * Extract the attestation certificate & read the Subject & retreive the SW_ID.
461 *
462 * @bin_file: struct image_section *
463 */
464int get_sw_id_from_component_bin_elf(struct image_section *section)
465{
466 Elf32_Ehdr *elf;
467 Elf32_Phdr *phdr;
468 Mbn_Hdr *mbn_hdr;
469 uint8_t *fp;
470 int cert_offset;
471 char *sw_version;
472
473 if (!process_elf(section->file, &fp, &elf, &phdr, &mbn_hdr)) {
474 return 0;
475 }
476
477 cert_offset = mbn_hdr->cert_ptr - mbn_hdr->image_dest_ptr + 40;
478 printf("Image with version information\n");
479 sw_version = find_value((char *)(fp + phdr->p_offset + cert_offset), "SW_ID", 17);
480 if (sw_version) {
481 sw_version[8] = '\0';
482 sscanf(sw_version, "%x", &section->img_version);
483 printf("SW ID:%d\n", section->img_version);
484 free(sw_version);
485 }
486
487 return 1;
488}
489
490int find_mtd_part_size(void)
491{
492 char *mtdname = "kernel";
493 char prefix[] = "/dev/mtd";
494 char dev[PATH_MAX];
495 int i = -1, fd;
496 int vol_size;
497 int flag = 0;
498 char mtd_part[256];
499 FILE *fp = fopen("/proc/mtd", "r");
500 mtd_info_t mtd_dev_info;
501
502 if (fp == NULL) {
503 printf("Error finding mtd part\n");
504 return -1;
505 }
506
507 while (fgets(dev, sizeof(dev), fp)) {
508 if (strstr(dev, mtdname)) {
509 flag = 1;
510 break;
511 }
512 i++;
513 }
514 fclose(fp);
515
516 if (flag != 1) {
517 printf("%s block not found\n", mtdname);
518 return -1;
519 }
520
521 snprintf(mtd_part, sizeof(mtd_part), "%s%d", prefix, i);
522
523 fd = open(mtd_part, O_RDWR);
524 if (fd == -1) {
525 return -1;
526 }
527
528 if (ioctl(fd, MEMGETINFO, &mtd_dev_info) == -1) {
529 printf("Error getting block size\n");
530 close(fd);
531 return -1;
532 }
533
534 vol_size = mtd_dev_info.erasesize;
535 close(fd);
536
537 return vol_size;
538}
539
540/**
541 * In case of NAND image, Kernel image is ubinized & version information is
542 * part of Kernel image. Hence need to un-ubinize the image.
543 * To get the kernel image, Find the volume with volume id 0. Kernel image
544 * is fragmented and hence to assemble it to get complete image.
545 * In UBI image, first look for UBI#, which is magic number used to identify
546 * each eraseble block. Parse the UBI header, which starts with UBI# & get
547 * the VID(volume ID) header offset as well as Data offset.
548 * Traverse to VID header offset & check the volume ID. If it is ZERO, Kernel
549 * image is stored in this volume. Use Data offset to extract the Kernel image.
550 *
551 * @bin_file: struct image_section *
552 */
553int extract_kernel_binary(struct image_section *section)
554{
555 struct ubi_ec_hdr *ubi_ec;
556 struct ubi_vid_hdr *ubi_vol;
557 uint8_t *fp;
558 int fd, ofd, magic, data_size, vid_hdr_offset, data_offset;
559 struct stat sb;
560
561 fd = open(section->tmp_file, O_RDONLY);
562 if (fd < 0) {
563 perror(section->tmp_file);
564 return 0;
565 }
566
Gokul Sriram Palanisamy767b4572017-09-01 16:02:50 +0530567 memset(&sb, 0, sizeof(struct stat));
Sachin Sundar1ed5f5b2017-03-28 17:34:42 +0530568 if (fstat(fd, &sb) == -1) {
569 perror("fstat");
570 close(fd);
571 return 0;
572 }
573
574 fp = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
575 if (fp == MAP_FAILED) {
576 perror("mmap");
577 close(fd);
578 return 0;
579 }
580
581 ofd = open(section->file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
582 if (ofd == -1) {
583 perror(section->file);
584 close(fd);
585 return 0;
586 }
587
588 data_size = find_mtd_part_size();
589 if (data_size == -1) {
590 printf("Error finding data size\n");
591 return 0;
592 }
593
594 ubi_ec = (struct ubi_ec_hdr *)fp;
595 magic = be32_to_cpu(ubi_ec->magic);
596 while (magic == UBI_EC_HDR_MAGIC) {
597 vid_hdr_offset = be32_to_cpu(ubi_ec->vid_hdr_offset);
598 data_offset = be32_to_cpu(ubi_ec->data_offset);
599 ubi_vol = (struct ubi_vid_hdr *)((uint8_t *)ubi_ec + vid_hdr_offset);
600 magic = be32_to_cpu(ubi_vol->magic);
601 if (magic != UBI_VID_HDR_MAGIC) {
602 printf("Wrong ubi format\n");
603 close(ofd);
604 close(fd);
605 return 0;
606 }
607
608 if (ubi_vol->vol_id == 0) {
609 if (write(ofd, (void *)((uint8_t *)ubi_ec + data_offset), data_size) == -1) {
610 printf("Write error\n");
611 close(fd);
612 close(ofd);
613 return 0;
614 }
615 }
616 if ((int)ubi_vol->vol_id > 0) {
617 break;
618 }
619
620 ubi_ec = (struct ubi_ec_hdr *)((uint8_t *)ubi_ec + data_offset + data_size);
621 magic = be32_to_cpu(ubi_ec->magic);
622 }
623
624 close(ofd);
625 close(fd);
626 printf("Kernel extracted from ubi image\n");
627 return 1;
628}
629
630/**
631 * is_image_version_higher() iterates through each component and check
632 * versions against locally installed version.
633 * If newer component version is lower than locally insatlled image,
634 * abort the FW upgrade process.
635 *
636 * @img: char *
637 */
638int is_image_version_higher(void)
639{
640 int i;
641 for (i = 0; i < NO_OF_SECTIONS; i++) {
642 if (!sections[i].is_present) {
643 continue;
644 }
645
646 if (sections[i].local_version > sections[i].img_version) {
647 printf("Version of image %s (%d) is lower than minimal supported version(%d)\n",
648 sections[i].file,
649 sections[i].img_version,
650 sections[i].local_version);
651 return 0;
652 }
653
654 if (sections[i].img_version > sections[i].max_version) {
655 printf("Version of image %s (%d) is higher than maximum supported version(%d)\n",
656 sections[i].file,
657 sections[i].img_version,
658 sections[i].max_version);
659 }
660 }
661
662 return 1;
663}
664
665/**
666 * Update the version information file based on currently SW_ID being installed.
667 *
668 */
669int update_version(void)
670{
671 int i;
672 for (i = 0; i < NO_OF_SECTIONS; i++) {
673 if (!sections[i].is_present) {
674 continue;
675 }
676
677 if (set_local_image_version(&sections[i]) != 1) {
678 printf("Error updating version of %s\n", sections[i].file);
679 return 0;
680 }
681 }
682
683 return 1;
684}
685
686int check_image_version(void)
687{
688 if (is_version_check_enabled() == 0) {
689 printf("Version check is not enabled, upgrade to continue !!!\n");
690 return 1;
691 }
692
693 if (is_image_version_higher() == 0) {
694 printf("New image versions are lower than existing image, upgrade to STOP !!!\n");
695 return 0;
696 }
697
698 if (update_version() != 1) {
699 printf("Error while updating verison information\n");
700 return 0;
701 }
702 printf("Update completed!\n");
703
704 return 1;
705}
706
707/**
708 * split_code_signature_cert_from_component_bin splits the component
709 * binary by splitting into code(including MBN header), signature file &
710 * attenstation certificate.
711 *
712 * @bin_file: char *
713 * @src: char *
714 * @sig: char *
715 * @cert: char *
716 */
717int split_code_signature_cert_from_component_bin(struct image_section *section,
718 char **src, char **sig, char **cert)
719{
720 Mbn_Hdr *mbn_hdr;
721 int fd = open(section->file, O_RDONLY);
722 uint8_t *fp;
723 int sig_offset = 0;
724 int cert_offset = 0;
725 struct stat sb;
726 int sig_cert_size;
727
728 if (fd == -1) {
729 perror(section->file);
730 return 0;
731 }
732
Gokul Sriram Palanisamy767b4572017-09-01 16:02:50 +0530733 memset(&sb, 0, sizeof(struct stat));
Sachin Sundar1ed5f5b2017-03-28 17:34:42 +0530734 if (fstat(fd, &sb) == -1) {
735 perror("fstat");
736 close(fd);
737 return 0;
738 }
739
740 fp = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
741 if (fp == MAP_FAILED) {
742 perror("mmap");
743 close(fd);
744 return 0;
745 }
746
747 mbn_hdr = (Mbn_Hdr *)fp;
748 if (strstr(section->file, sections[4].type)) {
749 uint32_t preamble = sections[2].is_present ? SBL_NAND_PREAMBLE : 0;
750
751 mbn_hdr = (Mbn_Hdr *)(fp + preamble + SBL_HDR_RESERVED);
752 sig_offset = preamble + MBN_HDR_SIZE;
753 cert_offset = preamble + MBN_HDR_SIZE;
754 }
755 sig_cert_size = mbn_hdr->image_size - mbn_hdr->code_size;
756 if (sig_cert_size != SIG_CERT_2_SIZE && sig_cert_size != SIG_CERT_3_SIZE) {
757 printf("Error: Image without version information\n");
758 close(fd);
759 return 0;
760 }
761 *src = malloc((mbn_hdr->code_size + 1) * sizeof(char));
762 if (*src == NULL) {
763 close(fd);
764 return 0;
765 }
766 memcpy(*src, fp, mbn_hdr->code_size);
767 src_size = mbn_hdr->code_size;
768 (*src)[mbn_hdr->code_size] = '\0';
769
770 sig_offset += mbn_hdr->sig_ptr - mbn_hdr->image_dest_ptr + MBN_HDR_SIZE;
771 *sig = malloc((SIG_SIZE + 1) * sizeof(char));
772 if (*sig == NULL) {
773 free(*src);
774 return 0;
775 }
776 memcpy(*sig, fp + sig_offset, SIG_SIZE);
777 (*sig)[SIG_SIZE] = '\0';
778
779 cert_offset += mbn_hdr->cert_ptr - mbn_hdr->image_dest_ptr + MBN_HDR_SIZE;
780 *cert = malloc((CERT_SIZE + 1) * sizeof(char));
781 if (*cert == NULL) {
782 free(*src);
783 free(*sig);
784 return 0;
785 }
786 memcpy(*cert, fp + cert_offset, CERT_SIZE);
787 (*cert)[CERT_SIZE] = '\0';
788
789 close(fd);
790 return 1;
791}
792
793/**
794 * split_code_signature_cert_from_component_bin_elf splits the component
795 * binary by splitting into code(including ELF header), signature file &
796 * attenstation certificate.
797 *
798 * @bin_file: char *
799 * @src: char *
800 * @sig: char *
801 * @cert: char *
802 */
803int split_code_signature_cert_from_component_bin_elf(struct image_section *section,
804 char **src, char **sig, char **cert)
805{
806 Elf32_Ehdr *elf;
807 Elf32_Phdr *phdr;
808 Mbn_Hdr *mbn_hdr;
809 uint8_t *fp;
810 int sig_offset;
811 int cert_offset;
812 int len;
813
814 if (!process_elf(section->file, &fp, &elf, &phdr, &mbn_hdr)) {
815 return 0;
816 }
817
818 sig_offset = mbn_hdr->sig_ptr - mbn_hdr->image_dest_ptr + MBN_HDR_SIZE;
819 len = MBN_HDR_SIZE + sig_offset;
820 *src = malloc((len + 1) * sizeof(char));
821 if (*src == NULL) {
822 return 0;
823 }
824 memcpy(*src, fp + phdr->p_offset, len);
825 src_size = len;
826 (*src)[len] = '\0';
827
828 *sig = malloc((SIG_SIZE + 1) * sizeof(char));
829 if (*sig == NULL) {
830 free(*src);
831 return 0;
832 }
833 memcpy(*sig, fp + phdr->p_offset + sig_offset, SIG_SIZE);
834 (*sig)[SIG_SIZE] = '\0';
835
836 cert_offset = mbn_hdr->cert_ptr - mbn_hdr->image_dest_ptr + MBN_HDR_SIZE;
837 *cert = malloc((CERT_SIZE + 1) * sizeof(char));
838 if (*cert == NULL) {
839 free(*src);
840 free(*sig);
841 return 0;
842 }
843 memcpy(*cert, fp + phdr->p_offset + cert_offset, CERT_SIZE);
844 (*cert)[CERT_SIZE] = '\0';
845
846 return 1;
847}
848
849/**
850 * being used to calculate the image hash
851 *
852 */
853#define SW_MASK 0x3636363636363636ull
854
855void generate_swid_ipad(char *sw_id, unsigned long long *swid_xor_ipad)
856{
857 unsigned long long int val;
858
859 val = strtoull(sw_id, NULL, 16);
860 *swid_xor_ipad = val ^ SW_MASK;
861
862 printf("%llx\n", *swid_xor_ipad);
863}
864
865/**
866 * being used to calculate the image hash
867 *
868 */
869#define HW_ID_MASK 0x5c5c5c5cull
870#define OEM_ID_MASK 0x00005c5cull
871#define OEM_MODEL_ID_MASK 0x00005c5cull
872
873void generate_hwid_opad(char *hw_id, char *oem_id, char *oem_model_id,
874 unsigned long long *hwid_xor_opad)
875{
876 unsigned long long val;
877
878 val = strtoul(hw_id, NULL, 16);
879 *hwid_xor_opad = ((val ^ HW_ID_MASK) << 32);
880
881 val = strtoul(oem_id, NULL, 16);
882 *hwid_xor_opad |= ((val ^ OEM_ID_MASK) << 16);
883
884 val = strtoul(oem_model_id, NULL, 16);
885 *hwid_xor_opad |= (val ^ OEM_MODEL_ID_MASK) & 0xffff;
886
887 printf("%llx\n", *hwid_xor_opad);
888}
889
890int create_file(char *name, char *buffer, int size)
891{
892 int fd;
893
894 fd = open(name, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
895 if (fd == -1) {
896 perror(name);
897 return 0;
898 }
899
900 if (write(fd, buffer, size) == -1) {
901 close(fd);
902 return 0;
903 }
904
905 close(fd);
906 return 1;
907}
908
909char *create_xor_ipad_opad(char *f_xor, unsigned long long *xor_buffer)
910{
911 int fd;
912 char *file;
913
914 file = mktemp(f_xor);
915 fd = open(file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
916 if (fd == -1) {
917 perror(file);
918 return NULL;
919 }
920
921 if (write(fd, xor_buffer, sizeof(*xor_buffer)) == -1) {
922 close(fd);
923 return 0;
924 }
925
926 close(fd);
927 return file;
928}
929
930char *read_file(char *file_name)
931{
932 int fd;
933 struct stat st;
934 char *buffer;
935
936 fd = open(file_name, O_RDONLY);
937 if (fd == -1) {
938 perror(file_name);
939 return NULL;
940 }
941
Gokul Sriram Palanisamy767b4572017-09-01 16:02:50 +0530942 memset(&st, 0, sizeof(struct stat));
Sachin Sundar1ed5f5b2017-03-28 17:34:42 +0530943 fstat(fd, &st);
944 buffer = malloc(st.st_size * sizeof(buffer));
945 if (buffer == NULL) {
946 close(fd);
947 return NULL;
948 }
949 if (read(fd, buffer, st.st_size) == -1) {
950 close(fd);
951 return NULL;
952 }
953
954 close(fd);
955 return buffer;
956}
957
958int generate_hash(char *cert, char *sw_file, char *hw_file)
959{
960 unsigned long long swid_xor_ipad, hwid_xor_opad;
961 char *tmp;
962 char *sw_id_str = find_value(cert, "SW_ID", 17);
963 char *hw_id_str = find_value(cert, "HW_ID", 9);
964 char *oem_id_str = find_value(cert, "OEM_ID", 5);
965 char *oem_model_id_str = find_value(cert, "MODEL_ID", 5);
966 char f_sw_xor[] = "/tmp/swid_xor_XXXXXX";
967 char f_hw_xor[] = "/tmp/hwid_xor_XXXXXX";
968
969 if (sw_id_str == NULL || hw_id_str == NULL || oem_id_str == NULL || oem_model_id_str == NULL) {
970 if (sw_id_str != NULL) {
971 free(sw_id_str);
972 }
973 if (hw_id_str != NULL) {
974 free(hw_id_str);
975 }
976 if (oem_id_str != NULL) {
977 free(oem_id_str);
978 }
979 if (oem_model_id_str != NULL) {
980 free(oem_model_id_str);
981 }
982 return 0;
983 }
984 printf("sw_id=%s\thw_id=%s\t", sw_id_str, hw_id_str);
985 printf("oem_id=%s\toem_model_id=%s\n", oem_id_str, oem_model_id_str);
986
987 generate_swid_ipad(sw_id_str, &swid_xor_ipad);
988 tmp = create_xor_ipad_opad(f_sw_xor, &swid_xor_ipad);
989 if (tmp == NULL) {
990 free(sw_id_str);
991 free(hw_id_str);
992 free(oem_id_str);
993 free(oem_model_id_str);
994 return 0;
995 }
996 strncpy(sw_file, tmp, 32);
997 free(tmp);
998
999 generate_hwid_opad(hw_id_str, oem_id_str, oem_model_id_str, &hwid_xor_opad);
1000 tmp = create_xor_ipad_opad(f_hw_xor, &hwid_xor_opad);
1001 if (tmp == NULL) {
1002 free(sw_id_str);
1003 free(hw_id_str);
1004 free(oem_id_str);
1005 free(oem_model_id_str);
1006 return 0;
1007 }
1008 strncpy(hw_file, tmp, 32);
1009 free(tmp);
1010
1011 free(sw_id_str);
1012 free(hw_id_str);
1013 free(oem_id_str);
1014 free(oem_model_id_str);
1015
1016 return 1;
1017}
1018
1019void remove_file(char *sw_file, char *hw_file, char *code_file, char *pub_file)
1020{
1021 remove(sw_file);
1022 remove(hw_file);
1023 remove(code_file);
1024 remove(pub_file);
1025 remove("src");
1026 remove("sig");
1027 remove("cert");
1028}
1029
1030/**
1031 * is_component_authenticated() usage the code, signature & public key retrieved
1032 * for each component.
1033 *
1034 * @src: char *
1035 * @sig: char *
1036 * @cert: char *
1037 */
1038int is_component_authenticated(char *src, char *sig, char *cert)
1039{
1040 char command[256];
1041 char *computed_hash;
1042 char *reference_hash;
1043 char pub_key[] = "/tmp/pub_keyXXXXXX", *pub_file;
1044 char code_hash[] = "/tmp/code_hash_XXXXXX", *code_file;
1045 char tmp_hash[] = "/tmp/tmp_hash_XXXXXX", *tmp_file;
1046 char f_computed_hash[] = "/tmp/computed_hash_XXXXXX", *computed_file;
1047 char f_reference_hash[] = "/tmp/reference_hash_XXXXXX", *reference_file;
1048 char sw_file[32],hw_file[32];
1049 int retval;
1050
1051 if (!create_file("src", src, src_size) || !create_file("sig", sig, SIG_SIZE) ||
1052 !create_file("cert", cert, CERT_SIZE)) {
1053 return 0;
1054 }
1055
1056 pub_file = mktemp(pub_key);
1057 snprintf(command, sizeof(command),
1058 "openssl x509 -in cert -pubkey -inform DER -noout > %s", pub_file);
1059 retval = system(command);
1060 if (retval != 0) {
1061 remove("src");
1062 remove("sig");
1063 remove("cert");
1064 printf("Error generating public key\n");
1065 return 0;
1066 }
1067
1068 retval = generate_hash(cert, sw_file, hw_file);
1069 if (retval == 0) {
1070 return 0;
1071 }
1072
1073 code_file = mktemp(code_hash);
1074 snprintf(command, sizeof(command),
1075 "openssl dgst -sha256 -binary -out %s src", code_file);
1076 retval = system(command);
1077 if (retval != 0) {
1078 remove_file(sw_file, hw_file, code_file, pub_file);
1079 printf("Error in openssl digest\n");
1080 return 0;
1081 }
1082
1083 tmp_file = mktemp(tmp_hash);
1084 snprintf(command, sizeof(command),
1085 "cat %s %s | openssl dgst -sha256 -binary -out %s",
1086 sw_file, code_file, tmp_file);
1087 retval = system(command);
1088 if (retval != 0) {
1089 remove_file(sw_file, hw_file, code_file, pub_file);
1090 remove(tmp_file);
1091 printf("Error generating temp has\n");
1092 return 0;
1093 }
1094
1095 computed_file = mktemp(f_computed_hash);
1096 snprintf(command, sizeof(command),
1097 "cat %s %s | openssl dgst -sha256 -binary -out %s",
1098 hw_file, tmp_file, computed_file);
1099 retval = system(command);
1100 if (retval != 0) {
1101 remove_file(sw_file, hw_file, code_file, pub_file);
1102 remove(tmp_file);
1103 remove(computed_file);
1104 printf("Error generating hash\n");
1105 return 0;
1106 }
1107
1108 reference_file = mktemp(f_reference_hash);
1109 snprintf(command, sizeof(command),
1110 "openssl rsautl -in sig -pubin -inkey %s -verify > %s",
1111 pub_file, reference_file);
1112 retval = system(command);
1113 if (retval != 0) {
1114 remove_file(sw_file, hw_file, code_file, pub_file);
1115 remove(tmp_file);
1116 remove(computed_file);
1117 remove(reference_file);
1118 printf("Error generating reference hash\n");
1119 return 0;
1120 }
1121
1122 computed_hash = read_file(computed_file);
1123 reference_hash = read_file(reference_file);
1124 if (computed_hash == NULL || reference_hash == NULL) {
1125 remove_file(sw_file, hw_file, code_file, pub_file);
1126 remove(tmp_file);
1127 remove(computed_file);
1128 remove(reference_file);
1129 free(computed_hash?computed_hash:reference_hash);
1130 return 0;
1131 }
1132
1133 remove_file(sw_file, hw_file, code_file, pub_file);
1134 remove(tmp_file);
1135 remove(computed_file);
1136 remove(reference_file);
1137 if (strcmp(computed_hash, reference_hash)) {
1138 free(computed_hash);
1139 free(reference_hash);
1140 return 1;
1141 }
1142 free(computed_hash);
1143 free(reference_hash);
1144 return 0;
1145}
1146
1147/**
1148 * is_image_authenticated() iterates through each component and check
1149 * whether individual component is authenticated. If not, abort the FW
1150 * upgrade process.
1151 *
1152 * @img: char *
1153 */
1154int is_image_authenticated(void)
1155{
1156 int i;
1157 char *src, *sig, *cert;
1158 for (i = 0; i < NO_OF_SECTIONS; i++) {
1159 if (!sections[i].is_present) {
1160 continue;
1161 }
1162 if (!sections[i].split_components(&sections[i], &src, &sig, &cert)) {
1163 printf("Error while splitting code/signature/Certificate from %s\n",
1164 sections[i].file);
1165 return 0;
1166 }
1167 if (!is_component_authenticated(src, sig, cert)) {
1168 printf("Error while authenticating %s\n", sections[i].file);
1169 return 0;
1170 }
1171 }
1172
1173 return 1;
1174}
1175
1176int do_board_upgrade_check(char *img)
1177{
1178 if (is_authentication_check_enabled()) {
1179 if (!get_sections()) {
1180 printf("Error: %s is not a signed image\n", img);
1181 return 1;
1182 }
1183
1184 if (!is_image_authenticated()) {
1185 printf("Error: \"%s\" couldn't be authenticated. Abort...\n", img);
1186 return 1;
1187 }
1188
1189 if (!check_image_version()) {
1190 printf("Error: \"%s\" couldn't be upgraded. Abort...\n", img);
1191 return 1;
1192 }
1193 }
1194
1195 return 0;
1196}