xref: /aosp_15_r20/external/vboot_reference/futility/updater_utils.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
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(&section, 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(&section, 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(&section, 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