• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <fcntl.h>
5 #include <errno.h>
6 #include <limits.h>
7 #include <openssl/sha.h>
8 #include <stdio.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <stdlib.h>
13 
14 #include "amdfwtool.h"
15 
16 /* Defines related to hashing signed binaries */
17 enum hash_header_ver {
18 	HASH_HDR_V1 = 1,
19 	HASH_HDR_V2,
20 };
21 /* Signature ID enums are defined by PSP based on the algorithm used. */
22 enum signature_id {
23 	SIG_ID_RSA2048,
24 	SIG_ID_RSA4096 = 2,
25 };
26 
27 #define HASH_FILE_SUFFIX ".hash"
28 struct psp_fw_hash_file_info {
29 	int fd;
30 	bool present;
31 	struct psp_fw_hash_table hash_header;
32 };
33 static struct psp_fw_hash_file_info hash_files[MAX_NUM_HASH_TABLES];
34 
35 #define UUID_MAGIC "gpd.ta.appID"
36 
get_psp_fw_type(enum platform soc_id,struct amd_fw_header * header)37 static uint16_t get_psp_fw_type(enum platform soc_id, struct amd_fw_header *header)
38 {
39 	switch (soc_id) {
40 	case PLATFORM_MENDOCINO:
41 	case PLATFORM_PHOENIX:
42 	case PLATFORM_GLINDA:
43 		/* Fallback to fw_type if fw_id is not populated, which serves the same
44 		   purpose on older SoCs. */
45 		return header->fw_id ? header->fw_id : header->fw_type;
46 	default:
47 		return header->fw_type;
48 	}
49 }
50 
get_psp_fw_uuid(void * buf,size_t buf_len,uint8_t * uuid)51 static void get_psp_fw_uuid(void *buf, size_t buf_len, uint8_t *uuid)
52 {
53 	void *ptr = memmem(buf, buf_len, UUID_MAGIC, strlen(UUID_MAGIC));
54 
55 	assert(ptr != NULL);
56 
57 	memcpy(uuid, ptr + strlen(UUID_MAGIC), UUID_LEN_BYTES);
58 }
59 
add_single_sha(amd_fw_entry_hash * entry,void * buf,enum platform soc_id,fwid_type_t fwid_type)60 static int add_single_sha(amd_fw_entry_hash *entry, void *buf, enum platform soc_id,
61 								fwid_type_t fwid_type)
62 {
63 	uint8_t hash[SHA384_DIGEST_LENGTH];
64 	struct amd_fw_header *header = (struct amd_fw_header *)buf;
65 	/* Include only signed part for hash calculation. */
66 	size_t len = header->fw_size_signed + sizeof(struct amd_fw_header);
67 	uint8_t *body = (uint8_t *)buf;
68 
69 	if (len > header->size_total)
70 		return -1;
71 
72 	if (header->sig_id == SIG_ID_RSA4096) {
73 		SHA384(body, len, hash);
74 		entry->sha_len = SHA384_DIGEST_LENGTH;
75 	} else if (header->sig_id == SIG_ID_RSA2048) {
76 		SHA256(body, len, hash);
77 		entry->sha_len = SHA256_DIGEST_LENGTH;
78 	} else {
79 		fprintf(stderr, "%s: Unknown signature id: 0x%08x\n",
80 						__func__, header->sig_id);
81 		return -1;
82 	}
83 
84 	memcpy(entry->sha, hash, entry->sha_len);
85 	entry->fwid_type = fwid_type;
86 	if (fwid_type == FWID_TYPE_UUID)
87 		get_psp_fw_uuid(buf, header->size_total, entry->uuid);
88 	else
89 		entry->fw_id = get_psp_fw_type(soc_id, header);
90 	entry->subtype = header->fw_subtype;
91 
92 	return 0;
93 }
94 
get_num_binaries(void * buf,size_t buf_size)95 static int get_num_binaries(void *buf, size_t buf_size)
96 {
97 	struct amd_fw_header *header = (struct amd_fw_header *)buf;
98 	size_t total_len = 0;
99 	int num_binaries = 0;
100 
101 	while (total_len < buf_size) {
102 		num_binaries++;
103 		total_len += header->size_total;
104 		header = (struct amd_fw_header *)(buf + total_len);
105 	}
106 
107 	if (total_len != buf_size) {
108 		fprintf(stderr, "Malformed binary\n");
109 		return -1;
110 	}
111 	return num_binaries;
112 }
113 
add_sha(amd_fw_entry * entry,void * buf,size_t buf_size,enum platform soc_id)114 static int add_sha(amd_fw_entry *entry, void *buf, size_t buf_size, enum platform soc_id)
115 {
116 	struct amd_fw_header *header = (struct amd_fw_header *)buf;
117 	/* Include only signed part for hash calculation. */
118 	size_t total_len = 0;
119 	int num_binaries = get_num_binaries(buf, buf_size);
120 
121 	if (num_binaries <= 0)
122 		return num_binaries;
123 
124 	entry->hash_entries = calloc(num_binaries, sizeof(amd_fw_entry_hash));
125 	if (!entry->hash_entries) {
126 		fprintf(stderr, "Error allocating memory to add FW hash\n");
127 		return -1;
128 	}
129 	entry->num_hash_entries = num_binaries;
130 
131 	/* Iterate through each binary */
132 	for (int i = 0; i < num_binaries; i++) {
133 		if (add_single_sha(&entry->hash_entries[i], buf + total_len, soc_id,
134 								entry->fwid_type)) {
135 			free(entry->hash_entries);
136 			return -1;
137 		}
138 		total_len += header->size_total;
139 		header = (struct amd_fw_header *)(buf + total_len);
140 	}
141 
142 	return 0;
143 }
144 
write_one_psp_firmware_hash_entry(int fd,amd_fw_entry_hash * entry,uint8_t hash_tbl_id)145 static void write_one_psp_firmware_hash_entry(int fd, amd_fw_entry_hash *entry,
146 								uint8_t hash_tbl_id)
147 {
148 	uint16_t subtype = entry->subtype;
149 
150 	if (hash_files[hash_tbl_id].hash_header.version == HASH_HDR_V2) {
151 		write_or_fail(fd, entry->uuid, UUID_LEN_BYTES);
152 	} else {
153 		write_or_fail(fd, &entry->fw_id, sizeof(entry->fw_id));
154 		write_or_fail(fd, &subtype, sizeof(subtype));
155 	}
156 	write_or_fail(fd, entry->sha, entry->sha_len);
157 }
158 
open_psp_fw_hash_files(const char * file_prefix)159 static void open_psp_fw_hash_files(const char *file_prefix)
160 {
161 	size_t hash_file_strlen;
162 	char *hash_file_name;
163 
164 	/* Hash Table ID is part of the file name. For now only single digit ID is
165 	   supported and is sufficient. Hence assert MAX_NUM_HASH_TABLES < 10 before
166 	   constructing file name. Revisit later when > 10 hash tables are required. */
167 	assert(MAX_NUM_HASH_TABLES < 10);
168 	/* file_prefix + ".[1-9]" + ".hash" + '\0' */
169 	hash_file_strlen = strlen(file_prefix) + 2 + strlen(HASH_FILE_SUFFIX) + 1;
170 	hash_file_name = malloc(hash_file_strlen);
171 	if (!hash_file_name)  {
172 		fprintf(stderr, "malloc(%lu) failed\n", hash_file_strlen);
173 		exit(-1);
174 	}
175 
176 	for (unsigned int i = 0; i < MAX_NUM_HASH_TABLES; i++) {
177 		/* Hash table IDs are expected to be contiguous and hence holes are not
178 		   expected. */
179 		if (!hash_files[i].present)
180 			break;
181 
182 		if (i)
183 			snprintf(hash_file_name, hash_file_strlen, "%s.%d%s",
184 				 file_prefix, i, HASH_FILE_SUFFIX);
185 		else
186 			/* Default file name without number for backwards compatibility. */
187 			snprintf(hash_file_name, hash_file_strlen, "%s%s",
188 				 file_prefix, HASH_FILE_SUFFIX);
189 
190 		hash_files[i].fd = open(hash_file_name, O_RDWR | O_CREAT | O_TRUNC, 0666);
191 		if (hash_files[i].fd < 0) {
192 			fprintf(stderr, "Error opening file: %s: %s\n",
193 					hash_file_name, strerror(errno));
194 			free(hash_file_name);
195 			exit(-1);
196 		}
197 	}
198 	free(hash_file_name);
199 }
200 
close_psp_fw_hash_files(void)201 static void close_psp_fw_hash_files(void)
202 {
203 	for (unsigned int i = 0; i < MAX_NUM_HASH_TABLES; i++) {
204 		if (!hash_files[i].present)
205 			break;
206 
207 		close(hash_files[i].fd);
208 	}
209 }
210 
write_psp_firmware_hash(amd_fw_entry * fw_table)211 static void write_psp_firmware_hash(amd_fw_entry *fw_table)
212 {
213 	uint8_t hash_tbl_id;
214 
215 	for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
216 		hash_tbl_id = fw_table[i].hash_tbl_id;
217 		assert(hash_files[hash_tbl_id].present);
218 
219 		for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) {
220 			if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH) {
221 				hash_files[hash_tbl_id].hash_header.no_of_entries_256++;
222 			} else if (fw_table[i].hash_entries[j].sha_len ==
223 								SHA384_DIGEST_LENGTH) {
224 				hash_files[hash_tbl_id].hash_header.no_of_entries_384++;
225 			} else if (fw_table[i].hash_entries[j].sha_len) {
226 				fprintf(stderr, "%s: Error invalid sha_len %d\n",
227 						__func__, fw_table[i].hash_entries[j].sha_len);
228 				exit(-1);
229 			}
230 		}
231 	}
232 
233 	for (unsigned int i = 0; i < MAX_NUM_HASH_TABLES; i++) {
234 		if (!hash_files[i].present)
235 			continue;
236 		write_or_fail(hash_files[i].fd, &hash_files[i].hash_header,
237 						sizeof(hash_files[i].hash_header));
238 		/* Add a reserved field as expected by version 2 header */
239 		if (hash_files[i].hash_header.version == HASH_HDR_V2) {
240 			uint16_t reserved = 0;
241 
242 			write_or_fail(hash_files[i].fd, &reserved, sizeof(reserved));
243 		}
244 	}
245 
246 	/* Add all the SHA256 hash entries first followed by SHA384 entries. PSP verstage
247 	   processes the table in that order. Mixing and matching SHA256 and SHA384 entries
248 	   will cause the hash verification failure at run-time. */
249 	for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
250 		hash_tbl_id = fw_table[i].hash_tbl_id;
251 		for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) {
252 			if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH)
253 				write_one_psp_firmware_hash_entry(hash_files[hash_tbl_id].fd,
254 						&fw_table[i].hash_entries[j], hash_tbl_id);
255 		}
256 	}
257 
258 	for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
259 		hash_tbl_id = fw_table[i].hash_tbl_id;
260 		for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) {
261 			if (fw_table[i].hash_entries[j].sha_len == SHA384_DIGEST_LENGTH)
262 				write_one_psp_firmware_hash_entry(hash_files[hash_tbl_id].fd,
263 						&fw_table[i].hash_entries[j], hash_tbl_id);
264 		}
265 	}
266 
267 	for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
268 		if (!fw_table[i].num_hash_entries || !fw_table[i].hash_entries)
269 			continue;
270 
271 		free(fw_table[i].hash_entries);
272 		fw_table[i].hash_entries = NULL;
273 		fw_table[i].num_hash_entries = 0;
274 	}
275 }
276 
update_hash_files_config(amd_fw_entry * fw_table)277 static void update_hash_files_config(amd_fw_entry *fw_table)
278 {
279 	uint16_t version = fw_table->fwid_type == FWID_TYPE_UUID ? HASH_HDR_V2 : HASH_HDR_V1;
280 
281 	hash_files[fw_table->hash_tbl_id].present = true;
282 	if (version > hash_files[fw_table->hash_tbl_id].hash_header.version)
283 		hash_files[fw_table->hash_tbl_id].hash_header.version = version;
284 }
285 
286 /**
287  * process_signed_psp_firmwares() - Process the signed PSP binaries to keep them separate
288  * @signed_rom:	Output file path grouping all the signed PSP binaries.
289  * @fw_table:	Table of all the PSP firmware entries/binaries to be processed.
290  * @signed_start_addr:	Offset of the FMAP section, within the flash device, to hold
291  *                      the signed PSP binaries.
292  * @soc_id:	SoC ID of the PSP binaries.
293  */
process_signed_psp_firmwares(const char * signed_rom,amd_fw_entry * fw_table,uint64_t signed_start_addr,enum platform soc_id)294 void process_signed_psp_firmwares(const char *signed_rom,
295 		amd_fw_entry *fw_table,
296 		uint64_t signed_start_addr,
297 		enum platform soc_id)
298 {
299 	unsigned int i;
300 	int fd;
301 	int signed_rom_fd;
302 	ssize_t bytes, align_bytes;
303 	uint8_t *buf;
304 	struct amd_fw_header header;
305 	struct stat fd_stat;
306 	/* Every blob in amdfw*.rom has to start at address aligned to 0x100. Prepare an
307 	   alignment data with 0xff to pad the blobs and meet the alignment requirement. */
308 	uint8_t align_data[BLOB_ALIGNMENT - 1];
309 
310 	memset(align_data, 0xff, sizeof(align_data));
311 	signed_rom_fd = open(signed_rom, O_RDWR | O_CREAT | O_TRUNC,
312 				S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
313 	if (signed_rom_fd < 0) {
314 		fprintf(stderr, "Error opening file: %s: %s\n",
315 				signed_rom, strerror(errno));
316 		return;
317 	}
318 
319 	for (i = 0; fw_table[i].type != AMD_FW_INVALID; i++) {
320 		fw_table[i].num_hash_entries = 0;
321 		fw_table[i].hash_entries = NULL;
322 
323 		if (!(fw_table[i].filename) || fw_table[i].skip_hashing)
324 			continue;
325 
326 		memset(&header, 0, sizeof(header));
327 
328 		fd = open(fw_table[i].filename, O_RDONLY);
329 		if (fd < 0) {
330 			/* Keep the file along with set of unsigned PSP binaries & continue. */
331 			fprintf(stderr, "Error opening file: %s: %s\n",
332 					fw_table[i].filename, strerror(errno));
333 			continue;
334 		}
335 
336 		if (fstat(fd, &fd_stat)) {
337 			/* Keep the file along with set of unsigned PSP binaries & continue. */
338 			fprintf(stderr, "fstat error: %s\n", strerror(errno));
339 			close(fd);
340 			continue;
341 		}
342 
343 		bytes = read_from_file_to_buf(fd, &header, sizeof(struct amd_fw_header));
344 		if (bytes != (ssize_t)sizeof(struct amd_fw_header)) {
345 			/* Keep the file along with set of unsigned PSP binaries & continue. */
346 			fprintf(stderr, "%s: Error reading header from %s\n",
347 						__func__, fw_table[i].filename);
348 			close(fd);
349 			continue;
350 		}
351 
352 		/* If firmware header looks like invalid, assume it's not signed */
353 		if (!header.fw_type && !header.fw_id) {
354 			fprintf(stderr, "%s: Invalid FWID for %s\n",
355 					__func__, fw_table[i].filename);
356 			close(fd);
357 			continue;
358 		}
359 
360 
361 		/* PSP binary is not signed and should not be part of signed PSP binaries
362 		   set. */
363 		if (header.sig_opt != 1) {
364 			close(fd);
365 			continue;
366 		}
367 
368 		buf = malloc(fd_stat.st_size);
369 		if (!buf) {
370 			/* Keep the file along with set of unsigned PSP binaries & continue. */
371 			fprintf(stderr, "%s: failed to allocate memory with size %lld\n",
372 							__func__, (long long)fd_stat.st_size);
373 			close(fd);
374 			continue;
375 		}
376 
377 		lseek(fd, SEEK_SET, 0);
378 		bytes = read_from_file_to_buf(fd, buf, fd_stat.st_size);
379 		if (bytes != fd_stat.st_size) {
380 			/* Keep the file along with set of unsigned PSP binaries & continue. */
381 			fprintf(stderr, "%s: failed to read %s\n",
382 					__func__, fw_table[i].filename);
383 			free(buf);
384 			close(fd);
385 			continue;
386 		}
387 
388 		bytes = write_from_buf_to_file(signed_rom_fd, buf, fd_stat.st_size);
389 		if (bytes != fd_stat.st_size) {
390 			/* Keep the file along with set of unsigned PSP binaries & continue. */
391 			fprintf(stderr, "%s: failed to write %s\n",
392 					__func__, fw_table[i].filename);
393 			free(buf);
394 			close(fd);
395 			continue;
396 		}
397 
398 		/* Write Blob alignment bytes */
399 		align_bytes = 0;
400 		if (fd_stat.st_size & (BLOB_ALIGNMENT - 1)) {
401 			align_bytes = BLOB_ALIGNMENT -
402 				(fd_stat.st_size & (BLOB_ALIGNMENT - 1));
403 			bytes = write_from_buf_to_file(signed_rom_fd, align_data, align_bytes);
404 			if (bytes != align_bytes) {
405 				fprintf(stderr, "%s: failed to write alignment data for %s\n",
406 								__func__, fw_table[i].filename);
407 				lseek(signed_rom_fd, SEEK_CUR, -fd_stat.st_size);
408 				free(buf);
409 				close(fd);
410 				continue;
411 			}
412 		}
413 
414 		if (add_sha(&fw_table[i], buf, fd_stat.st_size, soc_id))
415 			exit(-1);
416 
417 		/* File is successfully processed and is part of signed PSP binaries set. */
418 		fw_table[i].addr_signed = signed_start_addr;
419 		fw_table[i].file_size = (uint32_t)fd_stat.st_size;
420 		update_hash_files_config(&fw_table[i]);
421 
422 		signed_start_addr += fd_stat.st_size + align_bytes;
423 
424 		free(buf);
425 		close(fd);
426 	}
427 
428 	close(signed_rom_fd);
429 
430 	open_psp_fw_hash_files(signed_rom);
431 	write_psp_firmware_hash(fw_table);
432 	close_psp_fw_hash_files();
433 }
434