diff --git a/tools/sysupgrade.c b/tools/sysupgrade.c index 0dc2b7ba0b..0682cd4ece 100644 --- a/tools/sysupgrade.c +++ b/tools/sysupgrade.c @@ -24,6 +24,7 @@ #define AUTHENTICATE_FILE "/sys/devices/system/qfprom/qfprom0/authenticate" #define SEC_AUTHENTICATE_FILE "/sys/sec_upgrade/sec_auth" #define TEMP_KERNEL_PATH "/tmp/tmp_kernel.bin" +#define TEMP_ROOTFS_PATH "/tmp/rootfs.bin" #define MAX_SBL_VERSION 11 #define MAX_HLOS_VERSION 32 #define MAX_TZ_VERSION 14 @@ -83,7 +84,7 @@ struct image_section sections[] = { .section_type = HLOS_TYPE, .type = "ubi", .tmp_file = TMP_FILE_DIR, - .pre_op = extract_kernel_binary, + .pre_op = extract_binary, .max_version = MAX_HLOS_VERSION, .file = TEMP_KERNEL_PATH, .version_file = HLOS_VERSION_FILE, @@ -222,7 +223,7 @@ int get_sections(void) return 0; } - data_size = find_mtd_part_size(); + data_size = find_mtd_part_size("kernel"); while ((file = readdir(dir)) != NULL) { for (i = 0, sec = §ions[0]; i < NO_OF_SECTIONS; i++, sec++) { /* Skip loading of ubi section if board is not from nand boot */ @@ -269,7 +270,7 @@ int load_sections(void) return 0; } - data_size = find_mtd_part_size(); + data_size = find_mtd_part_size("kernel"); while ((file = readdir(dir)) != NULL) { for (i = 0, sec = §ions[0]; i < NO_OF_SECTIONS; i++, sec++) { /* Skip loading of ubi section if board is not from nand boot */ @@ -277,7 +278,6 @@ int load_sections(void) continue; if (!strncmp(file->d_name, sec->type, strlen(sec->type))) { strlcat(sec->file, file->d_name, sizeof(sec->file)); - if (sec->pre_op) { strlcat(sec->tmp_file, file->d_name, sizeof(sec->tmp_file)); @@ -701,9 +701,8 @@ int get_sw_id_from_component_bin_elf64(struct image_section *section) return 1; } -int find_mtd_part_size(void) +int find_mtd_part_size(char *mtdname) { - char *mtdname = "kernel"; char prefix[] = "/dev/mtd"; char dev[PATH_MAX]; int i = -1, fd; @@ -754,7 +753,7 @@ int find_mtd_part_size(void) /** * Helper function to dynamically get volume id */ -int get_kernel_volume_id(void) +int get_ubi_volume_id(char *vol_name) { int i, number_of_ubi_volumes; char ubi_vol_count[] = "/sys/class/ubi/ubi0/volumes_count"; @@ -775,8 +774,9 @@ int get_kernel_volume_id(void) snprintf(ubi_vol, sizeof(ubi_vol), "%s%d%s", prefix, i, suffix); fp = fopen(ubi_vol, "r"); fgets(ubi_vol_name, sizeof(ubi_vol_name), fp); - if (strstr(ubi_vol_name, "kernel")) { - printf("kernel ubi volume id = %d\n", i); + if (strstr(ubi_vol_name, vol_name)) { + printf("%s volume id = %d\n", vol_name, i); + close(fp); return i; } } @@ -784,6 +784,21 @@ int get_kernel_volume_id(void) return -1; } +/** + * For NAND image, kernel and rootfs image is ubinized. + * Hence need to un-ubinize the ubi image and extract both kernel + * and rootfs images. Kernel image section and volume name are passed as + * argument in extract_kernel_binary(). After kernel extraction, + * parse_elf_image_phdr() is called which parses the ELF32 program header + * to get the ELF header of rootfs metadata. + */ + +void extract_binary(struct image_section *section) +{ + extract_kernel_binary(section, "kernel"); + parse_elf_image_phdr(section); +} + /** * In case of NAND image, Kernel image is ubinized & version information is * part of Kernel image. Hence need to un-ubinize the image. @@ -798,18 +813,47 @@ int get_kernel_volume_id(void) * * @bin_file: struct image_section * */ -int extract_kernel_binary(struct image_section *section) + +int extract_kernel_binary(struct image_section *section, char *volname) +{ + char *ifname, *ofname; + + ifname = section->tmp_file; + ofname = section->file; + + if (extract_ubi_volume(volname, ifname, ofname) != 1) { + printf("Image extraction failed\n"); + return 0; + } + return 1; +} + +/** + * extract_ubi_volume() extracts both kernel image and rootfs image + * from UBI image. extract_kernel_binary() passes volume name, + * UBI image as Input file name, kernel or rootfs as Output file name. + * This function finds respective UBI volume ID, identifies each eraseble + * block. Parses UBI header and gets Volume ID header offset as well as + * Data offset. When volume ID matches for kernel and rootfs, Uses data offset + * to extract both images separately. + */ + +int extract_ubi_volume(char *vol_name, char *if_name, char *of_name) { struct ubi_ec_hdr *ubi_ec; struct ubi_vid_hdr *ubi_vol; uint8_t *fp; int fd, ofd, magic, data_size, vid_hdr_offset, data_offset; - int kernel_vol_id, curr_vol_id; + int ret_vol_id, curr_vol_id; struct stat sb; - fd = open(section->tmp_file, O_RDONLY); + if (if_name == NULL) { + return 0; + } + + fd = open(if_name, O_RDONLY); if (fd < 0) { - perror(section->tmp_file); + perror(if_name); return 0; } @@ -827,21 +871,21 @@ int extract_kernel_binary(struct image_section *section) return 0; } - ofd = open(section->file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + ofd = open(of_name, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); if (ofd == -1) { - perror(section->file); + perror(of_name); close(fd); return 0; } - data_size = find_mtd_part_size(); + data_size = find_mtd_part_size(vol_name); if (data_size == -1) { printf("Error finding data size\n"); return 0; } - kernel_vol_id = get_kernel_volume_id(); - if (kernel_vol_id == -1) { + ret_vol_id = get_ubi_volume_id(vol_name); + if (ret_vol_id == -1) { printf("Wrong ubi volume id for kernel\n"); return 0; } @@ -861,7 +905,22 @@ int extract_kernel_binary(struct image_section *section) } curr_vol_id = be32_to_cpu(ubi_vol->vol_id); - if (curr_vol_id == kernel_vol_id) { + if (curr_vol_id == ret_vol_id) { + if (ret_vol_id == 2) { + struct ubi_ec_hdr *ubi_ec_next = (struct ubi_ec_hdr *)((uint8_t *)ubi_ec + data_offset + data_size); + int magic = be32_to_cpu(ubi_ec_next->magic); + if(magic != UBI_EC_HDR_MAGIC) { + uint8_t *tmp = (uint8_t *)ubi_ec + data_offset; + int max_limit = data_size; + int byte = 0; + while (byte < max_limit) { + if ((*(tmp+byte) == 0xde) && (*(tmp+byte+1) == 0xad) && (*(tmp+byte+2) == 0xc0) && (*(tmp+byte+3) == 0xde)) { + data_size = byte + 4; + } + byte = byte + 1; + } + } + } if (write(ofd, (void *)((uint8_t *)ubi_ec + data_offset), data_size) == -1) { printf("Write error\n"); close(fd); @@ -869,14 +928,125 @@ int extract_kernel_binary(struct image_section *section) return 0; } } - ubi_ec = (struct ubi_ec_hdr *)((uint8_t *)ubi_ec + data_offset + data_size); magic = be32_to_cpu(ubi_ec->magic); } - + if (munmap(fp, sb.st_size) == -1) { + perror("munmap"); + close(ofd); + close(fd); + return 0; + } close(ofd); close(fd); - printf("Kernel extracted from ubi image\n"); + printf("%s extracted from ubi image\n", vol_name); + return 1; +} + +/** + * check_image_exist() used to check whether the ubi image for NAND + * or rootfs image for EMMC are available in /tmp directory. + * If respective image was found, the filename will be passed. If + * not found, it returns NULL + */ + +char * check_image_exist(char *imgname) { + DIR* FD; + struct dirent* in_file; + char extension[256] = "/tmp/"; + + /* Scanning the in directory */ + if (NULL == (FD = opendir ("/tmp"))) + { + fprintf(stderr, "Error : Failed to open input directory\n"); + return NULL; + } + + while ((in_file = readdir(FD))) + { + if (strstr(in_file->d_name, imgname)) { + printf("%s file found\n", in_file->d_name); + strlcat(extension, in_file->d_name, sizeof(extension)); + strlcpy(in_file->d_name, extension, sizeof(extension)); + return in_file->d_name; + } + } + return NULL; +} + +/** + * In case of EMMC, extract_rootfs_binary() extracts the rootfs image + * till Deadcode from existing rootfs image. After extraction, the new rootfs + * image will replace old rootfs image. This function removes padded + * binaries and helps to authenticate rootfs image using sec_auth + */ + +int extract_rootfs_binary(char *filename) +{ + int ifd, ofd; + uint8_t *fp; + struct stat sb; + + if (filename == NULL) { + return 0; + } + + ifd = open(filename, O_RDONLY); + if (ifd < 0) { + perror(filename); + return 0; + } + + memset(&sb, 0, sizeof(struct stat)); + if (fstat(ifd, &sb) == -1) { + perror("fstat"); + close(ifd); + return 0; + } + + fp = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, ifd, 0); + if (fp == MAP_FAILED) { + perror("mmap"); + close(fp); + return 0; + } + + ofd = open(TEMP_ROOTFS_PATH, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + if (ofd < 0) { + perror("fopen"); + close(ifd); + return 0; + } + + int offset = 0,dead_off; + while ( offset < sb.st_size) + { + if ((fp[offset] == 0xde) && (fp[offset+1] == 0xad) && (fp[offset+2] == 0xc0) && (fp[offset+3] == 0xde)) { + dead_off=offset; + } + offset = offset + 4096; + } + + if((write(ofd, fp, dead_off+4)) == -1) { + printf("Write error\n"); + close(ifd); + close(ofd); + return 0; + } + + if (munmap(fp, sb.st_size) == -1) { + perror("munmap"); + close(ifd); + close(ofd); + return 0; + } + + close(ifd); + close(ofd); + + if (rename(TEMP_ROOTFS_PATH, filename) != 0) { + printf("Error renaming file\n"); + } return 1; } @@ -1635,6 +1805,9 @@ int sec_image_auth(void) int do_board_upgrade_check(char *img) { if (is_tz_authentication_enabled()) { + /* If image is having signed rootfs image, then extract kernel and rootfs binary for parsing metadata. */ + extract_rootfs_binary(check_image_exist("rootfs-")); + extract_ubi_volume("ubi_rootfs", check_image_exist("ubi-"), TEMP_ROOTFS_PATH); printf("TZ authentication enabled ...\n"); if (!load_sections()) { printf("Error: Failed to load sections from image: %s\n", img); diff --git a/tools/sysupgrade.h b/tools/sysupgrade.h index 277331fc1e..c32c5c4808 100644 --- a/tools/sysupgrade.h +++ b/tools/sysupgrade.h @@ -113,7 +113,8 @@ int is_version_check_enabled(void); int get_sw_id_from_component_bin(struct image_section *); int get_sw_id_from_component_bin_elf(struct image_section *); int get_sw_id_from_component_bin_elf64(struct image_section *); -int extract_kernel_binary(struct image_section *); +void extract_binary(struct image_section *); +int extract_kernel_binary(struct image_section *, char *); int is_image_version_higher(void); int update_version(void); int check_image_version(void); @@ -127,7 +128,8 @@ int is_component_authenticated(char *, char *, char *); int is_image_authenticated(void); int do_board_upgrade_check(char *); int check_nand_preamble(uint8_t *); -int find_mtd_part_size(void); +int find_mtd_part_size(char *); int create_file(char *, char *, int ); int parse_elf_image_phdr(struct image_section *); int compute_sha384(struct image_section *); +char *check_image_exist(char *);