* NOTE: This currently only implements support for MBN version 6 (as used by sc7180). Support * for other MBN versions could probably be added but may require more parsing to tell them * apart, and minor modifications (e.g. different hash algorithm). Add later as needed. */
| 112 | * apart, and minor modifications (e.g. different hash algorithm). Add later as needed. |
| 113 | */ |
| 114 | static void *qualcomm_find_hash(struct buffer *in, size_t bb_offset, struct vb2_hash *real_hash) |
| 115 | { |
| 116 | Elf64_Phdr *ph; |
| 117 | struct buffer elf; |
| 118 | buffer_clone(&elf, in); |
| 119 | |
| 120 | /* When buffer_size(&elf) becomes this small, we know we've searched through 32KiB (or |
| 121 | the whole bootblock) without finding anything, so we know we can stop looking. */ |
| 122 | size_t search_end_size = MIN(0, buffer_size(in) - 32 * KiB); |
| 123 | |
| 124 | /* To identify a Qualcomm image, first we find the GPT header... */ |
| 125 | while (buffer_size(&elf) > search_end_size && |
| 126 | !buffer_check_magic(&elf, "EFI PART", 8)) |
| 127 | buffer_seek(&elf, 512); |
| 128 | |
| 129 | /* ...then shortly afterwards there's an ELF header... */ |
| 130 | while (buffer_size(&elf) > search_end_size && |
| 131 | !buffer_check_magic(&elf, ELFMAG, 4)) |
| 132 | buffer_seek(&elf, 512); |
| 133 | |
| 134 | if (buffer_size(&elf) <= search_end_size) |
| 135 | return NULL; /* Doesn't seem to be a Qualcomm image. */ |
| 136 | |
| 137 | struct parsed_elf pelf; |
| 138 | if (parse_elf(&elf, &pelf, ELF_PARSE_PHDR)) |
| 139 | return NULL; /* Not an ELF -- guess not a Qualcomm MBN after all? */ |
| 140 | |
| 141 | /* |
| 142 | * Check if it is a multi ELF or single ELF. If bb_offset is beyond the |
| 143 | * final segment of first ELF, it is a multi ELF. |
| 144 | */ |
| 145 | ph = &pelf.phdr[pelf.ehdr.e_phnum - 1]; |
| 146 | if (bb_offset > (ph->p_offset + ph->p_filesz)) { /* MBNv7 multi ELF */ |
| 147 | parsed_elf_destroy(&pelf); |
| 148 | return qualcomm_find_hash_mbnv7(&elf, bb_offset, real_hash); |
| 149 | } |
| 150 | |
| 151 | /* Qualcomm stores an array of SHA-384 hashes in a special ELF segment. One special one |
| 152 | to start with, and then one for each segment in order. */ |
| 153 | void *bb_hash = NULL; |
| 154 | void *hashtable = NULL; |
| 155 | int i; |
| 156 | int bb_segment = -1; |
| 157 | for (i = 0; i < pelf.ehdr.e_phnum; i++) { |
| 158 | ph = &pelf.phdr[i]; |
| 159 | if ((ph->p_flags & PF_QC_SG_MASK) == PF_QC_SG_HASH) { |
| 160 | if ((int)ph->p_filesz != |
| 161 | (pelf.ehdr.e_phnum + 1) * VB2_SHA384_DIGEST_SIZE) { |
| 162 | ERROR("fixups: Qualcomm hash segment has wrong size!\n"); |
| 163 | goto destroy_elf; |
| 164 | } /* Found the table with the hashes -- store its address. */ |
| 165 | hashtable = buffer_get(&elf) + ph->p_offset; |
| 166 | } else if (bb_segment < 0 && ph->p_offset + ph->p_filesz < buffer_size(&elf) && |
| 167 | buffer_offset(&elf) + ph->p_offset <= bb_offset && |
| 168 | buffer_offset(&elf) + ph->p_offset + ph->p_filesz > bb_offset) { |
| 169 | bb_segment = i; /* Found the bootblock segment -- store its index. */ |
| 170 | } |
| 171 | } |
no test coverage detected