sysupgrade: Add support to process 64 bit image

The existing sysupgrade treats all images as 32-bit image.
This change adds a check to signify the image class and
adds functions to process the headers respectively.

Change-Id: I04040fdc6e1a9c6c2df2407cd4b26dddaf4a008c
Signed-off-by: Pavithra Palanisamy <pavip@codeaurora.org>
This commit is contained in:
pavip 2017-10-12 14:47:47 +05:30 committed by Pavithra Palanisamy
parent 453d3d213b
commit fb8e307bbc
3 changed files with 200 additions and 14 deletions

View file

@ -113,6 +113,25 @@ typedef struct elfhdr{
header string table" entry offset */
} Elf32_Ehdr;
/*ELF64 Header */
typedef struct elf64hdr{
unsigned char e_ident[EI_NIDENT]; /* ELF Identification */
Elf64_Half e_type; /* object file type */
Elf64_Half e_machine; /* machine */
Elf64_Word e_version; /* object file version */
Elf64_Addr e_entry; /* virtual entry point */
Elf64_Off e_phoff; /* program header table offset */
Elf64_Off e_shoff; /* section header table offset */
Elf64_Word e_flags; /* processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size */
Elf64_Half e_phentsize; /* program header entry size */
Elf64_Half e_phnum; /* number of program header entries */
Elf64_Half e_shentsize; /* section header entry size */
Elf64_Half e_shnum; /* number of section header entries */
Elf64_Half e_shstrndx; /* section header table's "section
header string table" entry offset */
} Elf64_Ehdr;
/* e_type */
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* relocatable file */
@ -411,6 +430,18 @@ typedef struct {
Elf32_Word p_align; /* memory alignment */
} Elf32_Phdr;
/* Program Header Elf64*/
typedef struct {
Elf64_Word p_type; /* segment type */
Elf64_Word p_flags; /* flags */
Elf64_Off p_offset; /* segment offset */
Elf64_Addr p_vaddr; /* virtual address of segment */
Elf64_Addr p_paddr; /* physical address - ignored? */
Elf64_Xword p_filesz; /* number of bytes in file for seg. */
Elf64_Xword p_memsz; /* number of bytes in mem. for seg. */
Elf64_Xword p_align; /* memory alignment */
} Elf64_Phdr;
/* Segment types - p_type */
#define PT_NULL 0 /* unused */
#define PT_LOAD 1 /* loadable segment */

View file

