xref: /aosp_15_r20/external/vboot_reference/futility/updater_manifest.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2022 The ChromiumOS Authors
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * Build up the list of updater resources from an archive.
6  */
7 
8 #include <assert.h>
9 #if defined(__OpenBSD__)
10 #include <sys/types.h>
11 #endif
12 
13 #include "updater.h"
14 #include "util_misc.h"
15 
16 /*
17  * The updater reads image files from a package. The package is usually an
18  * archive (see updater_archive.c) with image files and configuration files, and
19  * the meta data is maintained by a "manifest" that described below.
20  *
21  * A package for a single board (i.e., not Unified Build) will have all the
22  * image files in the top folder:
23  *  - host: 'image.bin'
24  *  - ec: 'ec.bin'
25  *
26  * A package for Unified Build is more complicated.
27  *
28  * You need to look at the signer_config.csv file to find the columns of
29  * model_name, image files (firmware_image, ec_image) and then search for
30  * patch files (root key, vblock files, GSC verification data, ...) in the
31  * keyset/ folder:
32  *
33  *  - rootkey.$MODEL_NAME
34  *  - vblock_A.$MODEL_NAME
35  *  - vblock_B.$MODEL_NAME
36  *  - gscvd.$MODEL_NAME
37  *
38  * In the runtime, the updater should query for firmware manifest key (
39  * `crosid -f FIRMWARE_MANIFEST_KEY`) and use that to match the 'model_name'
40  * in the manifest database.
41  *
42  * If the model_name in `signer_config.csv` contains '-' then it is a custom
43  * label device. Today the FIRMWARE_MANIFEST_KEY from crosid won't handle custom
44  * label information and we have to add the custom label tag in the matching
45  * process.
46  *
47  * To do that, find the custom label tag from the VPD.
48  * - Newer devices: model_name = FIRMWARE_MANIFEST_KEY-$custom_label_tag
49  * - Old devices: model_name = FIRMWARE_MANIFEST_KEY-$whitelabel_tag
50  *
51  * For legacy devices manufactured before Unified Build, they have the VPD
52  * 'customization_id' in a special format: LOEM[-VARIANT].
53  * For example: "A-B" => LOEM="A".
54  * - Legacy devices: model_name = FIRMWARE_MANIFEST_KEY-$LOEM
55  */
56 
57 static const char * const DEFAULT_MODEL_NAME = "default",
58 		  * const VPD_CUSTOM_LABEL_TAG = "custom_label_tag",
59 		  * const VPD_CUSTOM_LABEL_TAG_LEGACY = "whitelabel_tag",
60 		  * const VPD_CUSTOMIZATION_ID = "customization_id",
61 		  * const PATH_KEYSET_FOLDER = "keyset/",
62 		  * const PATH_SIGNER_CONFIG = "signer_config.csv";
63 
64 /* Utility function to convert a string. */
str_convert(char * s,int (* convert)(int c))65 static void str_convert(char *s, int (*convert)(int c))
66 {
67 	int c;
68 
69 	for (; *s; s++) {
70 		c = *s;
71 		if (!isascii(c))
72 			continue;
73 		*s = convert(c);
74 	}
75 }
76 
77 /* Returns the VPD value by given key name, or NULL on error (or no value). */
vpd_get_value(const char * fpath,const char * key)78 static char *vpd_get_value(const char *fpath, const char *key)
79 {
80 	char *command, *result;
81 
82 	assert(fpath);
83 	ASPRINTF(&command, "vpd -g %s -f %s 2>/dev/null", key, fpath);
84 	result = host_shell(command);
85 	free(command);
86 
87 	if (result && !*result) {
88 		free(result);
89 		result = NULL;
90 	}
91 	return result;
92 }
93 
94 /*
95  * Changes the rootkey in firmware GBB to given new key.
96  * Returns 0 on success, otherwise failure.
97  */
change_gbb_rootkey(struct firmware_image * image,const char * section_name,const uint8_t * rootkey,uint32_t rootkey_len)98 static int change_gbb_rootkey(struct firmware_image *image,
99 			      const char *section_name,
100 			      const uint8_t *rootkey, uint32_t rootkey_len)
101 {
102 	const struct vb2_gbb_header *gbb = find_gbb(image);
103 	uint8_t *gbb_rootkey;
104 	if (!gbb) {
105 		ERROR("Cannot find GBB in image %s.\n", image->file_name);
106 		return -1;
107 	}
108 	if (gbb->rootkey_size < rootkey_len) {
109 		ERROR("New root key (%u bytes) larger than GBB (%u bytes).\n",
110 		      rootkey_len, gbb->rootkey_size);
111 		return -1;
112 	}
113 
114 	gbb_rootkey = (uint8_t *)gbb + gbb->rootkey_offset;
115 	/* See cmd_gbb_utility: root key must be first cleared with zero. */
116 	memset(gbb_rootkey, 0, gbb->rootkey_size);
117 	memcpy(gbb_rootkey, rootkey, rootkey_len);
118 	return 0;
119 }
120 
121 /*
122  * Changes the firmware section (for example vblock or GSCVD) to new data.
123  * Returns 0 on success, otherwise failure.
124  */
change_section(struct firmware_image * image,const char * section_name,const uint8_t * data,uint32_t data_len)125 static int change_section(struct firmware_image *image,
126 			  const char *section_name,
127 			  const uint8_t *data, uint32_t data_len)
128 {
129 	struct firmware_section section;
130 
131 	find_firmware_section(&section, image, section_name);
132 	if (!section.data) {
133 		ERROR("Need section %s in image %s.\n", section_name,
134 		      image->file_name);
135 		return -1;
136 	}
137 	if (section.size < data_len) {
138 		ERROR("'%s' is too small (%zu bytes) for patching %u bytes.\n",
139 		      section_name, section.size, data_len);
140 		return -1;
141 	}
142 	/* First erase (0xff) the section in case the new data is smaller. */
143 	memset(section.data, 0xff, section.size);
144 	memcpy(section.data, data, data_len);
145 	return 0;
146 }
147 
148 /*
149  * Applies a key file to firmware image.
150  * Returns 0 on success, otherwise failure.
151  */
apply_key_file(struct firmware_image * image,const char * path,struct u_archive * archive,const char * section_name,int (* apply)(struct firmware_image * image,const char * section,const uint8_t * data,uint32_t len))152 static int apply_key_file(
153 		struct firmware_image *image, const char *path,
154 		struct u_archive *archive, const char *section_name,
155 		int (*apply)(struct firmware_image *image, const char *section,
156 			     const uint8_t *data, uint32_t len))
157 {
158 	int r = 0;
159 	uint8_t *data = NULL;
160 	uint32_t len;
161 
162 	r = archive_read_file(archive, path, &data, &len, NULL);
163 	if (r == 0) {
164 		VB2_DEBUG("Loaded file: %s\n", path);
165 		r = apply(image, section_name, data, len);
166 		if (r)
167 			ERROR("Failed applying %s to %s\n", path, section_name);
168 	} else {
169 		ERROR("Failed reading: %s\n", path);
170 	}
171 	free(data);
172 	return r;
173 }
174 
175 /*
176  * Modifies a firmware image from patch information specified in model config.
177  * Returns 0 on success, otherwise number of failures.
178  */
patch_image_by_model(struct firmware_image * image,const struct model_config * model,struct u_archive * archive)179 int patch_image_by_model(
180 		struct firmware_image *image, const struct model_config *model,
181 		struct u_archive *archive)
182 {
183 	int err = 0;
184 	if (model->patches.rootkey)
185 		err += !!apply_key_file(
186 				image, model->patches.rootkey, archive,
187 				FMAP_RO_GBB, change_gbb_rootkey);
188 	if (model->patches.vblock_a)
189 		err += !!apply_key_file(
190 				image, model->patches.vblock_a, archive,
191 				FMAP_RW_VBLOCK_A, change_section);
192 	if (model->patches.vblock_b)
193 		err += !!apply_key_file(
194 				image, model->patches.vblock_b, archive,
195 				FMAP_RW_VBLOCK_B, change_section);
196 	if (model->patches.gscvd)
197 		err += !!apply_key_file(
198 				image, model->patches.gscvd, archive,
199 				FMAP_RO_GSCVD, change_section);
200 	return err;
201 }
202 
203 /*
204  * Finds available patch files by given model.
205  * Updates `model` argument with path of patch files.
206  */
find_patches_for_model(struct model_config * model,struct u_archive * archive)207 static void find_patches_for_model(struct model_config *model,
208 				   struct u_archive *archive)
209 {
210 	char *path;
211 	int i;
212 
213 	const char * const names[] = {
214 		"rootkey",
215 		"vblock_A",
216 		"vblock_B",
217 		"gscvd",
218 	};
219 
220 	char **targets[] = {
221 		&model->patches.rootkey,
222 		&model->patches.vblock_a,
223 		&model->patches.vblock_b,
224 		&model->patches.gscvd,
225 	};
226 
227 	assert(ARRAY_SIZE(names) == ARRAY_SIZE(targets));
228 	for (i = 0; i < ARRAY_SIZE(names); i++) {
229 		ASPRINTF(&path, "%s%s.%s", PATH_KEYSET_FOLDER, names[i], model->name);
230 		if (archive_has_entry(archive, path))
231 			*targets[i] = path;
232 		else
233 			free(path);
234 	}
235 }
236 
237 /*
238  * Adds and copies one new model config to the existing list of given manifest.
239  * Returns a pointer to the newly allocated config, or NULL on failure.
240  */
manifest_add_model(struct manifest * manifest,const struct model_config * cfg)241 static struct model_config *manifest_add_model(
242 		struct manifest *manifest,
243 		const struct model_config *cfg)
244 {
245 	struct model_config *model;
246 	manifest->num++;
247 	manifest->models = (struct model_config *)realloc(
248 			manifest->models, manifest->num * sizeof(*model));
249 	if (!manifest->models) {
250 		ERROR("Internal error: failed to allocate buffer.\n");
251 		return NULL;
252 	}
253 	model = &manifest->models[manifest->num - 1];
254 	memcpy(model, cfg, sizeof(*model));
255 	return model;
256 }
257 
258 /*
259  * A callback function for manifest to scan files in raw /firmware archive.
260  * Returns 0 to keep scanning, or non-zero to stop.
261  */
manifest_scan_raw_entries(const char * name,void * arg)262 static int manifest_scan_raw_entries(const char *name, void *arg)
263 {
264 	struct manifest *manifest = (struct manifest *)arg;
265 	struct u_archive *archive = manifest->archive;
266 	struct model_config model = {0};
267 	char *ec_name = NULL;
268 	int chars_read = 0;
269 
270 	/*
271 	 * /build/$BOARD/firmware (or CPFE firmware archives) layout:
272 	 * - image-${MODEL}{,.serial,.dev...}.bin
273 	 * - ${MODEL}/ec.bin
274 	 */
275 
276 	if (sscanf(name, "image-%m[^.].bin%n", &model.name, &chars_read) != 1)
277 		return 0;
278 
279 	/* Ignore the names with extra modifiers like image-$MODEL.serial.bin */
280 	if (!chars_read || name[chars_read]) {
281 		free(model.name);
282 		return 0;
283 	}
284 
285 	VB2_DEBUG("Found model <%s>: %s\n", model.name, name);
286 	model.image = strdup(name);
287 
288 	ASPRINTF(&ec_name, "%s/ec.bin", model.name);
289 	if (archive_has_entry(archive, ec_name))
290 		model.ec_image = strdup(ec_name);
291 	free(ec_name);
292 
293 	return !manifest_add_model(manifest, &model);
294 }
295 
296 /* Returns the matched model config from the manifest, or NULL if not found. */
manifest_get_model_config(const struct manifest * manifest,const char * name)297 static struct model_config *manifest_get_model_config(
298 		const struct manifest *manifest, const char *name)
299 {
300 	int i = 0;
301 
302 	for (i = 0; i < manifest->num; i++) {
303 		if (!strcmp(name, manifest->models[i].name))
304 			return &manifest->models[i];
305 	}
306 	return NULL;
307 }
308 
309 /* Releases (and zeros) the data inside a patch config. */
clear_patch_config(struct patch_config * patch)310 static void clear_patch_config(struct patch_config *patch)
311 {
312 	free(patch->rootkey);
313 	free(patch->vblock_a);
314 	free(patch->vblock_b);
315 	free(patch->gscvd);
316 	memset(patch, 0, sizeof(*patch));
317 }
318 
319 /*
320  * Creates the manifest from the 'signer_config.csv' file.
321  * Returns 0 on success (loaded), otherwise failure.
322  */
manifest_from_signer_config(struct manifest * manifest)323 static int manifest_from_signer_config(struct manifest *manifest)
324 {
325 	struct u_archive *archive = manifest->archive;
326 	uint32_t size;
327 	uint8_t *data;
328 	char *s, *tok_ptr = NULL;
329 
330 	VB2_DEBUG("Try to build the manifest from %s\n", PATH_SIGNER_CONFIG);
331 
332 	if (!archive_has_entry(archive, PATH_SIGNER_CONFIG))
333 		return -1;
334 
335 	/*
336 	 * CSV format: model_name,firmware_image,key_id,ec_image
337 	 *
338 	 * Note the key_id is for signer and won't be used by the updater,
339 	 * and ec_image may be optional (for example sarien).
340 	 */
341 
342 	if (archive_read_file(archive, PATH_SIGNER_CONFIG, &data, &size,NULL)) {
343 		ERROR("Failed reading: %s\n", PATH_SIGNER_CONFIG);
344 		return -1;
345 	}
346 
347 	/* Skip headers. */
348 	s = strtok_r((char *)data, "\n", &tok_ptr);
349 	if (!s || !strchr(s, ',')) {
350 		ERROR("Invalid %s: missing header.\n", PATH_SIGNER_CONFIG);
351 		free(data);
352 		return -1;
353 	}
354 
355 	for (s = strtok_r(NULL, "\n", &tok_ptr); s != NULL;
356 	     s = strtok_r(NULL, "\n", &tok_ptr)) {
357 
358 		struct model_config model = {0};
359 
360 		/*
361 		 * Both keyid (%3) and ec_image (%4) are optional so we want to
362 		 * read at least 2 fields.
363 		 */
364 		if (sscanf(s, "%m[^,],%m[^,],%*[^,],%m[^,]",
365 		    &model.name, &model.image, &model.ec_image) < 2) {
366 			ERROR("Invalid entry(%s): %s\n", PATH_SIGNER_CONFIG, s);
367 			free(model.name);
368 			free(model.image);
369 			free(model.ec_image);
370 			continue;
371 		}
372 
373 		if (strchr(model.name, '-')) {
374 			/* format: BaseModelName-CustomLabelTag */
375 			struct model_config *base_model;
376 			char *tok_dash;
377 			char *base_name = strdup(model.name);
378 
379 			VB2_DEBUG("Found custom-label: %s\n", model.name);
380 			base_name = strtok_r(base_name, "-", &tok_dash);
381 			assert(base_name);
382 
383 			/*
384 			 * Currently we assume the base model (e.g., base_name)
385 			 * is always listed before CL models in the CSV file -
386 			 * this is based on how the signerbot and the
387 			 * chromeos-config works today (validated on octopus).
388 			 */
389 			base_model = manifest_get_model_config(manifest, base_name);
390 
391 			if (!base_model) {
392 				ERROR("Invalid base model for custom label: %s\n", base_name);
393 			} else if (!base_model->has_custom_label) {
394 				base_model->has_custom_label = true;
395 			}
396 
397 			free(base_name);
398 		}
399 
400 		/* Find patch files. */
401 		find_patches_for_model(&model, archive);
402 
403 		if (!manifest_add_model(manifest, &model))
404 			break;
405 	}
406 	free(data);
407 	return 0;
408 }
409 
410 /*
411  * Creates the manifest from a simple (legacy) folder with only 1 set of
412  * firmware images.
413  * Returns 0 on success (loaded), otherwise failure.
414  */
manifest_from_simple_folder(struct manifest * manifest)415 static int manifest_from_simple_folder(struct manifest *manifest)
416 {
417 	const char * const host_image_name = "image.bin",
418 		   * const old_host_image_name = "bios.bin",
419 		   * const ec_name = "ec.bin";
420 	struct u_archive *archive = manifest->archive;
421 	const char *image_name = NULL;
422 	struct firmware_image image = {0};
423 	struct model_config model = {0};
424 
425 	VB2_DEBUG("Try to build the manifest from a simple folder\n");
426 
427 	/* Try to load from current folder. */
428 	if (archive_has_entry(archive, old_host_image_name))
429 		image_name = old_host_image_name;
430 	else if (archive_has_entry(archive, host_image_name))
431 		image_name = host_image_name;
432 	else
433 		return 1;
434 
435 	model.image = strdup(image_name);
436 	if (archive_has_entry(archive, ec_name))
437 		model.ec_image = strdup(ec_name);
438 	/* Extract model name from FWID: $Vendor_$Platform.$Version */
439 	if (!load_firmware_image(&image, image_name, archive)) {
440 		char *token = NULL;
441 		if (strtok(image.ro_version, "_"))
442 			token = strtok(NULL, ".");
443 		if (token && *token) {
444 			str_convert(token, tolower);
445 			model.name = strdup(token);
446 		}
447 		free_firmware_image(&image);
448 	}
449 	if (!model.name)
450 		model.name = strdup(DEFAULT_MODEL_NAME);
451 	manifest_add_model(manifest, &model);
452 	manifest->default_model = manifest->num - 1;
453 
454 	return 0;
455 }
456 
457 /*
458  * Finds the existing model_config from manifest that best matches current
459  * system (as defined by model_name).
460  * Returns a model_config from manifest, or NULL if not found.
461  */
manifest_find_model(struct updater_config * cfg,const struct manifest * manifest,const char * model_name)462 const struct model_config *manifest_find_model(struct updater_config *cfg,
463 					       const struct manifest *manifest,
464 					       const char *model_name)
465 {
466 	char *manifest_key = NULL;
467 	const struct model_config *model = NULL;
468 	int i;
469 	int matched_index;
470 
471 	/*
472 	 * For manifest with single model defined, we should just return because
473 	 * there are other mechanisms like platform name check to double confirm
474 	 * if the firmware is valid.
475 	 */
476 	if (manifest->num == 1)
477 		return &manifest->models[0];
478 
479 	if (!model_name) {
480 		matched_index = dut_get_manifest_key(&manifest_key, cfg);
481 		if (matched_index < 0) {
482 			ERROR("Failed to get device identity.  "
483 			      "Run \"crosid -v\" for explanation.\n");
484 			return NULL;
485 		}
486 
487 		INFO("Identified the device using libcrosid, "
488 		     "matched chromeos-config index: %d, "
489 		     "manifest key (model): %s\n",
490 		     matched_index, manifest_key);
491 		model_name = manifest_key;
492 	}
493 
494 	model = manifest_get_model_config(manifest, model_name);
495 
496 	if (!model) {
497 		ERROR("Unsupported model: '%s'.\n", model_name);
498 
499 		fprintf(stderr,
500 			"The firmware manifest key '%s' is not present in this "
501 			"updater archive. The known keys to this updater "
502 			"archive are:\n", model_name);
503 
504 		for (i = 0; i < manifest->num; i++)
505 			fprintf(stderr, " %s", manifest->models[i].name);
506 		fprintf(stderr, "\n\n");
507 		fprintf(stderr,
508 			"Perhaps you are trying to use an updater archive for "
509 			"the wrong board, or designed for an older OS version "
510 			"before this model was supported.\n");
511 		fprintf(stderr,
512 			"Hint: Read the FIRMWARE_MANIFEST_KEY from the output "
513 			"of the crosid command.\n");
514 	}
515 
516 
517 	free(manifest_key);
518 	return model;
519 }
520 
521 const struct model_config *
manifest_detect_model_from_frid(struct updater_config * cfg,struct manifest * manifest)522 manifest_detect_model_from_frid(struct updater_config *cfg,
523 				struct manifest *manifest)
524 {
525 	const struct model_config *result = NULL;
526 	struct firmware_image current_ro_frid = {0};
527 	current_ro_frid.programmer = cfg->image_current.programmer;
528 	int error = flashrom_read_region(&current_ro_frid, FMAP_RO_FRID,
529 					 cfg->verbosity + 1);
530 	const char *from_dot;
531 	int len;
532 
533 	if (error)
534 		return NULL;
535 
536 	current_ro_frid.data[current_ro_frid.size - 1] = '\0';
537 	from_dot = strchr((const char *)current_ro_frid.data, '.');
538 	if (!from_dot) {
539 		VB2_DEBUG("Missing dot (%s)\n",
540 			  (const char *)current_ro_frid.data);
541 		goto cleanup;
542 	}
543 	len = from_dot - (const char *)current_ro_frid.data + 1;
544 
545 	for (int i = 0; i < manifest->num && !result; ++i) {
546 		struct model_config *m = &manifest->models[i];
547 		struct firmware_image image = {0};
548 
549 		if (load_firmware_image(&image, m->image, manifest->archive))
550 			return NULL;
551 
552 		VB2_DEBUG("Comparing '%*.*s' with '%*.*s'\n", len, len,
553 			  (const char *)current_ro_frid.data, len, len,
554 			  image.ro_version);
555 		if (strncasecmp((const char *)current_ro_frid.data,
556 				image.ro_version, len) == 0) {
557 			result = m;
558 		}
559 		free_firmware_image(&image);
560 	}
561 	if (result) {
562 		INFO("Detected model: '%s'\n", result->name);
563 	} else {
564 		ERROR("Unsupported FRID: '%*.*s'.\n", len - 1, len - 1,
565 		      (const char *)current_ro_frid.data);
566 	}
567 cleanup:
568 	free_firmware_image(&current_ro_frid);
569 
570 	return result;
571 }
572 
573 /*
574  * Determines the custom label tag.
575  * Returns the tag string, or NULL if not found.
576  * Caller must free the returned string.
577  */
get_custom_label_tag(const char * image_file)578 static char *get_custom_label_tag(const char *image_file)
579 {
580 	/* TODO(hungte) Switch to look at /sys/firmware/vpd/ro/$KEY. */
581 	char *tag;
582 
583 	tag = vpd_get_value(image_file, VPD_CUSTOM_LABEL_TAG);
584 	if (tag)
585 		return tag;
586 
587 	tag = vpd_get_value(image_file, VPD_CUSTOM_LABEL_TAG_LEGACY);
588 	if (tag)
589 		return tag;
590 
591 	tag = vpd_get_value(image_file, VPD_CUSTOMIZATION_ID);
592 	/* VPD_CUSTOMIZATION_ID is complicated and can't be returned directly. */
593 	if (!tag)
594 		return NULL;
595 
596 	/* For VPD_CUSTOMIZATION_ID=LOEM[-VARIANT], we need only capitalized LOEM. */
597 	INFO("Using deprecated custom label tag: %s=%s\n", VPD_CUSTOMIZATION_ID, tag);
598 	char *dash = strchr(tag, '-');
599 	if (dash)
600 		*dash = '\0';
601 	str_convert(tag, toupper);
602 	VB2_DEBUG("Applied tag from %s: %s\n", tag, VPD_CUSTOMIZATION_ID);
603 	return tag;
604 }
605 
manifest_find_custom_label_model(struct updater_config * cfg,const struct manifest * manifest,const struct model_config * base_model)606 const struct model_config *manifest_find_custom_label_model(
607 		struct updater_config *cfg,
608 		const struct manifest *manifest,
609 		const struct model_config *base_model)
610 {
611 	const struct model_config *model;
612 
613 	/*
614 	 * Some custom label devices shipped with wrong key and must change
615 	 * their model names to match the right data.
616 	 */
617 	if (get_config_quirk(QUIRK_OVERRIDE_CUSTOM_LABEL, cfg)) {
618 		model = quirk_override_custom_label(cfg, manifest, base_model);
619 		if (model)
620 			return model;
621 	}
622 
623 	assert(cfg->image_current.data);
624 	const char *tmp_image = get_firmware_image_temp_file(
625 			&cfg->image_current, &cfg->tempfiles);
626 	if (!tmp_image) {
627 		ERROR("Failed to save the system firmware to a file.\n");
628 		return NULL;
629 	}
630 
631 	char *tag = get_custom_label_tag(tmp_image);
632 	if (!tag) {
633 		WARN("No custom label tag (VPD '%s'). "
634 		     "Use default keys from the base model '%s'.\n",
635 		     VPD_CUSTOM_LABEL_TAG, base_model->name);
636 		return base_model;
637 	}
638 
639 	VB2_DEBUG("Found custom label tag: %s (base=%s)\n", tag, base_model->name);
640 	char *name;
641 	ASPRINTF(&name, "%s-%s", base_model->name, tag);
642 	free(tag);
643 
644 	INFO("Find custom label model info using '%s'...\n", name);
645 	model = manifest_find_model(cfg, manifest, name);
646 
647 	if (model) {
648 		INFO("Applied custom label model: %s\n", name);
649 	} else {
650 		ERROR("Invalid custom label model: %s\n", name);
651 	}
652 	free(name);
653 	return model;
654 }
655 
manifest_from_build_artifacts(struct manifest * manifest)656 static int manifest_from_build_artifacts(struct manifest *manifest) {
657 	VB2_DEBUG("Try to build the manifest from a */firmware folder\n");
658 	return archive_walk(manifest->archive, manifest, manifest_scan_raw_entries);
659 }
660 
661 /*
662  * Creates a new manifest object by scanning files in archive.
663  * Returns the manifest on success, otherwise NULL for failure.
664  */
new_manifest_from_archive(struct u_archive * archive)665 struct manifest *new_manifest_from_archive(struct u_archive *archive)
666 {
667 	int i;
668 	struct manifest manifest = {0}, *new_manifest;
669 	int (*manifest_builders[])(struct manifest *) = {
670 		manifest_from_signer_config,
671 		manifest_from_build_artifacts,
672 		manifest_from_simple_folder,
673 	};
674 
675 	manifest.archive = archive;
676 	manifest.default_model = -1;
677 
678 	for (i = 0; !manifest.num && i < ARRAY_SIZE(manifest_builders); i++) {
679 		/*
680 		 * For archives manually updated (for testing), it is possible a
681 		 * builder can successfully scan the archive but no valid models
682 		 * were found, so here we don't need to check the return value.
683 		 * Only stop when manifest.num is non-zero.
684 		 */
685 		(void) manifest_builders[i](&manifest);
686 	}
687 
688 	VB2_DEBUG("%d model(s) loaded.\n", manifest.num);
689 	if (!manifest.num) {
690 		ERROR("No valid configurations found from the archive.\n");
691 		return NULL;
692 	}
693 
694 	new_manifest = (struct manifest *)malloc(sizeof(manifest));
695 	if (!new_manifest) {
696 		ERROR("Internal error: memory allocation error.\n");
697 		return NULL;
698 	}
699 	memcpy(new_manifest, &manifest, sizeof(manifest));
700 	return new_manifest;
701 }
702 
703 /* Releases all resources allocated by given manifest object. */
delete_manifest(struct manifest * manifest)704 void delete_manifest(struct manifest *manifest)
705 {
706 	int i;
707 	assert(manifest);
708 	for (i = 0; i < manifest->num; i++) {
709 		struct model_config *model = &manifest->models[i];
710 		free(model->name);
711 		free(model->image);
712 		free(model->ec_image);
713 		clear_patch_config(&model->patches);
714 	}
715 	free(manifest->models);
716 	free(manifest);
717 }
718 
get_gbb_key_hash(const struct vb2_gbb_header * gbb,int32_t offset,int32_t size)719 static const char *get_gbb_key_hash(const struct vb2_gbb_header *gbb,
720 				    int32_t offset, int32_t size)
721 {
722 	struct vb2_packed_key *key;
723 
724 	if (!gbb)
725 		return "<No GBB>";
726 	key = (struct vb2_packed_key *)((uint8_t *)gbb + offset);
727 	if (vb2_packed_key_looks_ok(key, size))
728 		return "<Invalid key>";
729 	return packed_key_sha1_string(key);
730 }
731 
732 /* Prints the information of given image file in JSON format. */
print_json_image(const char * name,const char * fpath,struct model_config * m,struct u_archive * archive,int indent,int is_host,bool is_first)733 static void print_json_image(
734 		const char *name, const char *fpath, struct model_config *m,
735 		struct u_archive *archive, int indent, int is_host,
736 		bool is_first)
737 {
738 	struct firmware_image image = {0};
739 	const struct vb2_gbb_header *gbb = NULL;
740 	if (!fpath)
741 		return;
742 	if (load_firmware_image(&image, fpath, archive))
743 		return;
744 	if (!is_first)
745 		printf(",\n");
746 	printf("%*s\"%s\": {", indent, "", name);
747 	indent += 2;
748 	printf("\n%*s\"versions\": {", indent, "");
749 	indent += 2;
750 	printf("\n%*s\"ro\": \"%s\"", indent, "", image.ro_version);
751 	printf(",\n%*s\"rw\": \"%s\"", indent, "", image.rw_version_a);
752 	if (is_host && image.ecrw_version_a[0] != '\0')
753 		printf(",\n%*s\"ecrw\": \"%s\"", indent, "",
754 		       image.ecrw_version_a);
755 	indent -= 2;
756 	printf("\n%*s},", indent, "");
757 	if (is_host) {
758 		if (patch_image_by_model(&image, m, archive))
759 			ERROR("Failed to patch images by model: %s\n", m->name);
760 		else
761 			gbb = find_gbb(&image);
762 	}
763 	if (gbb != NULL) {
764 		printf("\n%*s\"keys\": { \"root\": \"%s\", ",
765 		       indent, "",
766 		       get_gbb_key_hash(gbb, gbb->rootkey_offset,
767 					gbb->rootkey_size));
768 		printf("\"recovery\": \"%s\" },",
769 		       get_gbb_key_hash(gbb, gbb->recovery_key_offset,
770 					gbb->recovery_key_size));
771 	}
772 	printf("\n%*s\"image\": \"%s\"", indent, "", fpath);
773 	indent -= 2;
774 	printf("\n%*s}", indent, "");
775 	check_firmware_versions(&image);
776 	free_firmware_image(&image);
777 }
778 
779 /* Prints the information of objects in manifest (models and images) in JSON. */
print_json_manifest(const struct manifest * manifest)780 void print_json_manifest(const struct manifest *manifest)
781 {
782 	int i, j, indent;
783 	struct u_archive *ar = manifest->archive;
784 
785 	printf("{\n");
786 	for (i = 0, indent = 2; i < manifest->num; i++) {
787 		struct model_config *m = &manifest->models[i];
788 		struct {
789 			const char *name;
790 			const char *fpath;
791 			bool is_host;
792 		} images[] = {
793 			{"host", m->image, true},
794 			{"ec", m->ec_image},
795 		};
796 		bool is_first = true;
797 		printf("%s%*s\"%s\": {\n", i ? ",\n" : "", indent, "", m->name);
798 		indent += 2;
799 		for (j = 0; j < ARRAY_SIZE(images); j++) {
800 			if (!images[j].fpath)
801 				continue;
802 			print_json_image(images[j].name, images[j].fpath, m, ar,
803 					 indent, images[j].is_host, is_first);
804 			is_first = false;
805 		}
806 		if (m->patches.rootkey) {
807 			struct patch_config *p = &m->patches;
808 			printf(",\n%*s\"patches\": { \"rootkey\": \"%s\", "
809 			       "\"vblock_a\": \"%s\", \"vblock_b\": \"%s\"",
810 			       indent, "", p->rootkey, p->vblock_a,
811 			       p->vblock_b);
812 			if (p->gscvd)
813 				printf(", \"gscvd\": \"%s\"", p->gscvd);
814 			printf(" }");
815 		}
816 		printf("\n  }");
817 		indent -= 2;
818 		assert(indent == 2);
819 	}
820 	printf("\n}\n");
821 }
822