blob: 8421b253773e8173a7d3b21110f059d32f7a8273 [file] [log] [blame]
Bill Richardsoncf6e78d2014-08-27 15:50:25 -07001/*
2 * Copyright 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Bill Richardsoncf6e78d2014-08-27 15:50:25 -07007#include <stdint.h>
8#include <stdio.h>
Bill Richardsoncf6e78d2014-08-27 15:50:25 -07009
Bill Richardson25593382015-01-30 12:22:28 -080010#include "file_type.h"
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070011#include "fmap.h"
12#include "futility.h"
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070013#include "traversal.h"
14
15/* What functions do we invoke for a particular operation and component? */
16
17/* FUTIL_OP_SHOW */
Bill Richardson6f72ffa2014-09-23 14:40:20 -070018static int (* const cb_show_funcs[])(struct futil_traverse_state_s *state) = {
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070019 futil_cb_show_begin, /* CB_BEGIN_TRAVERSAL */
20 NULL, /* CB_END_TRAVERSAL */
21 futil_cb_show_gbb, /* CB_FMAP_GBB */
22 futil_cb_show_fw_preamble, /* CB_FMAP_VBLOCK_A */
23 futil_cb_show_fw_preamble, /* CB_FMAP_VBLOCK_B */
Bill Richardson6f72ffa2014-09-23 14:40:20 -070024 futil_cb_show_fw_main, /* CB_FMAP_FW_MAIN_A */
25 futil_cb_show_fw_main, /* CB_FMAP_FW_MAIN_B */
Bill Richardson4805f182015-01-30 22:21:10 -080026 futil_cb_show_pubkey, /* CB_PUBKEY */
Bill Richardson6f72ffa2014-09-23 14:40:20 -070027 futil_cb_show_keyblock, /* CB_KEYBLOCK */
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070028 futil_cb_show_gbb, /* CB_GBB */
29 futil_cb_show_fw_preamble, /* CB_FW_PREAMBLE */
Bill Richardson5f2696d2014-09-23 22:03:56 -070030 futil_cb_show_kernel_preamble, /* CB_KERN_PREAMBLE */
Bill Richardson6f72ffa2014-09-23 14:40:20 -070031 NULL, /* CB_RAW_FIRMWARE */
32 NULL, /* CB_RAW_KERNEL */
Bill Richardson4805f182015-01-30 22:21:10 -080033 futil_cb_show_privkey, /* CB_PRIVKEY */
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070034};
35BUILD_ASSERT(ARRAY_SIZE(cb_show_funcs) == NUM_CB_COMPONENTS);
36
Bill Richardson15dc6fc2014-09-02 14:45:44 -070037/* FUTIL_OP_SIGN */
Bill Richardson6f72ffa2014-09-23 14:40:20 -070038static int (* const cb_sign_funcs[])(struct futil_traverse_state_s *state) = {
Bill Richardson15dc6fc2014-09-02 14:45:44 -070039 futil_cb_sign_begin, /* CB_BEGIN_TRAVERSAL */
40 futil_cb_sign_end, /* CB_END_TRAVERSAL */
41 NULL, /* CB_FMAP_GBB */
Bill Richardson5f2696d2014-09-23 22:03:56 -070042 futil_cb_sign_fw_vblock, /* CB_FMAP_VBLOCK_A */
43 futil_cb_sign_fw_vblock, /* CB_FMAP_VBLOCK_B */
44 futil_cb_sign_fw_main, /* CB_FMAP_FW_MAIN_A */
45 futil_cb_sign_fw_main, /* CB_FMAP_FW_MAIN_B */
46 futil_cb_sign_pubkey, /* CB_PUBKEY */
47 NULL, /* CB_KEYBLOCK */
48 NULL, /* CB_GBB */
49 NULL, /* CB_FW_PREAMBLE */
50 futil_cb_resign_kernel_part, /* CB_KERN_PREAMBLE */
51 futil_cb_sign_raw_firmware, /* CB_RAW_FIRMWARE */
52 futil_cb_create_kernel_part, /* CB_RAW_KERNEL */
Bill Richardson4805f182015-01-30 22:21:10 -080053 NULL, /* CB_PRIVKEY */
Bill Richardson15dc6fc2014-09-02 14:45:44 -070054};
55BUILD_ASSERT(ARRAY_SIZE(cb_sign_funcs) == NUM_CB_COMPONENTS);
56
Bill Richardson6f72ffa2014-09-23 14:40:20 -070057static int (* const * const cb_func[])(struct futil_traverse_state_s *state) = {
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070058 cb_show_funcs,
Bill Richardson15dc6fc2014-09-02 14:45:44 -070059 cb_sign_funcs,
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070060};
61BUILD_ASSERT(ARRAY_SIZE(cb_func) == NUM_FUTIL_OPS);
62
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070063/*
64 * File types that don't need iterating can use a lookup table to determine the
65 * callback component and name. The index is the file type.
66 */
67static const struct {
68 enum futil_cb_component component;
69 const char * const name;
70} direct_callback[] = {
71 {0, NULL}, /* FILE_TYPE_UNKNOWN */
72 {CB_PUBKEY, "VbPublicKey"}, /* FILE_TYPE_PUBKEY */
73 {CB_KEYBLOCK, "VbKeyBlock"}, /* FILE_TYPE_KEYBLOCK */
Bill Richardson6f72ffa2014-09-23 14:40:20 -070074 {CB_FW_PREAMBLE, "FW Preamble"}, /* FILE_TYPE_FW_PREAMBLE */
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070075 {CB_GBB, "GBB"}, /* FILE_TYPE_GBB */
76 {0, NULL}, /* FILE_TYPE_BIOS_IMAGE */
77 {0, NULL}, /* FILE_TYPE_OLD_BIOS_IMAGE */
Bill Richardson6f72ffa2014-09-23 14:40:20 -070078 {CB_KERN_PREAMBLE, "Kernel Preamble"}, /* FILE_TYPE_KERN_PREAMBLE */
79 {CB_RAW_FIRMWARE, "raw firmware"}, /* FILE_TYPE_RAW_FIRMWARE */
80 {CB_RAW_KERNEL, "raw kernel"}, /* FILE_TYPE_RAW_KERNEL */
Bill Richardson25593382015-01-30 12:22:28 -080081 {0, "chromiumos disk"}, /* FILE_TYPE_CHROMIUMOS_DISK */
Bill Richardson4805f182015-01-30 22:21:10 -080082 {CB_PRIVKEY, "VbPrivateKey"}, /* FILE_TYPE_PRIVKEY */
Bill Richardsoncf6e78d2014-08-27 15:50:25 -070083};
84BUILD_ASSERT(ARRAY_SIZE(direct_callback) == NUM_FILE_TYPES);
85
86/*
87 * The Chrome OS BIOS must contain specific FMAP areas, and we generally want
88 * to look at each one in a certain order.
89 */
90struct bios_area_s {
91 const char * const name;
92 enum futil_cb_component component;
93};
94
95/* This are the expected areas, in order of traversal. */
96static const struct bios_area_s bios_area[] = {
97 {"GBB", CB_FMAP_GBB},
98 {"FW_MAIN_A", CB_FMAP_FW_MAIN_A},
99 {"FW_MAIN_B", CB_FMAP_FW_MAIN_B},
100 {"VBLOCK_A", CB_FMAP_VBLOCK_A},
101 {"VBLOCK_B", CB_FMAP_VBLOCK_B},
102 {0, 0}
103};
104
105/* Really old BIOS images had different names, but worked the same. */
106static const struct bios_area_s old_bios_area[] = {
107 {"GBB Area", CB_FMAP_GBB},
108 {"Firmware A Data", CB_FMAP_FW_MAIN_A},
109 {"Firmware B Data", CB_FMAP_FW_MAIN_B},
110 {"Firmware A Key", CB_FMAP_VBLOCK_A},
111 {"Firmware B Key", CB_FMAP_VBLOCK_B},
112 {0, 0}
113};
114
115static int has_all_areas(uint8_t *buf, uint32_t len, FmapHeader *fmap,
116 const struct bios_area_s *area)
117{
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700118 /* We must have all the expected areas */
119 for (; area->name; area++)
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700120 if (!fmap_find_by_name(buf, len, fmap, area->name, 0))
121 return 0;
122
123 /* Found 'em all */
124 return 1;
125}
126
Bill Richardson25593382015-01-30 12:22:28 -0800127enum futil_file_type recognize_bios_image(uint8_t *buf, uint32_t len)
128{
129 FmapHeader *fmap = fmap_find(buf, len);
130 if (fmap) {
131 if (has_all_areas(buf, len, fmap, bios_area))
132 return FILE_TYPE_BIOS_IMAGE;
133 if (has_all_areas(buf, len, fmap, old_bios_area))
134 return FILE_TYPE_OLD_BIOS_IMAGE;
135 }
136 return FILE_TYPE_UNKNOWN;
137}
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700138
Bill Richardson7ccd9ce2015-01-30 23:45:49 -0800139static const char * const futil_cb_component_str[] = {
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700140 "CB_BEGIN_TRAVERSAL",
141 "CB_END_TRAVERSAL",
142 "CB_FMAP_GBB",
143 "CB_FMAP_VBLOCK_A",
144 "CB_FMAP_VBLOCK_B",
145 "CB_FMAP_FW_MAIN_A",
146 "CB_FMAP_FW_MAIN_B",
147 "CB_PUBKEY",
148 "CB_KEYBLOCK",
149 "CB_GBB",
150 "CB_FW_PREAMBLE",
151 "CB_KERN_PREAMBLE",
152 "CB_RAW_FIRMWARE",
153 "CB_RAW_KERNEL",
Bill Richardson4805f182015-01-30 22:21:10 -0800154 "CB_PRIVKEY",
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700155};
156BUILD_ASSERT(ARRAY_SIZE(futil_cb_component_str) == NUM_CB_COMPONENTS);
157
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700158static int invoke_callback(struct futil_traverse_state_s *state,
159 enum futil_cb_component c, const char *name,
160 uint32_t offset, uint8_t *buf, uint32_t len)
161{
162 Debug("%s: name \"%s\" op %d component %s"
163 " offset=0x%08x len=0x%08x, buf=%p\n",
164 __func__, name, state->op, futil_cb_component_str[c],
165 offset, len, buf);
166
David Riley05987b12015-02-05 19:22:49 -0800167 if ((int) c < 0 || c >= NUM_CB_COMPONENTS) {
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700168 fprintf(stderr, "Invalid component %d\n", c);
169 return 1;
170 }
171
172 state->component = c;
173 state->name = name;
174 state->cb_area[c].offset = offset;
175 state->cb_area[c].buf = buf;
176 state->cb_area[c].len = len;
177 state->my_area = &state->cb_area[c];
178
179 if (cb_func[state->op][c])
180 return cb_func[state->op][c](state);
Bill Richardson6f72ffa2014-09-23 14:40:20 -0700181
182 return 0;
183}
184
Bill Richardson7ccd9ce2015-01-30 23:45:49 -0800185static void fmap_limit_area(FmapAreaHeader *ah, uint32_t len)
186{
187 uint32_t sum = ah->area_offset + ah->area_size;
188 if (sum < ah->area_size || sum > len) {
189 Debug("%s(%s) 0x%x + 0x%x > 0x%x\n",
190 __func__, ah->area_name,
191 ah->area_offset, ah->area_size, len);
192 ah->area_offset = 0;
193 ah->area_size = 0;
194 }
195}
196
Bill Richardsonb0f1cc52014-09-24 00:23:56 -0700197int futil_traverse(uint8_t *buf, uint32_t len,
198 struct futil_traverse_state_s *state,
199 enum futil_file_type type)
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700200{
201 FmapHeader *fmap;
202 FmapAreaHeader *ah = 0;
203 const struct bios_area_s *area;
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700204 int retval = 0;
205
David Riley05987b12015-02-05 19:22:49 -0800206 if ((int) state->op < 0 || state->op >= NUM_FUTIL_OPS) {
Bill Richardsonb0f1cc52014-09-24 00:23:56 -0700207 fprintf(stderr, "Invalid op %d\n", state->op);
208 return 1;
209 }
210
211 if (type == FILE_TYPE_UNKNOWN)
Bill Richardson25593382015-01-30 12:22:28 -0800212 type = futil_file_type_buf(buf, len);
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700213 state->in_type = type;
214
215 state->errors = retval;
216 retval |= invoke_callback(state, CB_BEGIN_TRAVERSAL, "<begin>",
217 0, buf, len);
218 state->errors = retval;
219
220 switch (type) {
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700221 case FILE_TYPE_BIOS_IMAGE:
222 /* We've already checked, so we know this will work. */
223 fmap = fmap_find(buf, len);
224 for (area = bios_area; area->name; area++) {
225 /* We know this will work, too */
226 fmap_find_by_name(buf, len, fmap, area->name, &ah);
Bill Richardson7ccd9ce2015-01-30 23:45:49 -0800227 /* But the file might be truncated */
228 fmap_limit_area(ah, len);
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700229 retval |= invoke_callback(state,
230 area->component,
231 area->name,
232 ah->area_offset,
233 buf + ah->area_offset,
234 ah->area_size);
235 state->errors = retval;
236 }
237 break;
238
239 case FILE_TYPE_OLD_BIOS_IMAGE:
240 /* We've already checked, so we know this will work. */
241 fmap = fmap_find(buf, len);
242 for (area = old_bios_area; area->name; area++) {
243 /* We know this will work, too */
244 fmap_find_by_name(buf, len, fmap, area->name, &ah);
Bill Richardson7ccd9ce2015-01-30 23:45:49 -0800245 /* But the file might be truncated */
246 fmap_limit_area(ah, len);
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700247 retval |= invoke_callback(state,
248 area->component,
249 area->name,
250 ah->area_offset,
251 buf + ah->area_offset,
252 ah->area_size);
253 state->errors = retval;
254 }
255 break;
256
Bill Richardson7ccd9ce2015-01-30 23:45:49 -0800257 case FILE_TYPE_UNKNOWN:
258 case FILE_TYPE_CHROMIUMOS_DISK:
259 /* Nothing to do for these file types (yet) */
260 break;
261
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700262 default:
Bill Richardson7ccd9ce2015-01-30 23:45:49 -0800263 /* All other file types have their own callbacks */
Bill Richardson25593382015-01-30 12:22:28 -0800264 retval |= invoke_callback(state,
265 direct_callback[type].component,
266 direct_callback[type].name,
267 0, buf, len);
268 state->errors = retval;
269 break;
Bill Richardsoncf6e78d2014-08-27 15:50:25 -0700270 }
271
272 retval |= invoke_callback(state, CB_END_TRAVERSAL, "<end>",
273 0, buf, len);
274 return retval;
275}