1 /* Copyright 2019 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 * The utility functions for firmware updater.
6 */
7
8 #include <assert.h>
9 #include <limits.h>
10 #include <stdbool.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <string.h>
14 #include <unistd.h>
15 #if defined (__FreeBSD__) || defined(__OpenBSD__)
16 #include <sys/wait.h>
17 #endif
18
19 #include "2common.h"
20 #include "cbfstool.h"
21 #include "host_misc.h"
22 #include "util_misc.h"
23 #include "updater.h"
24
25 #define COMMAND_BUFFER_SIZE 256
26
strip_string(char * s,const char * pattern)27 void strip_string(char *s, const char *pattern)
28 {
29 int len;
30 assert(s);
31
32 len = strlen(s);
33 while (len-- > 0) {
34 if (pattern) {
35 if (!strchr(pattern, s[len]))
36 break;
37 } else {
38 if (!isascii(s[len]) || !isspace(s[len]))
39 break;
40 }
41 s[len] = '\0';
42 }
43 }
44
save_file_from_stdin(const char * output)45 int save_file_from_stdin(const char *output)
46 {
47 FILE *in = stdin, *out = fopen(output, "wb");
48 char buffer[4096];
49 size_t sz;
50
51 assert(in);
52 if (!out)
53 return -1;
54
55 while (!feof(in)) {
56 sz = fread(buffer, 1, sizeof(buffer), in);
57 if (fwrite(buffer, 1, sz, out) != sz) {
58 fclose(out);
59 return -1;
60 }
61 }
62 fclose(out);
63 return 0;
64 }
65
66 /*
67 * Loads the firmware information from an FMAP section in loaded firmware image.
68 * The section should only contain ASCIIZ string as firmware version.
69 * Returns 0 if a non-empty version string is stored in *version, otherwise -1.
70 */
load_firmware_version(struct firmware_image * image,const char * section_name,char ** version)71 static int load_firmware_version(struct firmware_image *image,
72 const char *section_name,
73 char **version)
74 {
75 struct firmware_section fwid;
76 int len = 0;
77
78 /*
79 * section_name is NULL when parsing the RW versions on a non-vboot
80 * image (and already warned in load_firmware_image). We still need to
81 * initialize *version with empty string.
82 */
83 if (section_name) {
84 find_firmware_section(&fwid, image, section_name);
85 if (fwid.size)
86 len = fwid.size;
87 else
88 WARN("No valid section '%s', missing version info.\n",
89 section_name);
90 }
91
92 if (!len) {
93 *version = strdup("");
94 return -1;
95 }
96
97 /*
98 * For 'system current' images, the version string may contain
99 * invalid characters that we do want to strip.
100 */
101 *version = strndup((const char *)fwid.data, len);
102 strip_string(*version, "\xff");
103 return 0;
104 }
105
has_printable_ecrw_version(const struct firmware_image * image)106 static bool has_printable_ecrw_version(const struct firmware_image *image)
107 {
108 /*
109 * Wilco family (sarien & drallion) has binary ecrw version which may
110 * contain non-printable characters. Those images can be identified by
111 * checking if the DIAG_NVRAM FMAP section exists or not.
112 */
113 return !firmware_section_exists(image, FMAP_RW_DIAG_NVRAM);
114 }
115
116 /*
117 * Loads the version of "ecrw" CBFS file within `section_name` of `image_file`.
118 * Returns the version string on success; otherwise an empty string.
119 */
load_ecrw_version(const struct firmware_image * image,const char * image_file,const char * section_name)120 static char *load_ecrw_version(const struct firmware_image *image,
121 const char *image_file,
122 const char *section_name)
123 {
124 char *version = NULL;
125 struct tempfile tempfile_head = {0};
126
127 /* EC image or older AP images may not have the section. */
128 if (!firmware_section_exists(image, section_name))
129 goto done;
130
131 if (!has_printable_ecrw_version(image))
132 goto done;
133
134 const char *ecrw_version_file = create_temp_file(&tempfile_head);
135 if (!ecrw_version_file)
136 goto done;
137
138 /* "ecrw.version" doesn't exist in old images. */
139 const char *ecrw_version_name = "ecrw.version";
140 if (!cbfstool_file_exists(image_file, section_name, ecrw_version_name))
141 goto done;
142
143 if (cbfstool_extract(image_file, section_name, ecrw_version_name,
144 ecrw_version_file)) {
145 ERROR("Failed to extract %s from %s\n",
146 ecrw_version_name, section_name);
147 goto done;
148 }
149
150 uint8_t *data;
151 uint32_t size;
152 if (vb2_read_file(ecrw_version_file, &data, &size) != VB2_SUCCESS)
153 goto done;
154
155 version = strndup((const char *)data, size);
156
157 done:
158 if (!version)
159 version = strdup("");
160 remove_all_temp_files(&tempfile_head);
161 return version;
162 }
163
164 /* Loads the version of "ecrw" CBFS file for FW_MAIN_A and FW_MAIN_B. */
load_ecrw_versions(struct firmware_image * image)165 static void load_ecrw_versions(struct firmware_image *image)
166 {
167 struct tempfile tempfile_head = {0};
168 const char *image_file = get_firmware_image_temp_file(
169 image, &tempfile_head);
170
171 if (image_file) {
172 image->ecrw_version_a = load_ecrw_version(
173 image, image_file, FMAP_RW_FW_MAIN_A);
174 image->ecrw_version_b = load_ecrw_version(
175 image, image_file, FMAP_RW_FW_MAIN_B);
176 }
177
178 remove_all_temp_files(&tempfile_head);
179 }
180
181 /*
182 * Fills in the other fields of image using image->data.
183 * Returns IMAGE_LOAD_SUCCESS or IMAGE_PARSE_FAILURE.
184 */
parse_firmware_image(struct firmware_image * image)185 static int parse_firmware_image(struct firmware_image *image)
186 {
187 int ret = IMAGE_LOAD_SUCCESS;
188 const char *section_a = NULL, *section_b = NULL;
189
190 VB2_DEBUG("Image size: %d\n", image->size);
191 assert(image->data);
192
193 image->fmap_header = fmap_find(image->data, image->size);
194
195 if (!image->fmap_header) {
196 ERROR("Invalid image file (missing FMAP): %s\n", image->file_name);
197 ret = IMAGE_PARSE_FAILURE;
198 }
199
200 if (load_firmware_version(image, FMAP_RO_FRID, &image->ro_version))
201 ret = IMAGE_PARSE_FAILURE;
202
203 if (firmware_section_exists(image, FMAP_RW_FWID_A)) {
204 section_a = FMAP_RW_FWID_A;
205 section_b = FMAP_RW_FWID_B;
206 } else if (firmware_section_exists(image, FMAP_RW_FWID)) {
207 section_a = FMAP_RW_FWID;
208 section_b = FMAP_RW_FWID;
209 } else if (!ret) {
210 ERROR("Unsupported VBoot firmware (no RW ID): %s\n", image->file_name);
211 ret = IMAGE_PARSE_FAILURE;
212 }
213
214 /*
215 * Load and initialize both RW A and B sections.
216 * Note some unit tests will create only RW A.
217 */
218 load_firmware_version(image, section_a, &image->rw_version_a);
219 load_firmware_version(image, section_b, &image->rw_version_b);
220
221 load_ecrw_versions(image);
222
223 return ret;
224 }
225
load_firmware_image(struct firmware_image * image,const char * file_name,struct u_archive * archive)226 int load_firmware_image(struct firmware_image *image, const char *file_name,
227 struct u_archive *archive)
228 {
229 if (!file_name) {
230 ERROR("No file name given\n");
231 return IMAGE_READ_FAILURE;
232 }
233
234 VB2_DEBUG("Load image file from %s...\n", file_name);
235
236 if (!archive_has_entry(archive, file_name)) {
237 ERROR("Does not exist: %s\n", file_name);
238 return IMAGE_READ_FAILURE;
239 }
240 if (archive_read_file(archive, file_name, &image->data, &image->size,
241 NULL) != VB2_SUCCESS) {
242 ERROR("Failed to load %s\n", file_name);
243 return IMAGE_READ_FAILURE;
244 }
245
246 image->file_name = strdup(file_name);
247
248 return parse_firmware_image(image);
249 }
250
check_firmware_versions(const struct firmware_image * image)251 void check_firmware_versions(const struct firmware_image *image)
252 {
253 if (strcmp(image->rw_version_a, image->rw_version_b))
254 WARN("Different versions in %s (%s) and %s (%s).\n",
255 FMAP_RW_FWID_A, image->rw_version_a,
256 FMAP_RW_FWID_B, image->rw_version_b);
257 if (image->ecrw_version_a && image->ecrw_version_b &&
258 strcmp(image->ecrw_version_a, image->ecrw_version_b))
259 WARN("Different ecrw versions in %s (%s) and %s (%s).\n",
260 FMAP_RW_FW_MAIN_A, image->ecrw_version_a,
261 FMAP_RW_FW_MAIN_B, image->ecrw_version_b);
262 }
263
get_firmware_image_temp_file(const struct firmware_image * image,struct tempfile * tempfiles)264 const char *get_firmware_image_temp_file(const struct firmware_image *image,
265 struct tempfile *tempfiles)
266 {
267 const char *tmp_path = create_temp_file(tempfiles);
268 if (!tmp_path)
269 return NULL;
270
271 if (vb2_write_file(tmp_path, image->data, image->size) != VB2_SUCCESS) {
272 ERROR("Failed writing %s firmware image (%u bytes) to %s.\n",
273 image->programmer ? image->programmer : "temp",
274 image->size, tmp_path);
275 return NULL;
276 }
277 return tmp_path;
278 }
279
free_firmware_image(struct firmware_image * image)280 void free_firmware_image(struct firmware_image *image)
281 {
282 /*
283 * The programmer is not allocated by load_firmware_image and must be
284 * preserved explicitly.
285 */
286 const char *programmer = image->programmer;
287
288 free(image->data);
289 free(image->file_name);
290 free(image->ro_version);
291 free(image->rw_version_a);
292 free(image->rw_version_b);
293 free(image->ecrw_version_a);
294 free(image->ecrw_version_b);
295 memset(image, 0, sizeof(*image));
296 image->programmer = programmer;
297 }
298
reload_firmware_image(const char * file_path,struct firmware_image * image)299 int reload_firmware_image(const char *file_path, struct firmware_image *image)
300 {
301 free_firmware_image(image);
302 return load_firmware_image(image, file_path, NULL);
303 }
304
find_firmware_section(struct firmware_section * section,const struct firmware_image * image,const char * section_name)305 int find_firmware_section(struct firmware_section *section,
306 const struct firmware_image *image,
307 const char *section_name)
308 {
309 FmapAreaHeader *fah = NULL;
310 uint8_t *ptr;
311
312 section->data = NULL;
313 section->size = 0;
314 ptr = fmap_find_by_name(
315 image->data, image->size, image->fmap_header,
316 section_name, &fah);
317 if (!ptr)
318 return -1;
319 section->data = (uint8_t *)ptr;
320 section->size = fah->area_size;
321 return 0;
322 }
323
firmware_section_exists(const struct firmware_image * image,const char * section_name)324 int firmware_section_exists(const struct firmware_image *image,
325 const char *section_name)
326 {
327 struct firmware_section section;
328 find_firmware_section(§ion, image, section_name);
329 return section.data != NULL;
330 }
331
preserve_firmware_section(const struct firmware_image * image_from,struct firmware_image * image_to,const char * section_name)332 int preserve_firmware_section(const struct firmware_image *image_from,
333 struct firmware_image *image_to,
334 const char *section_name)
335 {
336 struct firmware_section from, to;
337
338 find_firmware_section(&from, image_from, section_name);
339 find_firmware_section(&to, image_to, section_name);
340 if (!from.data || !to.data) {
341 VB2_DEBUG("Cannot find section %.*s: from=%p, to=%p\n",
342 FMAP_NAMELEN, section_name, from.data, to.data);
343 return -1;
344 }
345 if (from.size > to.size) {
346 WARN("Section %.*s is truncated after updated.\n",
347 FMAP_NAMELEN, section_name);
348 }
349 /* Use memmove in case if we need to deal with sections that overlap. */
350 memmove(to.data, from.data, VB2_MIN(from.size, to.size));
351 return 0;
352 }
353
find_gbb(const struct firmware_image * image)354 const struct vb2_gbb_header *find_gbb(const struct firmware_image *image)
355 {
356 struct firmware_section section;
357 struct vb2_gbb_header *gbb_header;
358
359 find_firmware_section(§ion, image, FMAP_RO_GBB);
360 gbb_header = (struct vb2_gbb_header *)section.data;
361 if (!futil_valid_gbb_header(gbb_header, section.size, NULL)) {
362 ERROR("Cannot find GBB in image: %s.\n", image->file_name);
363 return NULL;
364 }
365 return gbb_header;
366 }
367
368 /*
369 * Different settings may have different SWWP programmers.
370 */
is_write_protection_enabled(struct updater_config * cfg,const char * programmer,enum dut_property_type swwp_type)371 static bool is_write_protection_enabled(struct updater_config *cfg,
372 const char *programmer,
373 enum dut_property_type swwp_type)
374 {
375 /* Assume HW/SW WP are enabled if -1 error code is returned */
376 bool hwwp = !!dut_get_property(DUT_PROP_WP_HW, cfg);
377 bool swwp = !!dut_get_property(swwp_type, cfg);
378 bool wp_enabled = hwwp && swwp;
379 STATUS("Write protection (%s): %d (%s; HW=%d, SW=%d).\n", programmer,
380 wp_enabled, wp_enabled ? "enabled" : "disabled", hwwp, swwp);
381 return wp_enabled;
382 }
383
is_ap_write_protection_enabled(struct updater_config * cfg)384 inline bool is_ap_write_protection_enabled(struct updater_config *cfg)
385 {
386 return is_write_protection_enabled(cfg, cfg->image.programmer, DUT_PROP_WP_SW_AP);
387 }
388
is_ec_write_protection_enabled(struct updater_config * cfg)389 inline bool is_ec_write_protection_enabled(struct updater_config *cfg)
390 {
391 return is_write_protection_enabled(cfg, cfg->ec_image.programmer, DUT_PROP_WP_SW_EC);
392 }
393
host_shell(const char * command)394 char *host_shell(const char *command)
395 {
396 /* Currently all commands we use do not have large output. */
397 char buf[COMMAND_BUFFER_SIZE];
398
399 int result;
400 FILE *fp = popen(command, "r");
401
402 VB2_DEBUG("%s\n", command);
403 buf[0] = '\0';
404 if (!fp) {
405 VB2_DEBUG("Execution error for %s.\n", command);
406 return strdup(buf);
407 }
408
409 if (fgets(buf, sizeof(buf), fp))
410 strip_string(buf, NULL);
411 result = pclose(fp);
412 if (!WIFEXITED(result) || WEXITSTATUS(result) != 0) {
413 VB2_DEBUG("Execution failure with exit code %d: %s\n",
414 WEXITSTATUS(result), command);
415 /*
416 * Discard all output if command failed, for example command
417 * syntax failure may lead to garbage in stdout.
418 */
419 buf[0] = '\0';
420 }
421 return strdup(buf);
422 }
423
prepare_servo_control(const char * control_name,bool on)424 void prepare_servo_control(const char *control_name, bool on)
425 {
426 char *cmd;
427 if (!control_name)
428 return;
429
430 ASPRINTF(&cmd, "dut-control %s:%s", control_name, on ? "on" : "off");
431 free(host_shell(cmd));
432 free(cmd);
433 }
434
host_detect_servo(const char ** prepare_ctrl_name)435 char *host_detect_servo(const char **prepare_ctrl_name)
436 {
437 const char *servo_port = getenv(ENV_SERVOD_PORT);
438 const char *servo_name = getenv(ENV_SERVOD_NAME);
439 const char *servo_id = servo_port, *servo_id_type = ENV_SERVOD_PORT;
440 char *servo_type = host_shell("dut-control -o servo_type 2>/dev/null");
441 const char *programmer = NULL;
442 char *ret = NULL;
443 char *servo_serial = NULL;
444
445 static const char * const raiden_debug_spi = "raiden_debug_spi";
446 static const char * const cpu_fw_spi = "cpu_fw_spi";
447 static const char * const ccd_cpu_fw_spi = "ccd_cpu_fw_spi";
448 const char *serial_cmd = "dut-control -o serialname 2>/dev/null";
449
450 /* By default, no control is needed. */
451 *prepare_ctrl_name = NULL;
452 VB2_DEBUG("servo_type: %s\n", servo_type);
453
454 /* dut-control defaults to port 9999, or non-empty servo_name. */
455 if (!servo_id || !*servo_id) {
456 if (servo_name && *servo_name) {
457 servo_id = servo_name;
458 servo_id_type = ENV_SERVOD_NAME;
459 } else {
460 servo_id = "9999";
461 }
462 }
463 assert(servo_id && *servo_id);
464
465 /* servo_type names: chromite/lib/firmware/servo_lib.py */
466 if (!*servo_type) {
467 ERROR("Failed to get servo type. Check servod.\n");
468 } else if (strcmp(servo_type, "servo_v2") == 0) {
469 VB2_DEBUG("Selected Servo V2.\n");
470 programmer = "ft2232_spi:type=google-servo-v2";
471 *prepare_ctrl_name = cpu_fw_spi;
472 } else if (strstr(servo_type, "servo_micro")) {
473 VB2_DEBUG("Selected Servo Micro.\n");
474 programmer = raiden_debug_spi;
475 *prepare_ctrl_name = cpu_fw_spi;
476 serial_cmd = ("dut-control -o servo_micro_serialname"
477 " 2>/dev/null");
478 } else if (strstr(servo_type, "ccd_cr50") ||
479 strstr(servo_type, "ccd_gsc") ||
480 strstr(servo_type, "ccd_ti50")) {
481 VB2_DEBUG("Selected CCD.\n");
482 programmer = "raiden_debug_spi:target=AP,custom_rst=true";
483 *prepare_ctrl_name = ccd_cpu_fw_spi;
484 serial_cmd = "dut-control -o ccd_serialname 2>/dev/null";
485 } else if (strstr(servo_type, "c2d2")) {
486 /* Most C2D2 devices don't support flashing AP, so this must
487 * come after CCD.
488 */
489 VB2_DEBUG("Selected C2D2.\n");
490 programmer = raiden_debug_spi;
491 *prepare_ctrl_name = cpu_fw_spi;
492 serial_cmd = ("dut-control -o c2d2_serialname"
493 " 2>/dev/null");
494 } else {
495 WARN("Unknown servo: %s\nAssuming debug header.\n", servo_type);
496 programmer = raiden_debug_spi;
497 *prepare_ctrl_name = cpu_fw_spi;
498 }
499
500 /*
501 * To support "multiple servos connected but only one servod running" we
502 * should always try to get the serial number.
503 */
504 VB2_DEBUG("Select servod by %s=%s\n", servo_id_type, servo_id);
505 servo_serial = host_shell(serial_cmd);
506 VB2_DEBUG("Servo SN=%s (serial cmd: %s)\n", servo_serial, serial_cmd);
507 if (!(servo_serial && *servo_serial)) {
508 ERROR("Failed to get serial: %s=%s\n", servo_id_type, servo_id);
509 /* If there is no servo serial, undo the prepare_ctrl_name. */
510 *prepare_ctrl_name = NULL;
511 } else if (programmer) {
512 if (!servo_serial) {
513 ret = strdup(programmer);
514 } else {
515 const char prefix = strchr(programmer, ':') ? ',' : ':';
516 ASPRINTF(&ret, "%s%cserial=%s", programmer, prefix,
517 servo_serial);
518 }
519 VB2_DEBUG("Servo programmer: %s\n", ret);
520 }
521
522 free(servo_type);
523 free(servo_serial);
524
525 return ret;
526 }
527
528 /*
529 * Returns 1 if the programmers in image1 and image2 are the same.
530 */
is_the_same_programmer(const struct firmware_image * image1,const struct firmware_image * image2)531 static int is_the_same_programmer(const struct firmware_image *image1,
532 const struct firmware_image *image2)
533 {
534 assert(image1 && image2);
535
536 /* Including if both are NULL. */
537 if (image1->programmer == image2->programmer)
538 return 1;
539
540 /* Not the same if either one is NULL. */
541 if (!image1->programmer || !image2->programmer)
542 return 0;
543
544 return strcmp(image1->programmer, image2->programmer) == 0;
545 }
546
load_system_firmware(struct updater_config * cfg,struct firmware_image * image)547 int load_system_firmware(struct updater_config *cfg,
548 struct firmware_image *image)
549 {
550 if (!strcmp(image->programmer, FLASHROM_PROGRAMMER_INTERNAL_EC))
551 WARN("%s: flashrom support for CrOS EC is EOL.\n", __func__);
552
553 int r, i;
554 const int tries = 1 + get_config_quirk(QUIRK_EXTRA_RETRIES, cfg);
555
556 int verbose = cfg->verbosity + 1; /* libflashrom verbose 1 = WARN. */
557
558 for (i = 1, r = -1; i <= tries && r != 0; i++, verbose++) {
559 if (i > 1)
560 WARN("Retry reading firmware (%d/%d)...\n", i, tries);
561 INFO("Reading SPI Flash..\n");
562 r = flashrom_read_image(image, NULL, 0, verbose);
563 }
564 if (r) {
565 /* Read failure, the content cannot be trusted. */
566 free_firmware_image(image);
567 } else {
568 /*
569 * Parse the contents. Note the image->data will remain even
570 * if parsing failed - this is important for system firmware
571 * because we may be trying to recover a device with corrupted
572 * firmware.
573 */
574 r = parse_firmware_image(image);
575 }
576 return r;
577 }
578
write_system_firmware(struct updater_config * cfg,const struct firmware_image * image,const char * const regions[],const size_t regions_len)579 int write_system_firmware(struct updater_config *cfg,
580 const struct firmware_image *image,
581 const char * const regions[],
582 const size_t regions_len)
583 {
584 if (!strcmp(image->programmer, FLASHROM_PROGRAMMER_INTERNAL_EC)) {
585 WARN("%s: flashrom support for CrOS EC is EOL.\n", __func__);
586 }
587
588 int r = 0, i;
589 const int tries = 1 + get_config_quirk(QUIRK_EXTRA_RETRIES, cfg);
590 struct firmware_image *flash_contents = NULL;
591
592 if (cfg->use_diff_image && cfg->image_current.data &&
593 is_the_same_programmer(&cfg->image_current, image))
594 flash_contents = &cfg->image_current;
595
596 int verbose = cfg->verbosity + 1; /* libflashrom verbose 1 = WARN. */
597
598 for (i = 1, r = -1; i <= tries && r != 0; i++, verbose++) {
599 if (i > 1)
600 WARN("Retry writing firmware (%d/%d)...\n", i, tries);
601 INFO("Writing SPI Flash..\n");
602 r = flashrom_write_image(image, regions, regions_len,
603 flash_contents, cfg->do_verify,
604 verbose);
605 /*
606 * Force a newline to flush stdout in case if
607 * flashrom_write_image left some messages in the buffer.
608 */
609 fprintf(stdout, "\n");
610
611 }
612 return r;
613 }
614
create_temp_file(struct tempfile * head)615 const char *create_temp_file(struct tempfile *head)
616 {
617 struct tempfile *new_temp;
618 char new_path[] = VBOOT_TMP_DIR "/fwupdater.XXXXXX";
619
620 int fd;
621 mode_t umask_save;
622
623 /* Set the umask before mkstemp for security considerations. */
624 umask_save = umask(077);
625 fd = mkstemp(new_path);
626 umask(umask_save);
627 if (fd < 0) {
628 ERROR("Failed to create new temp file in %s\n", new_path);
629 return NULL;
630 }
631 close(fd);
632 new_temp = (struct tempfile *)malloc(sizeof(*new_temp));
633 if (new_temp)
634 new_temp->filepath = strdup(new_path);
635 if (!new_temp || !new_temp->filepath) {
636 remove(new_path);
637 free(new_temp);
638 ERROR("Failed to allocate buffer for new temp file.\n");
639 return NULL;
640 }
641 VB2_DEBUG("Created new temporary file: %s.\n", new_path);
642 new_temp->next = NULL;
643 while (head->next)
644 head = head->next;
645 head->next = new_temp;
646 return new_temp->filepath;
647 }
648
remove_all_temp_files(struct tempfile * head)649 void remove_all_temp_files(struct tempfile *head)
650 {
651 /* head itself is dummy and should not be removed. */
652 assert(!head->filepath);
653 struct tempfile *next = head->next;
654 head->next = NULL;
655 while (next) {
656 head = next;
657 next = head->next;
658 assert(head->filepath);
659 VB2_DEBUG("Remove temporary file: %s.\n", head->filepath);
660 remove(head->filepath);
661 free(head->filepath);
662 free(head);
663 }
664 }
665
get_firmware_rootkey_hash(const struct firmware_image * image)666 const char *get_firmware_rootkey_hash(const struct firmware_image *image)
667 {
668 const struct vb2_gbb_header *gbb = NULL;
669 const struct vb2_packed_key *rootkey = NULL;
670
671 assert(image->data);
672
673 gbb = find_gbb(image);
674 if (!gbb) {
675 WARN("No GBB found in image.\n");
676 return NULL;
677 }
678
679 rootkey = get_rootkey(gbb);
680 if (!rootkey) {
681 WARN("No rootkey found in image.\n");
682 return NULL;
683 }
684
685 return packed_key_sha1_string(rootkey);
686 }
687
overwrite_section(struct firmware_image * image,const char * fmap_section,size_t offset,size_t size,const uint8_t * new_values)688 int overwrite_section(struct firmware_image *image,
689 const char *fmap_section, size_t offset,
690 size_t size, const uint8_t *new_values)
691 {
692 struct firmware_section section;
693
694 find_firmware_section(§ion, image, fmap_section);
695 if (section.size < offset + size) {
696 ERROR("Section smaller than given offset + size\n");
697 return -1;
698 }
699
700 if (memcmp(section.data + offset, new_values, size) == 0) {
701 VB2_DEBUG("Section already contains given values.\n");
702 return 0;
703 }
704
705 memcpy(section.data + offset, new_values, size);
706 return 0;
707 }
708