Commit 44f21ed1 authored by Peter Jones's avatar Peter Jones Committed by Greg Kroah-Hartman

efi: Do variable name validation tests in utf8

commit 3dcb1f55 upstream.

Actually translate from ucs2 to utf8 before doing the test, and then
test against our other utf8 data, instead of fudging it.
Signed-off-by: default avatarPeter Jones <pjones@redhat.com>
Acked-by: default avatarMatthew Garrett <mjg59@coreos.com>
Tested-by: default avatarLee, Chun-Yi <jlee@suse.com>
Signed-off-by: default avatarMatt Fleming <matt@codeblueprint.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c6d535a3
......@@ -219,7 +219,7 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
}
if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) {
efivar_validate(new_var->VariableName, new_var->Data, new_var->DataSize) == false) {
printk(KERN_ERR "efivars: Malformed variable content\n");
return -EINVAL;
}
......@@ -334,7 +334,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
return -EACCES;
if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) {
efivar_validate(new_var->VariableName, new_var->Data, new_var->DataSize) == false) {
printk(KERN_ERR "efivars: Malformed variable content\n");
return -EINVAL;
}
......
......@@ -42,7 +42,7 @@ DECLARE_WORK(efivar_work, NULL);
EXPORT_SYMBOL_GPL(efivar_work);
static bool
validate_device_path(struct efi_variable *var, int match, u8 *buffer,
validate_device_path(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
struct efi_generic_dev_path *node;
......@@ -75,7 +75,7 @@ validate_device_path(struct efi_variable *var, int match, u8 *buffer,
}
static bool
validate_boot_order(struct efi_variable *var, int match, u8 *buffer,
validate_boot_order(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
/* An array of 16-bit integers */
......@@ -86,18 +86,18 @@ validate_boot_order(struct efi_variable *var, int match, u8 *buffer,
}
static bool
validate_load_option(struct efi_variable *var, int match, u8 *buffer,
validate_load_option(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
u16 filepathlength;
int i, desclength = 0, namelen;
namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName));
namelen = ucs2_strnlen(var_name, EFI_VAR_NAME_LEN);
/* Either "Boot" or "Driver" followed by four digits of hex */
for (i = match; i < match+4; i++) {
if (var->VariableName[i] > 127 ||
hex_to_bin(var->VariableName[i] & 0xff) < 0)
if (var_name[i] > 127 ||
hex_to_bin(var_name[i] & 0xff) < 0)
return true;
}
......@@ -132,12 +132,12 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer,
/*
* And, finally, check the filepath
*/
return validate_device_path(var, match, buffer + desclength + 6,
return validate_device_path(var_name, match, buffer + desclength + 6,
filepathlength);
}
static bool
validate_uint16(struct efi_variable *var, int match, u8 *buffer,
validate_uint16(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
/* A single 16-bit integer */
......@@ -148,7 +148,7 @@ validate_uint16(struct efi_variable *var, int match, u8 *buffer,
}
static bool
validate_ascii_string(struct efi_variable *var, int match, u8 *buffer,
validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
int i;
......@@ -166,7 +166,7 @@ validate_ascii_string(struct efi_variable *var, int match, u8 *buffer,
struct variable_validate {
char *name;
bool (*validate)(struct efi_variable *var, int match, u8 *data,
bool (*validate)(efi_char16_t *var_name, int match, u8 *data,
unsigned long len);
};
......@@ -189,10 +189,19 @@ static const struct variable_validate variable_validate[] = {
};
bool
efivar_validate(struct efi_variable *var, u8 *data, unsigned long len)
efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long data_size)
{
int i;
u16 *unicode_name = var->VariableName;
unsigned long utf8_size;
u8 *utf8_name;
utf8_size = ucs2_utf8size(var_name);
utf8_name = kmalloc(utf8_size + 1, GFP_KERNEL);
if (!utf8_name)
return false;
ucs2_as_utf8(utf8_name, var_name, utf8_size);
utf8_name[utf8_size] = '\0';
for (i = 0; variable_validate[i].validate != NULL; i++) {
const char *name = variable_validate[i].name;
......@@ -200,28 +209,29 @@ efivar_validate(struct efi_variable *var, u8 *data, unsigned long len)
for (match = 0; ; match++) {
char c = name[match];
u16 u = unicode_name[match];
/* All special variables are plain ascii */
if (u > 127)
return true;
char u = utf8_name[match];
/* Wildcard in the matching name means we've matched */
if (c == '*')
return variable_validate[i].validate(var,
match, data, len);
if (c == '*') {
kfree(utf8_name);
return variable_validate[i].validate(var_name,
match, data, data_size);
}
/* Case sensitive match */
if (c != u)
break;
/* Reached the end of the string while matching */
if (!c)
return variable_validate[i].validate(var,
match, data, len);
if (!c) {
kfree(utf8_name);
return variable_validate[i].validate(var_name,
match, data, data_size);
}
}
}
kfree(utf8_name);
return true;
}
EXPORT_SYMBOL_GPL(efivar_validate);
......@@ -797,7 +807,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
*set = false;
if (efivar_validate(&entry->var, data, *size) == false)
if (efivar_validate(name, data, *size) == false)
return -EINVAL;
/*
......
......@@ -769,8 +769,10 @@ struct efivars {
* and we use a page for reading/writing.
*/
#define EFI_VAR_NAME_LEN 1024
struct efi_variable {
efi_char16_t VariableName[1024/sizeof(efi_char16_t)];
efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)];
efi_guid_t VendorGuid;
unsigned long DataSize;
__u8 Data[1024];
......@@ -832,7 +834,7 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
struct list_head *head, bool remove);
bool efivar_validate(struct efi_variable *var, u8 *data, unsigned long len);
bool efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len);
extern struct work_struct efivar_work;
void efivar_run_worker(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment