Commit 3285d6ab 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 84603ed7
...@@ -219,7 +219,7 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) ...@@ -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 || 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"); printk(KERN_ERR "efivars: Malformed variable content\n");
return -EINVAL; return -EINVAL;
} }
...@@ -334,7 +334,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, ...@@ -334,7 +334,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
return -EACCES; return -EACCES;
if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || 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"); printk(KERN_ERR "efivars: Malformed variable content\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -42,7 +42,7 @@ DECLARE_WORK(efivar_work, NULL); ...@@ -42,7 +42,7 @@ DECLARE_WORK(efivar_work, NULL);
EXPORT_SYMBOL_GPL(efivar_work); EXPORT_SYMBOL_GPL(efivar_work);
static bool 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) unsigned long len)
{ {
struct efi_generic_dev_path *node; struct efi_generic_dev_path *node;
...@@ -75,7 +75,7 @@ validate_device_path(struct efi_variable *var, int match, u8 *buffer, ...@@ -75,7 +75,7 @@ validate_device_path(struct efi_variable *var, int match, u8 *buffer,
} }
static bool 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) unsigned long len)
{ {
/* An array of 16-bit integers */ /* An array of 16-bit integers */
...@@ -86,18 +86,18 @@ validate_boot_order(struct efi_variable *var, int match, u8 *buffer, ...@@ -86,18 +86,18 @@ validate_boot_order(struct efi_variable *var, int match, u8 *buffer,
} }
static bool 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) unsigned long len)
{ {
u16 filepathlength; u16 filepathlength;
int i, desclength = 0, namelen; 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 */ /* Either "Boot" or "Driver" followed by four digits of hex */
for (i = match; i < match+4; i++) { for (i = match; i < match+4; i++) {
if (var->VariableName[i] > 127 || if (var_name[i] > 127 ||
hex_to_bin(var->VariableName[i] & 0xff) < 0) hex_to_bin(var_name[i] & 0xff) < 0)
return true; return true;
} }
...@@ -132,12 +132,12 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer, ...@@ -132,12 +132,12 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer,
/* /*
* And, finally, check the filepath * 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); filepathlength);
} }
static bool 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) unsigned long len)
{ {
/* A single 16-bit integer */ /* A single 16-bit integer */
...@@ -148,7 +148,7 @@ validate_uint16(struct efi_variable *var, int match, u8 *buffer, ...@@ -148,7 +148,7 @@ validate_uint16(struct efi_variable *var, int match, u8 *buffer,
} }
static bool 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) unsigned long len)
{ {
int i; int i;
...@@ -166,7 +166,7 @@ validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, ...@@ -166,7 +166,7 @@ validate_ascii_string(struct efi_variable *var, int match, u8 *buffer,
struct variable_validate { struct variable_validate {
char *name; 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); unsigned long len);
}; };
...@@ -189,10 +189,19 @@ static const struct variable_validate variable_validate[] = { ...@@ -189,10 +189,19 @@ static const struct variable_validate variable_validate[] = {
}; };
bool 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; 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++) { for (i = 0; variable_validate[i].validate != NULL; i++) {
const char *name = variable_validate[i].name; const char *name = variable_validate[i].name;
...@@ -200,28 +209,29 @@ efivar_validate(struct efi_variable *var, u8 *data, unsigned long len) ...@@ -200,28 +209,29 @@ efivar_validate(struct efi_variable *var, u8 *data, unsigned long len)
for (match = 0; ; match++) { for (match = 0; ; match++) {
char c = name[match]; char c = name[match];
u16 u = unicode_name[match]; char u = utf8_name[match];
/* All special variables are plain ascii */
if (u > 127)
return true;
/* Wildcard in the matching name means we've matched */ /* Wildcard in the matching name means we've matched */
if (c == '*') if (c == '*') {
return variable_validate[i].validate(var, kfree(utf8_name);
match, data, len); return variable_validate[i].validate(var_name,
match, data, data_size);
}
/* Case sensitive match */ /* Case sensitive match */
if (c != u) if (c != u)
break; break;
/* Reached the end of the string while matching */ /* Reached the end of the string while matching */
if (!c) if (!c) {
return variable_validate[i].validate(var, kfree(utf8_name);
match, data, len); return variable_validate[i].validate(var_name,
match, data, data_size);
}
} }
} }
kfree(utf8_name);
return true; return true;
} }
EXPORT_SYMBOL_GPL(efivar_validate); EXPORT_SYMBOL_GPL(efivar_validate);
...@@ -805,7 +815,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, ...@@ -805,7 +815,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
*set = false; *set = false;
if (efivar_validate(&entry->var, data, *size) == false) if (efivar_validate(name, data, *size) == false)
return -EINVAL; return -EINVAL;
/* /*
......
...@@ -792,8 +792,10 @@ struct efivars { ...@@ -792,8 +792,10 @@ struct efivars {
* and we use a page for reading/writing. * and we use a page for reading/writing.
*/ */
#define EFI_VAR_NAME_LEN 1024
struct efi_variable { 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; efi_guid_t VendorGuid;
unsigned long DataSize; unsigned long DataSize;
__u8 Data[1024]; __u8 Data[1024];
...@@ -864,7 +866,7 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), ...@@ -864,7 +866,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 efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
struct list_head *head, bool remove); 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; extern struct work_struct efivar_work;
void efivar_run_worker(void); 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