xref: /aosp_15_r20/external/vboot_reference/host/lib/flashrom.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2020 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 
6 /* For strdup */
7 #define _POSIX_C_SOURCE 200809L
8 
9 #include <fcntl.h>
10 #include <limits.h>
11 #include <stdbool.h>
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 
20 #include "2api.h"
21 #include "2return_codes.h"
22 #include "host_misc.h"
23 #include "flashrom.h"
24 #include "subprocess.h"
25 
26 #define FLASHROM_EXEC_NAME "flashrom"
27 
28 /**
29  * Helper to create a temporary file, and optionally write some data
30  * into it.
31  *
32  * @param data		If data needs to be written to the file, a
33  *			pointer to the buffer.  Pass NULL to just
34  *			create an empty temporary file.
35  * @param data_size	The size of the buffer to write, if applicable.
36  * @param path_out	An output pointer for the filename.  Caller
37  *			should free.
38  *
39  * @return VB2_SUCCESS on success, or a relevant error.
40  */
write_temp_file(const uint8_t * data,uint32_t data_size,char ** path_out)41 static vb2_error_t write_temp_file(const uint8_t *data, uint32_t data_size,
42 				   char **path_out)
43 {
44 	int fd;
45 	ssize_t write_rv;
46 	vb2_error_t rv;
47 	char *path;
48 	mode_t umask_save;
49 
50 	*path_out = NULL;
51 
52 	path = strdup(VBOOT_TMP_DIR "/vb2_flashrom.XXXXXX");
53 
54 	/* Set the umask before mkstemp for security considerations. */
55 	umask_save = umask(077);
56 	fd = mkstemp(path);
57 	umask(umask_save);
58 	if (fd < 0) {
59 		rv = VB2_ERROR_WRITE_FILE_OPEN;
60 		goto fail;
61 	}
62 
63 	while (data && data_size > 0) {
64 		write_rv = write(fd, data, data_size);
65 		if (write_rv < 0) {
66 			close(fd);
67 			unlink(path);
68 			rv = VB2_ERROR_WRITE_FILE_DATA;
69 			goto fail;
70 		}
71 
72 		data_size -= write_rv;
73 		data += write_rv;
74 	}
75 
76 	close(fd);
77 	*path_out = path;
78 	return VB2_SUCCESS;
79 
80  fail:
81 	free(path);
82 	return rv;
83 }
84 
run_flashrom(const char * const argv[])85 static vb2_error_t run_flashrom(const char *const argv[])
86 {
87 	int status = subprocess_run(argv, &subprocess_null, &subprocess_null,
88 				    &subprocess_null);
89 	if (status) {
90 		fprintf(stderr, "Flashrom invocation failed (exit status %d):",
91 			status);
92 
93 		for (const char *const *argp = argv; *argp; argp++)
94 			fprintf(stderr, " %s", *argp);
95 
96 		fprintf(stderr, "\n");
97 		return VB2_ERROR_FLASHROM;
98 	}
99 
100 	return VB2_SUCCESS;
101 }
102 
flashrom_read(struct firmware_image * image,const char * region)103 vb2_error_t flashrom_read(struct firmware_image *image, const char *region)
104 {
105 	char *tmpfile;
106 	char region_param[PATH_MAX];
107 	vb2_error_t rv;
108 
109 	image->data = NULL;
110 	image->size = 0;
111 
112 	VB2_TRY(write_temp_file(NULL, 0, &tmpfile));
113 
114 	if (region)
115 		snprintf(region_param, sizeof(region_param), "%s:%s", region,
116 			 tmpfile);
117 
118 	const char *const argv[] = {
119 		FLASHROM_EXEC_NAME,
120 		"-p",
121 		image->programmer,
122 		"-r",
123 		region ? "-i" : tmpfile,
124 		region ? region_param : NULL,
125 		NULL,
126 	};
127 
128 	rv = run_flashrom(argv);
129 	if (rv == VB2_SUCCESS)
130 		rv = vb2_read_file(tmpfile, &image->data, &image->size);
131 
132 	unlink(tmpfile);
133 	free(tmpfile);
134 	return rv;
135 }
136 
flashrom_write(struct firmware_image * image,const char * region)137 vb2_error_t flashrom_write(struct firmware_image *image, const char *region)
138 {
139 	char *tmpfile;
140 	char region_param[PATH_MAX];
141 	vb2_error_t rv;
142 
143 	VB2_TRY(write_temp_file(image->data, image->size, &tmpfile));
144 
145 	if (region)
146 		snprintf(region_param, sizeof(region_param), "%s:%s", region,
147 			 tmpfile);
148 
149 	const char *const argv[] = {
150 		FLASHROM_EXEC_NAME,
151 		"-p",
152 		image->programmer,
153 		"--noverify-all",
154 		"-w",
155 		region ? "-i" : tmpfile,
156 		region ? region_param : NULL,
157 		NULL,
158 	};
159 
160 	rv = run_flashrom(argv);
161 	unlink(tmpfile);
162 	free(tmpfile);
163 	return rv;
164 }
165