ACK: [PATCH v2 1/2] uefirtvariable: allow large sizes for variable names

ivanhu ivan.hu at canonical.com
Wed Mar 4 06:39:59 UTC 2015


On 2015年02月12日 04:43, Ricardo Neri wrote:
> The UEFI specification does not define the maximum length for the
> variable name. Thus, it may happen that some firmware implementations
> have variable names longer than 1024 characters. Rather than limiting
> the maximum size to 1024 characters, set the initial size to 1024 chars
> and enlarge as required.
>
> To allow for longer names, allocate and and grow the allocated memory
> as required by the firmware. If we are unable to allocate the needed
> memory, we skip the test.
>
> This functionality required to rework the error paths of the involved
> functions.
>
> Signed-off-by: Ricardo Neri <ricardo.neri-calderon at linux.intel.com>
> ---
>   efi_runtime/efi_runtime.c                |   3 -
>   src/uefi/uefirtvariable/uefirtvariable.c | 152 ++++++++++++++++++++++++++-----
>   2 files changed, 128 insertions(+), 27 deletions(-)
>
> diff --git a/efi_runtime/efi_runtime.c b/efi_runtime/efi_runtime.c
> index 786a1df..1125556 100644
> --- a/efi_runtime/efi_runtime.c
> +++ b/efi_runtime/efi_runtime.c
> @@ -450,9 +450,6 @@ static long efi_runtime_get_nextvariablename(unsigned long arg)
>   			   sizeof(vendor_guid)))
>   		return -EFAULT;
>   
> -	if (name_size > 1024)
> -		return -EFAULT;
> -
>   	convert_from_guid(&vendor, &vendor_guid);
>   
>   	rv = copy_ucs2_from_user_len(&name,
> diff --git a/src/uefi/uefirtvariable/uefirtvariable.c b/src/uefi/uefirtvariable/uefirtvariable.c
> index 0c3f532..b966aed 100644
> --- a/src/uefi/uefirtvariable/uefirtvariable.c
> +++ b/src/uefi/uefirtvariable/uefirtvariable.c
> @@ -295,9 +295,11 @@ static int getnextvariable_test1(fwts_framework *fw)
>   
>   	struct efi_getnextvariablename getnextvariablename;
>   	uint64_t variablenamesize = MAX_DATA_LENGTH;
> -	uint16_t variablename[MAX_DATA_LENGTH];
> +	uint64_t maxvariablenamesize = variablenamesize;
> +	uint16_t *variablename;
>   	EFI_GUID vendorguid;
>   	bool found_name = false, found_guid = false;
> +	int ret;
>   
>   	for (dataindex = 0; dataindex < datasize; dataindex++)
>   		data[dataindex] = (uint8_t)dataindex;
> @@ -329,6 +331,12 @@ static int getnextvariable_test1(fwts_framework *fw)
>   		return FWTS_ERROR;
>   	}
>   
> +	variablename = malloc(sizeof(uint16_t) * variablenamesize);
> +	if (!variablename) {
> +		fwts_skipped(fw, "Unable to alloc memory for variable name");
> +		ret = FWTS_SKIP;
> +		goto err_restore_env;
> +	}
>   	getnextvariablename.VariableNameSize = &variablenamesize;
>   	getnextvariablename.VariableName = variablename;
>   	getnextvariablename.VendorGuid = &vendorguid;
> @@ -340,7 +348,7 @@ static int getnextvariable_test1(fwts_framework *fw)
>   	 */
>   	variablename[0] = '\0';
>   	while (true) {
> -		variablenamesize = MAX_DATA_LENGTH;
> +		variablenamesize = maxvariablenamesize;
>   		ioret = ioctl(fd, EFI_RUNTIME_GET_NEXTVARIABLENAME, &getnextvariablename);
>   
>   		if (ioret == -1) {
> @@ -349,11 +357,32 @@ static int getnextvariable_test1(fwts_framework *fw)
>   			if (*getnextvariablename.status == EFI_NOT_FOUND)
>   				break;
>   
> +			/*
> +			 * If the buffer we provided is too small for the name,
> +			 * allocate a larger buffer and try again
> +			 */
> +			if (*getnextvariablename.status == EFI_BUFFER_TOO_SMALL) {
> +				uint16_t *tmp;
> +
> +				tmp = realloc(variablename,
> +					      sizeof(uint16_t) * variablenamesize);
> +				if (tmp) {
> +					variablename = tmp;
> +					getnextvariablename.VariableName = variablename;
> +					maxvariablenamesize = variablenamesize;
> +					continue;
> +				}
> +				fwts_skipped(fw, "Unable to reallocate memory for variable name");
> +				ret = FWTS_SKIP;
> +				goto err_restore_env;
> +			}
> +
>   			fwts_failed(fw, LOG_LEVEL_HIGH,
>   				"UEFIRuntimeGetNextVariableName",
>   				"Failed to get next variable name with UEFI "
>   				"runtime service.");
>   			fwts_uefi_print_status_info(fw, status);
> +			ret = FWTS_ERROR;
>   			goto err_restore_env;
>   		}
>   		if (compare_name(getnextvariablename.VariableName, variablenametest))
> @@ -364,6 +393,12 @@ static int getnextvariable_test1(fwts_framework *fw)
>   			break;
>   	};
>   
> +	if (variablename) {
> +		free(variablename);
> +		getnextvariablename.VariableName = NULL;
> +		variablename = NULL;
> +	}
> +
>   	if (!found_name) {
>   		fwts_failed(fw, LOG_LEVEL_HIGH,
>   			"UEFIRuntimeGetNextVariableNameName",
> @@ -404,7 +439,10 @@ err_restore_env:
>   		return FWTS_ERROR;
>   	}
>   
> -	return FWTS_ERROR;
> +	if (variablename)
> +		free(variablename);
> +
> +	return ret;
>   }
>   
>   /*
> @@ -434,8 +472,16 @@ static int getnextvariable_test2(fwts_framework *fw)
>   
>   	struct efi_getnextvariablename getnextvariablename;
>   	uint64_t variablenamesize = MAX_DATA_LENGTH;
> -	uint16_t variablename[MAX_DATA_LENGTH];
> +	uint64_t maxvariablenamesize = variablenamesize;
> +	uint16_t *variablename;
>   	EFI_GUID vendorguid;
> +	int ret = FWTS_OK;
> +
> +	variablename = malloc(sizeof(uint16_t) * variablenamesize);
> +	if (!variablename) {
> +		fwts_skipped(fw, "Unable to alloc memory for variable name");
> +		return FWTS_SKIP;
> +	}
>   
>   	getnextvariablename.VariableNameSize = &variablenamesize;
>   	getnextvariablename.VariableName = variablename;
> @@ -448,7 +494,7 @@ static int getnextvariable_test2(fwts_framework *fw)
>   	 */
>   	variablename[0] = '\0';
>   	while (true) {
> -		variablenamesize = MAX_DATA_LENGTH;
> +		variablenamesize = maxvariablenamesize;
>   		ioret = ioctl(fd, EFI_RUNTIME_GET_NEXTVARIABLENAME, &getnextvariablename);
>   
>   		if (ioret == -1) {
> @@ -456,27 +502,47 @@ static int getnextvariable_test2(fwts_framework *fw)
>   			/* no next variable was found*/
>   			if (*getnextvariablename.status == EFI_NOT_FOUND)
>   				break;
> +			/*
> +			 * If the buffer we provided is too small for the name,
> +			 * allocate a larger buffer and try again
> +			 */
> +			if (*getnextvariablename.status == EFI_BUFFER_TOO_SMALL) {
> +				uint16_t *tmp;
> +
> +				tmp = realloc(variablename,
> +					      sizeof(uint16_t) * variablenamesize);
> +				if (tmp) {
> +					variablename = tmp;
> +					getnextvariablename.VariableName = variablename;
> +					maxvariablenamesize = variablenamesize;
> +					continue;
> +				}
> +				fwts_skipped(fw, "Unable to reallocate memory for variable name");
> +				ret = FWTS_SKIP;
> +				break;
> +			}
>   
>   			fwts_failed(fw, LOG_LEVEL_HIGH,
>   				"UEFIRuntimeGetNextVariableName",
>   				"Failed to get next variable name with UEFI "
>   				"runtime service.");
>   			fwts_uefi_print_status_info(fw, status);
> -			goto err;
> +			ret = FWTS_ERROR;
> +			break;
> +
>   		}
>   
> -		if (variablenamesize != MAX_DATA_LENGTH &&
> -		    !strlen_valid(variablename, variablenamesize)) {
> +		if (!strlen_valid(variablename, variablenamesize)) {
>   			fwts_warning(fw, "UEFIRuntimeGetNextVariableName "
>   				"Unexpected variable name size returned.");
> -			goto err;
> +			ret = FWTS_ERROR;
> +			break;
>   		}
>   	};
>   
> -	return FWTS_OK;
> -
> -err:
> -	return FWTS_ERROR;
> +	if (variablename)
> +		free(variablename);
> +	return ret;
>   }
>   
>   struct efi_var_item {
> @@ -564,9 +630,17 @@ static int getnextvariable_test3(fwts_framework *fw)
>   
>   	struct efi_getnextvariablename getnextvariablename;
>   	uint64_t variablenamesize = MAX_DATA_LENGTH;
> -	uint16_t variablename[MAX_DATA_LENGTH];
> +	uint64_t maxvariablenamesize = variablenamesize;
> +	uint16_t *variablename;
>   	EFI_GUID vendorguid;
> -	char name[MAX_DATA_LENGTH];
> +	char *name;
> +	int ret;
> +
> +	variablename = malloc(sizeof(uint16_t) * variablenamesize);
> +	if (!variablename) {
> +		fwts_skipped(fw, "Unable to alloc memory for variable name");
> +		return FWTS_SKIP;
> +	}
>   
>   	getnextvariablename.VariableNameSize = &variablenamesize;
>   	getnextvariablename.VariableName = variablename;
> @@ -581,7 +655,7 @@ static int getnextvariable_test3(fwts_framework *fw)
>   	while (true) {
>   		struct efi_var_item *item;
>   
> -		variablenamesize = MAX_DATA_LENGTH;
> +		variablenamesize = maxvariablenamesize;
>   		ioret = ioctl(fd, EFI_RUNTIME_GET_NEXTVARIABLENAME, &getnextvariablename);
>   
>   		if (ioret == -1) {
> @@ -589,12 +663,31 @@ static int getnextvariable_test3(fwts_framework *fw)
>   			/* no next variable was found*/
>   			if (*getnextvariablename.status == EFI_NOT_FOUND)
>   				break;
> +			/*
> +			 * if the buffer we provided is too small for the name,
> +			 * allocate a larger buffer and try again
> +			 */
> +			if (*getnextvariablename.status == EFI_BUFFER_TOO_SMALL) {
> +				uint16_t *tmp;
> +				tmp = realloc(variablename,
> +					      sizeof(uint16_t) * variablenamesize);
> +				 if (tmp) {
> +					variablename = tmp;
> +					getnextvariablename.VariableName = variablename;
> +					maxvariablenamesize = variablenamesize;
> +					continue;
> +				}
> +				fwts_skipped(fw, "Unable to reallocate memory for variable name");
> +				ret = FWTS_SKIP;
> +				goto err;
> +			}
>   
>   			fwts_failed(fw, LOG_LEVEL_HIGH,
>   				"UEFIRuntimeGetNextVariableName",
>   				"Failed to get next variable name with UEFI "
>   				"runtime service.");
>   			fwts_uefi_print_status_info(fw, status);
> +			ret = FWTS_ERROR;
>   			goto err;
>   		}
>   
> @@ -603,6 +696,7 @@ static int getnextvariable_test3(fwts_framework *fw)
>   			fwts_failed(fw, LOG_LEVEL_HIGH,
>   				"UEFIRuntimeGetNextVariableName",
>   				"Failed to allocate memory for test.");
> +			ret = FWTS_ERROR;
>   			goto err;
>   		}
>   
> @@ -612,6 +706,7 @@ static int getnextvariable_test3(fwts_framework *fw)
>   				"UEFIRuntimeGetNextVariableName",
>   				"Failed to allocate memory for test.");
>   			free(item);
> +			ret = FWTS_ERROR;
>   			goto err;
>   		}
>   
> @@ -625,6 +720,7 @@ static int getnextvariable_test3(fwts_framework *fw)
>   				"Failed to allocate memory for test.");
>   			free(item->guid);
>   			free(item);
> +			ret = FWTS_ERROR;
>   			goto err;
>   		}
>   
> @@ -634,23 +730,31 @@ static int getnextvariable_test3(fwts_framework *fw)
>   		item->hash = hash_func(variablename, variablenamesize);
>   
>   		if (bucket_insert(item)) {
> -			fwts_uefi_str16_to_str(name, sizeof(name), variablename);
> -			fwts_failed(fw, LOG_LEVEL_HIGH,
> -				"UEFIRuntimeGetNextVariableName",
> -				"Duplicate variable name %s found.", name);
> +			name = malloc(variablenamesize * sizeof(char));
> +			if (name) {
> +				fwts_uefi_str16_to_str(name, sizeof(name), variablename);
> +				fwts_failed(fw, LOG_LEVEL_HIGH,
> +					"UEFIRuntimeGetNextVariableName",
> +					"Duplicate variable name %s found.", name);
> +				free(name);
> +			} else
> +				fwts_failed(fw, LOG_LEVEL_HIGH,
> +					"UEFIRuntimeGetNextVariableName",
> +					"Duplicate variable name found (too long name).");
>   			free(item->name);
>   			free(item->guid);
>   			free(item);
> +			ret = FWTS_ERROR;
>   			goto err;
>   		}
>   	};
>   
> -	bucket_destroy();
> -	return FWTS_OK;
> -
> +	ret = FWTS_OK;
>   err:
>   	bucket_destroy();
> -	return FWTS_ERROR;
> +	if (variablename)
> +		free(variablename);
> +	return ret;
>   }
>   
>   static int getnextvariable_test4(fwts_framework *fw)

Acked-by: Ivan Hu <ivan.hu at canonical.com>



More information about the fwts-devel mailing list