@ -142,11 +142,22 @@ int check_mbn_elf(struct image_section **sec)
elf = (Elf32_Ehdr *)fp;
if (!strncmp((char *)&(elf->e_ident[1]), "ELF", 3)) {
(*sec)->get_sw_id = get_sw_id_from_component_bin_elf;
(*sec)->split_components = split_code_signature_cert_from_component_bin_elf;
/* EI_CLASS Check for 32/64-bit */
if( ((int)(elf->e_ident[4])) == 2) {
(*sec)->get_sw_id = get_sw_id_from_component_bin_elf64;
(*sec)->split_components = split_code_signature_cert_from_component_bin_elf64;
} else {
(*sec)->get_sw_id = get_sw_id_from_component_bin_elf;
(*sec)->split_components = split_code_signature_cert_from_component_bin_elf;
}
} else if (!strncmp((char *)&(((Elf32_Ehdr *)(fp + SBL_NAND_PREAMBLE))->e_ident[1]), "ELF", 3)) {
(*sec)->get_sw_id = get_sw_id_from_component_bin_elf;
(*sec)->split_components = split_code_signature_cert_from_component_bin_elf;
if( ((int)(elf->e_ident[4])) == 2) {
(*sec)->get_sw_id = get_sw_id_from_component_bin_elf64;
(*sec)->split_components = split_code_signature_cert_from_component_bin_elf64;
} else {
(*sec)->get_sw_id = get_sw_id_from_component_bin_elf;
(*sec)->split_components = split_code_signature_cert_from_component_bin_elf;
}
} else {
(*sec)->get_sw_id = get_sw_id_from_component_bin;
(*sec)->split_components = split_code_signature_cert_from_component_bin;
@ -377,9 +388,8 @@ int get_sw_id_from_component_bin(struct image_section *section)
}
sig_cert_size = mbn_hdr->image_size - mbn_hdr->code_size;
if (sig_cert_size != SIG_CERT_2_SIZE && sig_cert_size != SIG_CERT_3_SIZE) {
printf("Error: Image without version information\n");
close(fd);
return 0;
printf("WARNING: signature certificate size is different\n");
// ipq807x has certificate size as dynamic, hence ignore this check
}
cert_offset = mbn_hdr->cert_ptr - mbn_hdr->image_dest_ptr + 40;
@ -452,6 +462,61 @@ int process_elf(char *bin_file, uint8_t **fp, Elf32_Ehdr **elf, Elf32_Phdr **phd
return 1;
}
int process_elf64(char *bin_file, uint8_t **fp, Elf64_Ehdr **elf, Elf64_Phdr **phdr, Mbn_Hdr **mbn_hdr)
{
struct stat sb;
int i, fd, version = 0;
fd = open(bin_file, O_RDONLY);
if (fd < 0) {
perror(bin_file);
return 0;
}
memset(&sb, 0, sizeof(struct stat));
if (fstat(fd, &sb) == -1) {
perror("fstat");
close(fd);
return 0;
}
*fp = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (*fp == MAP_FAILED) {
perror("mmap");
close(fd);
return 0;
}
*elf = (Elf64_Ehdr *)*fp;
while (strncmp((char *)&((*elf)->e_ident[1]), "ELF", 3)) {
*fp = (uint8_t *)((char *)(*fp) + SBL_NAND_PREAMBLE);
*elf = (Elf64_Ehdr *)*fp;
}
*phdr = (Elf64_Phdr *)(*fp + (*elf)->e_phoff);
for (i = 0; i < (*elf)->e_phnum; i++, (*phdr)++) {
if ((*phdr)->p_flags == HASH_P_FLAG) {
*mbn_hdr = (Mbn_Hdr *)(*fp + (*phdr)->p_offset);
if ((*mbn_hdr)->image_size != (*mbn_hdr)->code_size) {
version = 1;
break;
} else {
printf("Error: Image without version information\n");
close(fd);
return 0;
}
}
}
if (version != 1) {
printf("Error: Image without version information\n");
return 0;
}
close(fd);
return 1;
}
/**
* get_sw_id_from_component_bin_elf() parses the ELF header to get the MBN header
* of the hash table segment. Parses the MBN header of hash table segment & checks
@ -487,6 +552,41 @@ int get_sw_id_from_component_bin_elf(struct image_section *section)
return 1;
}
/**
* get_sw_id_from_component_bin_elf64() parses the ELF64 header to get the MBN header
* of the hash table segment. Parses the MBN header of hash table segment & checks
* total size v/s actual component size. If both differ, it means signature &
* certificates are appended at end.
* Extract the attestation certificate & read the Subject & retreive the SW_ID.
*
32_Phdr *phdr;* @bin_file: struct image_section *
*/
int get_sw_id_from_component_bin_elf64(struct image_section *section)
{
Elf64_Ehdr *elf;
Elf64_Phdr *phdr;
Mbn_Hdr *mbn_hdr;
uint8_t *fp;
int cert_offset;
char *sw_version;
if (!process_elf64(section->file, &fp, &elf, &phdr, &mbn_hdr)) {
return 0;
}
cert_offset = mbn_hdr->code_size + mbn_hdr->sig_sz + 40;
printf("Image with version information64\n");
sw_version = find_value((char *)(fp + phdr->p_offset + cert_offset), "SW_ID", 17);
if (sw_version) {
sw_version[8] = '\0';
sscanf(sw_version, "%x", &section->img_version);
printf("SW ID:%d\n", section->img_version);
free(sw_version);
}
return 1;
}
int find_mtd_part_size(void)
{
char *mtdname = "kernel";
@ -846,6 +946,62 @@ int split_code_signature_cert_from_component_bin_elf(struct image_section *secti
return 1;
}
/**
* split_code_signature_cert_from_component_bin_elf64 splits the component
* binary by splitting into code(including ELF header), signature file &
* attenstation certificate.
*
* @bin_file: char *
* @src: char *
* @sig: char *
* @cert: char *
*/
int split_code_signature_cert_from_component_bin_elf64(struct image_section *section,
char **src, char **sig, char **cert)
{
Elf64_Ehdr *elf;
Elf64_Phdr *phdr;
Mbn_Hdr *mbn_hdr;
uint8_t *fp;
int len, sig_offset, cert_offset;
if (!process_elf64(section->file, &fp, &elf, &phdr, &mbn_hdr)) {
return 0;
}
sig_offset = mbn_hdr->code_size + MBN_HDR_SIZE;
len = sig_offset;
*src = malloc((len + 1) * sizeof(char));
if (*src == NULL) {
return 0;
}
memcpy(*src, fp + phdr->p_offset, len);
src_size = len;
(*src)[len] = '\0';
*sig = malloc((SIG_SIZE + 1) * sizeof(char));
if (*sig == NULL) {
free(*src);
return 0;
}
memcpy(*sig, fp + phdr->p_offset + sig_offset, SIG_SIZE);
(*sig)[SIG_SIZE] = '\0';
cert_offset = mbn_hdr->code_size + mbn_hdr->sig_sz + MBN_HDR_SIZE;
*cert = malloc((CERT_SIZE + 1) * sizeof(char));
if (*cert == NULL) {
free(*src);
free(*sig);
return 0;
}
memcpy(*cert, fp + phdr->p_offset + cert_offset, CERT_SIZE);
(*cert)[CERT_SIZE] = '\0';
return 1;
}
/**
* being used to calculate the image hash
*
@ -910,6 +1066,7 @@ char *create_xor_ipad_opad(char *f_xor, unsigned long long *xor_buffer)
{
int fd;
char *file;
unsigned long long sw_id, sw_id_be;
file = mktemp(f_xor);
fd = open(file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
@ -918,11 +1075,9 @@ char *create_xor_ipad_opad(char *f_xor, unsigned long long *xor_buffer)
return NULL;
}
if (write(fd, xor_buffer, sizeof(*xor_buffer)) == -1) {
close(fd);
return 0;
}
sw_id = *xor_buffer;
sw_id_be = htobe64(sw_id);
write(fd, &sw_id_be, sizeof(sw_id_be));
close(fd);
return file;
}
@ -994,7 +1149,6 @@ int generate_hash(char *cert, char *sw_file, char *hw_file)
return 0;
}
strncpy(sw_file, tmp, 32);
free(tmp);
generate_hwid_opad(hw_id_str, oem_id_str, oem_model_id_str, &hwid_xor_opad);
tmp = create_xor_ipad_opad(f_hw_xor, &hwid_xor_opad);
@ -1006,7 +1160,6 @@ int generate_hash(char *cert, char *sw_file, char *hw_file)
return 0;
}
strncpy(hw_file, tmp, 32);
free(tmp);
free(sw_id_str);
free(hw_id_str);

View file

@ -88,12 +88,14 @@ int set_local_image_version(struct image_section *);
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 *);
int is_image_version_higher(void);
int update_version(void);
int check_image_version(void);
int split_code_signature_cert_from_component_bin(struct image_section *, char **, char **, char **);
int split_code_signature_cert_from_component_bin_elf(struct image_section *, char **, char **, char **);
int split_code_signature_cert_from_component_bin_elf64(struct image_section *, char **, char **, char **);
void generate_swid_ipad(char *, unsigned long long *);
void generate_hwid_opad(char *, char *, char *, unsigned long long *);
int generate_hash(char *, char *, char *);