efi_loader: validate load option
For passing the optional data of the load option to the loaded imaged protocol we need its size. efi_deserialize_load_option() is changed to return the size of the optional data. As a by-product we get a partial validation of the load option. Checking the length of the device path remains to be implemented. Some Coverity defects identified the load options as user input because get_unaligned_le32() and get_unaligned_le16() is called. But non of these Coverity defects can be resolved without marking functions with Coverity specific tags. Reported-by: Coverity (CID 303760) Reported-by: Coverity (CID 303768) Reported-by: Coverity (CID 303776) Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
This commit is contained in:
		
							parent
							
								
									ecd4d99f65
								
							
						
					
					
						commit
						0e69bcfb27
					
				|  | @ -694,14 +694,19 @@ static int do_efi_boot_rm(struct cmd_tbl *cmdtp, int flag, | ||||||
|  * |  * | ||||||
|  * Decode the value of UEFI load option variable and print information. |  * Decode the value of UEFI load option variable and print information. | ||||||
|  */ |  */ | ||||||
| static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t size) | static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t *size) | ||||||
| { | { | ||||||
| 	struct efi_load_option lo; | 	struct efi_load_option lo; | ||||||
| 	char *label, *p; | 	char *label, *p; | ||||||
| 	size_t label_len16, label_len; | 	size_t label_len16, label_len; | ||||||
| 	u16 *dp_str; | 	u16 *dp_str; | ||||||
|  | 	efi_status_t ret; | ||||||
| 
 | 
 | ||||||
| 	efi_deserialize_load_option(&lo, data); | 	ret = efi_deserialize_load_option(&lo, data, size); | ||||||
|  | 	if (ret != EFI_SUCCESS) { | ||||||
|  | 		printf("%ls: invalid load option\n", varname16); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	label_len16 = u16_strlen(lo.label); | 	label_len16 = u16_strlen(lo.label); | ||||||
| 	label_len = utf16_utf8_strnlen(lo.label, label_len16); | 	label_len = utf16_utf8_strnlen(lo.label, label_len16); | ||||||
|  | @ -728,8 +733,7 @@ static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t size) | ||||||
| 
 | 
 | ||||||
| 	printf("  data:\n"); | 	printf("  data:\n"); | ||||||
| 	print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1, | 	print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1, | ||||||
| 		       lo.optional_data, size + (u8 *)data - | 		       lo.optional_data, *size, true); | ||||||
| 		       (u8 *)lo.optional_data, true); |  | ||||||
| 	free(label); | 	free(label); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -759,7 +763,7 @@ static void show_efi_boot_opt(u16 *varname16) | ||||||
| 						&efi_global_variable_guid, | 						&efi_global_variable_guid, | ||||||
| 						NULL, &size, data)); | 						NULL, &size, data)); | ||||||
| 		if (ret == EFI_SUCCESS) | 		if (ret == EFI_SUCCESS) | ||||||
| 			show_efi_boot_opt_data(varname16, data, size); | 			show_efi_boot_opt_data(varname16, data, &size); | ||||||
| 		free(data); | 		free(data); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -920,7 +924,12 @@ static int show_efi_boot_order(void) | ||||||
| 			goto out; | 			goto out; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		efi_deserialize_load_option(&lo, data); | 		ret = efi_deserialize_load_option(&lo, data, &size); | ||||||
|  | 		if (ret != EFI_SUCCESS) { | ||||||
|  | 			printf("%ls: invalid load option\n", var_name16); | ||||||
|  | 			ret = CMD_RET_FAILURE; | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		label_len16 = u16_strlen(lo.label); | 		label_len16 = u16_strlen(lo.label); | ||||||
| 		label_len = utf16_utf8_strnlen(lo.label, label_len16); | 		label_len = utf16_utf8_strnlen(lo.label, label_len16); | ||||||
|  |  | ||||||
|  | @ -708,7 +708,8 @@ struct efi_load_option { | ||||||
| 	const u8 *optional_data; | 	const u8 *optional_data; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data); | efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data, | ||||||
|  | 					 efi_uintn_t *size); | ||||||
| unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data); | unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data); | ||||||
| efi_status_t efi_bootmgr_load(efi_handle_t *handle); | efi_status_t efi_bootmgr_load(efi_handle_t *handle); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -36,24 +36,50 @@ static const struct efi_runtime_services *rs; | ||||||
|  * |  * | ||||||
|  * @lo:		pointer to target |  * @lo:		pointer to target | ||||||
|  * @data:	serialized data |  * @data:	serialized data | ||||||
|  |  * @size:	size of the load option, on return size of the optional data | ||||||
|  |  * Return:	status code | ||||||
|  */ |  */ | ||||||
| void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data) | efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data, | ||||||
|  | 					 efi_uintn_t *size) | ||||||
| { | { | ||||||
|  | 	efi_uintn_t len; | ||||||
|  | 
 | ||||||
|  | 	len = sizeof(u32); | ||||||
|  | 	if (*size < len + 2 * sizeof(u16)) | ||||||
|  | 		return EFI_INVALID_PARAMETER; | ||||||
| 	lo->attributes = get_unaligned_le32(data); | 	lo->attributes = get_unaligned_le32(data); | ||||||
| 	data += sizeof(u32); | 	data += len; | ||||||
|  | 	*size -= len; | ||||||
| 
 | 
 | ||||||
|  | 	len = sizeof(u16); | ||||||
| 	lo->file_path_length = get_unaligned_le16(data); | 	lo->file_path_length = get_unaligned_le16(data); | ||||||
| 	data += sizeof(u16); | 	data += len; | ||||||
|  | 	*size -= len; | ||||||
| 
 | 
 | ||||||
| 	/* FIXME */ |  | ||||||
| 	lo->label = (u16 *)data; | 	lo->label = (u16 *)data; | ||||||
| 	data += (u16_strlen(lo->label) + 1) * sizeof(u16); | 	len = u16_strnlen(lo->label, *size / sizeof(u16) - 1); | ||||||
|  | 	if (lo->label[len]) | ||||||
|  | 		return EFI_INVALID_PARAMETER; | ||||||
|  | 	len = (len + 1) * sizeof(u16); | ||||||
|  | 	if (*size < len) | ||||||
|  | 		return EFI_INVALID_PARAMETER; | ||||||
|  | 	data += len; | ||||||
|  | 	*size -= len; | ||||||
| 
 | 
 | ||||||
| 	/* FIXME */ | 	len = lo->file_path_length; | ||||||
|  | 	if (*size < len) | ||||||
|  | 		return EFI_INVALID_PARAMETER; | ||||||
| 	lo->file_path = (struct efi_device_path *)data; | 	lo->file_path = (struct efi_device_path *)data; | ||||||
| 	data += lo->file_path_length; | 	 /*
 | ||||||
|  | 	  * TODO: validate device path. There should be an end node within | ||||||
|  | 	  * the indicated file_path_length. | ||||||
|  | 	  */ | ||||||
|  | 	data += len; | ||||||
|  | 	*size -= len; | ||||||
| 
 | 
 | ||||||
| 	lo->optional_data = data; | 	lo->optional_data = data; | ||||||
|  | 
 | ||||||
|  | 	return EFI_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -168,7 +194,11 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle) | ||||||
| 	if (!load_option) | 	if (!load_option) | ||||||
| 		return EFI_LOAD_ERROR; | 		return EFI_LOAD_ERROR; | ||||||
| 
 | 
 | ||||||
| 	efi_deserialize_load_option(&lo, load_option); | 	ret = efi_deserialize_load_option(&lo, load_option, &size); | ||||||
|  | 	if (ret != EFI_SUCCESS) { | ||||||
|  | 		log_warning("Invalid load option for %ls\n", varname); | ||||||
|  | 		goto error; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (lo.attributes & LOAD_OPTION_ACTIVE) { | 	if (lo.attributes & LOAD_OPTION_ACTIVE) { | ||||||
| 		u32 attributes; | 		u32 attributes; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue