Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | |
| 2 * Use of this source code is governed by a BSD-style license that can be | |
| 3 * found in the LICENSE file. | |
| 4 * | |
| 5 * Routines for verifying a firmware image's signature. | |
| 6 */ | |
| 7 | |
| 8 #include <errno.h> | |
| 9 #include <fcntl.h> | |
| 10 #include <stdio.h> | |
| 11 #include <stdlib.h> | |
| 12 #include <string.h> | |
| 13 #include <sys/mman.h> | |
| 14 #include <sys/stat.h> | |
| 15 #include <sys/types.h> | |
| 16 #include <unistd.h> | |
| 17 | |
| 18 #include "fmap.h" | |
| 19 #include "gbb_header.h" | |
| 20 #include "load_firmware_fw.h" | |
| 21 #include "vboot_struct.h" | |
| 22 | |
| 23 | |
| 24 typedef struct _CallerInternal { | |
| 25 struct { | |
| 26 uint8_t *fw; | |
|
Randall Spangler
2011/02/09 19:42:14
Google style nit: * is next to the type, not the v
Che-Liang Chiou
2011/02/10 09:11:03
Done.
| |
| 27 uint64_t size; | |
| 28 } firmware[2]; | |
| 29 } CallerInternal; | |
| 30 | |
| 31 static char *progname = NULL; | |
| 32 static char *image_path = NULL; | |
| 33 | |
| 34 | |
| 35 /* return -1 on error */ | |
| 36 int area_index(FmapHeader *fh, AreaHeader *ah, const char name[]); | |
|
Randall Spangler
2011/02/09 19:42:14
move to fmap.h; add more description
Che-Liang Chiou
2011/02/10 09:11:03
Done.
| |
| 37 /* wrapper of area_index; print error when not found */ | |
| 38 int area_index_or_error(FmapHeader *fh, AreaHeader *ah, const char name[]); | |
| 39 /* return NULL on error */ | |
| 40 const char *status_string(int status); | |
| 41 | |
| 42 int GetFirmwareBody(LoadFirmwareParams *params, uint64_t firmware_index) { | |
| 43 CallerInternal* ci = (CallerInternal *) params->caller_internal; | |
| 44 | |
| 45 if (firmware_index != 0 && firmware_index != 1) | |
| 46 return 1; | |
| 47 | |
| 48 UpdateFirmwareBodyHash(params, | |
| 49 ci->firmware[firmware_index].fw, | |
| 50 ci->firmware[firmware_index].size); | |
| 51 | |
| 52 return 0; | |
| 53 } | |
| 54 | |
| 55 /* return zero on success, non-zero on error */ | |
| 56 int drive_load_firmware(void *base_of_rom, void *fmap) { | |
|
gauravsh
2011/02/09 19:58:22
comment on arguments and what the function does?
Che-Liang Chiou
2011/02/10 09:11:03
Done.
| |
| 57 LoadFirmwareParams lfp; | |
| 58 CallerInternal ci; | |
| 59 | |
| 60 FmapHeader *fh = (FmapHeader *) fmap; | |
| 61 AreaHeader *ah = (AreaHeader *) (fmap + sizeof(FmapHeader)); | |
| 62 int retval = 1; | |
| 63 int i, j, k, status; | |
| 64 void *gbb, *kb; | |
| 65 GoogleBinaryBlockHeader *gbbh; | |
| 66 VbKeyBlockHeader *kbh; | |
| 67 VbFirmwarePreambleHeader *fph; | |
| 68 const char *status_str; | |
| 69 | |
| 70 const char *key_area_name[2] = { | |
| 71 "Firmware A Key", | |
| 72 "Firmware B Key" | |
| 73 }; | |
| 74 void **vblock_ptr[2] = { | |
| 75 &lfp.verification_block_0, | |
| 76 &lfp.verification_block_1 | |
| 77 }; | |
| 78 uint64_t *vsize_ptr[2] = { | |
| 79 &lfp.verification_size_0, | |
| 80 &lfp.verification_size_1 | |
| 81 }; | |
| 82 | |
| 83 const char *data_area_name[2] = { | |
| 84 "Firmware A Data", | |
| 85 "Firmware B Data" | |
| 86 }; | |
| 87 | |
| 88 i = area_index_or_error(fh, ah, "GBB Area"); | |
| 89 if (i < 0) | |
| 90 goto EXIT; | |
| 91 | |
| 92 gbb = base_of_rom + ah[i].area_offset; | |
|
gauravsh
2011/02/09 19:58:22
2 comments -
1) this method is pretty big. conside
Che-Liang Chiou
2011/02/10 09:11:03
Done.
| |
| 93 gbbh = (GoogleBinaryBlockHeader *) gbb; | |
| 94 lfp.firmware_root_key_blob = gbb + gbbh->rootkey_offset; | |
| 95 printf("firmware root key blob at 0x%08" PRIx64 "\n", | |
| 96 lfp.firmware_root_key_blob - base_of_rom); | |
| 97 | |
| 98 for (k = 0; k < 2; k ++) { | |
| 99 i = area_index_or_error(fh, ah, key_area_name[k]); | |
| 100 if (i < 0) | |
| 101 goto EXIT; | |
| 102 | |
| 103 j = area_index_or_error(fh, ah, data_area_name[k]); | |
| 104 if (j < 0) | |
| 105 goto EXIT; | |
| 106 | |
| 107 kb = base_of_rom + ah[i].area_offset; | |
| 108 | |
| 109 *vblock_ptr[k] = kb; | |
| 110 printf("verification block %d at 0x%08" PRIx64 "\n", k, | |
| 111 *vblock_ptr[k] - base_of_rom); | |
| 112 | |
| 113 kbh = (VbKeyBlockHeader *) kb; | |
| 114 fph = (VbFirmwarePreambleHeader *) (kb + kbh->key_block_size); | |
| 115 | |
| 116 *vsize_ptr[k] = kbh->key_block_size + fph->preamble_size; | |
| 117 printf("verification block %d size is 0x%08" PRIx64 "\n", k, *vsize_ptr[k]); | |
| 118 | |
| 119 ci.firmware[k].fw = (uint8_t *) (base_of_rom + ah[j].area_offset); | |
| 120 printf("firmware %c at 0x%08" PRIx64 "\n", "AB"[k], | |
| 121 (void *) ci.firmware[k].fw - base_of_rom); | |
| 122 | |
| 123 ci.firmware[k].size = (uint64_t) fph->body_signature.data_size; | |
| 124 printf("firmware %c size is 0x%08" PRIx64 "\n", "AB"[k], | |
| 125 ci.firmware[k].size); | |
| 126 } | |
| 127 lfp.caller_internal = &ci; | |
| 128 | |
| 129 /* remember to free kernel_sign_key_blob before exit */ | |
| 130 lfp.kernel_sign_key_blob = malloc(LOAD_FIRMWARE_KEY_BLOB_REC_SIZE); | |
| 131 lfp.kernel_sign_key_size = LOAD_FIRMWARE_KEY_BLOB_REC_SIZE; | |
| 132 printf("kernel sign key size is 0x%08" PRIx64 "\n", lfp.kernel_sign_key_size); | |
| 133 | |
| 134 lfp.boot_flags = 0; | |
| 135 printf("boot flags is 0x%08" PRIx64 "\n", lfp.boot_flags); | |
| 136 | |
| 137 status = LoadFirmware(&lfp); | |
| 138 status_str = status_string(status); | |
| 139 if (status_str) | |
| 140 printf("LoadFirmware returns %s\n", status_str); | |
| 141 else | |
| 142 printf("LoadFirmware returns unknown status code: %d\n", status); | |
| 143 if (status == LOAD_FIRMWARE_SUCCESS) | |
| 144 printf("firmwiare index is %" PRIu64 "\n", lfp.firmware_index); | |
| 145 | |
| 146 free(lfp.kernel_sign_key_blob); | |
| 147 retval = 0; | |
| 148 | |
| 149 EXIT: | |
|
gauravsh
2011/02/09 19:58:22
in general, we try to avoid goto. refactor to not
Che-Liang Chiou
2011/02/10 09:11:03
Done.
| |
| 150 return retval; | |
| 151 } | |
| 152 | |
| 153 /* return -1 on error */ | |
| 154 int area_index(FmapHeader *fh, AreaHeader *ah, const char name[]) { | |
|
Randall Spangler
2011/02/09 19:42:14
Move these to fmap.c
Use Fmap prefix on all funct
Randall Spangler
2011/02/09 19:42:14
const char* name
Che-Liang Chiou
2011/02/10 09:11:03
Done.
Che-Liang Chiou
2011/02/10 09:11:03
Done.
| |
| 155 size_t len = strlen(name); | |
|
Randall Spangler
2011/02/09 19:42:14
Is this just an optimization to save doing the imp
Che-Liang Chiou
2011/02/10 09:11:03
I guess not.
| |
| 156 int i; | |
| 157 for (i = 0; i < fh->fmap_nareas; i++) | |
| 158 if (!strncmp((const char *) ah[i].area_name, name, len)) | |
| 159 return i; | |
| 160 return -1; | |
| 161 } | |
| 162 | |
| 163 /* wrap area_index; print error when not found */ | |
| 164 int area_index_or_error(FmapHeader *fh, AreaHeader *ah, const char name[]) { | |
|
gauravsh
2011/02/09 19:58:22
this looks like it could be moved to fmap.c
Che-Liang Chiou
2011/02/10 09:11:03
progname is a static global variable of load_firmw
| |
| 165 int i = area_index(fh, ah, name); | |
| 166 if (i < 0) | |
| 167 fprintf(stderr, "%s: can't find %s in firmware image\n", progname, name); | |
| 168 return i; | |
| 169 } | |
| 170 | |
| 171 /* return NULL on error */ | |
| 172 const char *status_string(int status) { | |
|
gauravsh
2011/02/09 19:58:22
comment?
Che-Liang Chiou
2011/02/10 09:11:03
Done.
| |
| 173 switch (status) { | |
| 174 case LOAD_FIRMWARE_SUCCESS: | |
| 175 return "LOAD_FIRMWARE_SUCCESS"; | |
| 176 case LOAD_FIRMWARE_RECOVERY: | |
| 177 return "LOAD_FIRMWARE_RECOVERY"; | |
| 178 case LOAD_FIRMWARE_REBOOT: | |
| 179 return "LOAD_FIRMWARE_REBOOT"; | |
| 180 case LOAD_FIRMWARE_RECOVERY_TPM: | |
| 181 return "LOAD_FIRMWARE_RECOVERY_TPM"; | |
| 182 default: | |
| 183 return NULL; | |
| 184 } | |
| 185 } | |
| 186 | |
| 187 /* main function and its subroutines */ | |
| 188 | |
| 189 void error_and_exit(char *action_name) { | |
| 190 fprintf(stderr, "%s: can't %s %s: %s\n", | |
| 191 progname, | |
| 192 action_name, | |
| 193 image_path, | |
| 194 strerror(errno)); | |
| 195 exit(1); | |
| 196 } | |
| 197 | |
| 198 int main(int argc, char *argv[]) { | |
| 199 int fd, retval = 0; | |
| 200 struct stat sb; | |
| 201 void *base_of_rom, *fmap; | |
| 202 | |
| 203 progname = argv[0]; | |
| 204 | |
| 205 if (argc < 2) { | |
| 206 fprintf(stderr, "usage: %s <firmware_image>\n", progname); | |
| 207 exit(1); | |
| 208 } | |
| 209 | |
| 210 image_path = argv[1]; | |
| 211 | |
| 212 if (0 != stat(image_path, &sb)) | |
| 213 error_and_exit("stat"); | |
| 214 | |
| 215 fd = open(image_path, O_RDONLY); | |
|
Randall Spangler
2011/02/09 19:42:14
Why not just use ReadFile() from host lib? Code w
Che-Liang Chiou
2011/02/10 09:11:03
Done.
| |
| 216 if (fd < 0) | |
| 217 error_and_exit("open"); | |
| 218 | |
| 219 printf("opened %s\n", image_path); | |
| 220 | |
| 221 base_of_rom = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); | |
|
gauravsh
2011/02/09 19:58:22
i don't think it is really any better to use mmap(
Che-Liang Chiou
2011/02/10 09:11:03
Done.
| |
| 222 if (base_of_rom == (void *) -1) { | |
| 223 close(fd); | |
| 224 error_and_exit("mmap"); | |
| 225 } | |
| 226 | |
| 227 fmap = find_fmap((char *) base_of_rom, sb.st_size); | |
| 228 | |
| 229 retval = drive_load_firmware(base_of_rom, fmap); | |
| 230 | |
| 231 if (0 != munmap(base_of_rom, sb.st_size)) { | |
| 232 close(fd); | |
| 233 error_and_exit("munmap"); | |
| 234 } | |
| 235 | |
| 236 if (0 != close(fd)) | |
| 237 error_and_exit("close"); | |
| 238 | |
| 239 return retval; | |
| 240 } | |
| OLD | NEW |