diff options
Diffstat (limited to 'drivers/firmware/efivars.c')
-rw-r--r-- | drivers/firmware/efivars.c | 98 |
1 files changed, 21 insertions, 77 deletions
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 7acafb80fd4c..182ce9471175 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c | |||
@@ -80,6 +80,7 @@ | |||
80 | #include <linux/slab.h> | 80 | #include <linux/slab.h> |
81 | #include <linux/pstore.h> | 81 | #include <linux/pstore.h> |
82 | #include <linux/ctype.h> | 82 | #include <linux/ctype.h> |
83 | #include <linux/ucs2_string.h> | ||
83 | 84 | ||
84 | #include <linux/fs.h> | 85 | #include <linux/fs.h> |
85 | #include <linux/ramfs.h> | 86 | #include <linux/ramfs.h> |
@@ -172,51 +173,6 @@ static void efivar_update_sysfs_entries(struct work_struct *); | |||
172 | static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries); | 173 | static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries); |
173 | static bool efivar_wq_enabled = true; | 174 | static bool efivar_wq_enabled = true; |
174 | 175 | ||
175 | /* Return the number of unicode characters in data */ | ||
176 | static unsigned long | ||
177 | utf16_strnlen(efi_char16_t *s, size_t maxlength) | ||
178 | { | ||
179 | unsigned long length = 0; | ||
180 | |||
181 | while (*s++ != 0 && length < maxlength) | ||
182 | length++; | ||
183 | return length; | ||
184 | } | ||
185 | |||
186 | static inline unsigned long | ||
187 | utf16_strlen(efi_char16_t *s) | ||
188 | { | ||
189 | return utf16_strnlen(s, ~0UL); | ||
190 | } | ||
191 | |||
192 | /* | ||
193 | * Return the number of bytes is the length of this string | ||
194 | * Note: this is NOT the same as the number of unicode characters | ||
195 | */ | ||
196 | static inline unsigned long | ||
197 | utf16_strsize(efi_char16_t *data, unsigned long maxlength) | ||
198 | { | ||
199 | return utf16_strnlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t); | ||
200 | } | ||
201 | |||
202 | static inline int | ||
203 | utf16_strncmp(const efi_char16_t *a, const efi_char16_t *b, size_t len) | ||
204 | { | ||
205 | while (1) { | ||
206 | if (len == 0) | ||
207 | return 0; | ||
208 | if (*a < *b) | ||
209 | return -1; | ||
210 | if (*a > *b) | ||
211 | return 1; | ||
212 | if (*a == 0) /* implies *b == 0 */ | ||
213 | return 0; | ||
214 | a++; | ||
215 | b++; | ||
216 | len--; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | static bool | 176 | static bool |
221 | validate_device_path(struct efi_variable *var, int match, u8 *buffer, | 177 | validate_device_path(struct efi_variable *var, int match, u8 *buffer, |
222 | unsigned long len) | 178 | unsigned long len) |
@@ -268,7 +224,7 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer, | |||
268 | u16 filepathlength; | 224 | u16 filepathlength; |
269 | int i, desclength = 0, namelen; | 225 | int i, desclength = 0, namelen; |
270 | 226 | ||
271 | namelen = utf16_strnlen(var->VariableName, sizeof(var->VariableName)); | 227 | namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName)); |
272 | 228 | ||
273 | /* Either "Boot" or "Driver" followed by four digits of hex */ | 229 | /* Either "Boot" or "Driver" followed by four digits of hex */ |
274 | for (i = match; i < match+4; i++) { | 230 | for (i = match; i < match+4; i++) { |
@@ -291,7 +247,7 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer, | |||
291 | * There's no stored length for the description, so it has to be | 247 | * There's no stored length for the description, so it has to be |
292 | * found by hand | 248 | * found by hand |
293 | */ | 249 | */ |
294 | desclength = utf16_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2; | 250 | desclength = ucs2_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2; |
295 | 251 | ||
296 | /* Each boot entry must have a descriptor */ | 252 | /* Each boot entry must have a descriptor */ |
297 | if (!desclength) | 253 | if (!desclength) |
@@ -436,24 +392,12 @@ static efi_status_t | |||
436 | check_var_size_locked(struct efivars *efivars, u32 attributes, | 392 | check_var_size_locked(struct efivars *efivars, u32 attributes, |
437 | unsigned long size) | 393 | unsigned long size) |
438 | { | 394 | { |
439 | u64 storage_size, remaining_size, max_size; | ||
440 | efi_status_t status; | ||
441 | const struct efivar_operations *fops = efivars->ops; | 395 | const struct efivar_operations *fops = efivars->ops; |
442 | 396 | ||
443 | if (!efivars->ops->query_variable_info) | 397 | if (!efivars->ops->query_variable_store) |
444 | return EFI_UNSUPPORTED; | 398 | return EFI_UNSUPPORTED; |
445 | 399 | ||
446 | status = fops->query_variable_info(attributes, &storage_size, | 400 | return fops->query_variable_store(attributes, size); |
447 | &remaining_size, &max_size); | ||
448 | |||
449 | if (status != EFI_SUCCESS) | ||
450 | return status; | ||
451 | |||
452 | if (!storage_size || size > remaining_size || size > max_size || | ||
453 | (remaining_size - size) < (storage_size / 2)) | ||
454 | return EFI_OUT_OF_RESOURCES; | ||
455 | |||
456 | return status; | ||
457 | } | 401 | } |
458 | 402 | ||
459 | 403 | ||
@@ -593,7 +537,7 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) | |||
593 | spin_lock_irq(&efivars->lock); | 537 | spin_lock_irq(&efivars->lock); |
594 | 538 | ||
595 | status = check_var_size_locked(efivars, new_var->Attributes, | 539 | status = check_var_size_locked(efivars, new_var->Attributes, |
596 | new_var->DataSize + utf16_strsize(new_var->VariableName, 1024)); | 540 | new_var->DataSize + ucs2_strsize(new_var->VariableName, 1024)); |
597 | 541 | ||
598 | if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED) | 542 | if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED) |
599 | status = efivars->ops->set_variable(new_var->VariableName, | 543 | status = efivars->ops->set_variable(new_var->VariableName, |
@@ -771,7 +715,7 @@ static ssize_t efivarfs_file_write(struct file *file, | |||
771 | * QueryVariableInfo() isn't supported by the firmware. | 715 | * QueryVariableInfo() isn't supported by the firmware. |
772 | */ | 716 | */ |
773 | 717 | ||
774 | varsize = datasize + utf16_strsize(var->var.VariableName, 1024); | 718 | varsize = datasize + ucs2_strsize(var->var.VariableName, 1024); |
775 | status = check_var_size(efivars, attributes, varsize); | 719 | status = check_var_size(efivars, attributes, varsize); |
776 | 720 | ||
777 | if (status != EFI_SUCCESS) { | 721 | if (status != EFI_SUCCESS) { |
@@ -1223,7 +1167,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) | |||
1223 | 1167 | ||
1224 | inode = NULL; | 1168 | inode = NULL; |
1225 | 1169 | ||
1226 | len = utf16_strlen(entry->var.VariableName); | 1170 | len = ucs2_strlen(entry->var.VariableName); |
1227 | 1171 | ||
1228 | /* name, plus '-', plus GUID, plus NUL*/ | 1172 | /* name, plus '-', plus GUID, plus NUL*/ |
1229 | name = kmalloc(len + 1 + GUID_LEN + 1, GFP_ATOMIC); | 1173 | name = kmalloc(len + 1 + GUID_LEN + 1, GFP_ATOMIC); |
@@ -1481,8 +1425,8 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | |||
1481 | 1425 | ||
1482 | if (efi_guidcmp(entry->var.VendorGuid, vendor)) | 1426 | if (efi_guidcmp(entry->var.VendorGuid, vendor)) |
1483 | continue; | 1427 | continue; |
1484 | if (utf16_strncmp(entry->var.VariableName, efi_name, | 1428 | if (ucs2_strncmp(entry->var.VariableName, efi_name, |
1485 | utf16_strlen(efi_name))) { | 1429 | ucs2_strlen(efi_name))) { |
1486 | /* | 1430 | /* |
1487 | * Check if an old format, | 1431 | * Check if an old format, |
1488 | * which doesn't support holding | 1432 | * which doesn't support holding |
@@ -1494,8 +1438,8 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | |||
1494 | for (i = 0; i < DUMP_NAME_LEN; i++) | 1438 | for (i = 0; i < DUMP_NAME_LEN; i++) |
1495 | efi_name_old[i] = name_old[i]; | 1439 | efi_name_old[i] = name_old[i]; |
1496 | 1440 | ||
1497 | if (utf16_strncmp(entry->var.VariableName, efi_name_old, | 1441 | if (ucs2_strncmp(entry->var.VariableName, efi_name_old, |
1498 | utf16_strlen(efi_name_old))) | 1442 | ucs2_strlen(efi_name_old))) |
1499 | continue; | 1443 | continue; |
1500 | } | 1444 | } |
1501 | 1445 | ||
@@ -1573,8 +1517,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | |||
1573 | * Does this variable already exist? | 1517 | * Does this variable already exist? |
1574 | */ | 1518 | */ |
1575 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { | 1519 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { |
1576 | strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); | 1520 | strsize1 = ucs2_strsize(search_efivar->var.VariableName, 1024); |
1577 | strsize2 = utf16_strsize(new_var->VariableName, 1024); | 1521 | strsize2 = ucs2_strsize(new_var->VariableName, 1024); |
1578 | if (strsize1 == strsize2 && | 1522 | if (strsize1 == strsize2 && |
1579 | !memcmp(&(search_efivar->var.VariableName), | 1523 | !memcmp(&(search_efivar->var.VariableName), |
1580 | new_var->VariableName, strsize1) && | 1524 | new_var->VariableName, strsize1) && |
@@ -1590,7 +1534,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | |||
1590 | } | 1534 | } |
1591 | 1535 | ||
1592 | status = check_var_size_locked(efivars, new_var->Attributes, | 1536 | status = check_var_size_locked(efivars, new_var->Attributes, |
1593 | new_var->DataSize + utf16_strsize(new_var->VariableName, 1024)); | 1537 | new_var->DataSize + ucs2_strsize(new_var->VariableName, 1024)); |
1594 | 1538 | ||
1595 | if (status && status != EFI_UNSUPPORTED) { | 1539 | if (status && status != EFI_UNSUPPORTED) { |
1596 | spin_unlock_irq(&efivars->lock); | 1540 | spin_unlock_irq(&efivars->lock); |
@@ -1614,7 +1558,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | |||
1614 | 1558 | ||
1615 | /* Create the entry in sysfs. Locking is not required here */ | 1559 | /* Create the entry in sysfs. Locking is not required here */ |
1616 | status = efivar_create_sysfs_entry(efivars, | 1560 | status = efivar_create_sysfs_entry(efivars, |
1617 | utf16_strsize(new_var->VariableName, | 1561 | ucs2_strsize(new_var->VariableName, |
1618 | 1024), | 1562 | 1024), |
1619 | new_var->VariableName, | 1563 | new_var->VariableName, |
1620 | &new_var->VendorGuid); | 1564 | &new_var->VendorGuid); |
@@ -1644,8 +1588,8 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, | |||
1644 | * Does this variable already exist? | 1588 | * Does this variable already exist? |
1645 | */ | 1589 | */ |
1646 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { | 1590 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { |
1647 | strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); | 1591 | strsize1 = ucs2_strsize(search_efivar->var.VariableName, 1024); |
1648 | strsize2 = utf16_strsize(del_var->VariableName, 1024); | 1592 | strsize2 = ucs2_strsize(del_var->VariableName, 1024); |
1649 | if (strsize1 == strsize2 && | 1593 | if (strsize1 == strsize2 && |
1650 | !memcmp(&(search_efivar->var.VariableName), | 1594 | !memcmp(&(search_efivar->var.VariableName), |
1651 | del_var->VariableName, strsize1) && | 1595 | del_var->VariableName, strsize1) && |
@@ -1691,9 +1635,9 @@ static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor) | |||
1691 | unsigned long strsize1, strsize2; | 1635 | unsigned long strsize1, strsize2; |
1692 | bool found = false; | 1636 | bool found = false; |
1693 | 1637 | ||
1694 | strsize1 = utf16_strsize(variable_name, 1024); | 1638 | strsize1 = ucs2_strsize(variable_name, 1024); |
1695 | list_for_each_entry_safe(entry, n, &efivars->list, list) { | 1639 | list_for_each_entry_safe(entry, n, &efivars->list, list) { |
1696 | strsize2 = utf16_strsize(entry->var.VariableName, 1024); | 1640 | strsize2 = ucs2_strsize(entry->var.VariableName, 1024); |
1697 | if (strsize1 == strsize2 && | 1641 | if (strsize1 == strsize2 && |
1698 | !memcmp(variable_name, &(entry->var.VariableName), | 1642 | !memcmp(variable_name, &(entry->var.VariableName), |
1699 | strsize2) && | 1643 | strsize2) && |
@@ -2131,7 +2075,7 @@ efivars_init(void) | |||
2131 | ops.get_variable = efi.get_variable; | 2075 | ops.get_variable = efi.get_variable; |
2132 | ops.set_variable = efi.set_variable; | 2076 | ops.set_variable = efi.set_variable; |
2133 | ops.get_next_variable = efi.get_next_variable; | 2077 | ops.get_next_variable = efi.get_next_variable; |
2134 | ops.query_variable_info = efi.query_variable_info; | 2078 | ops.query_variable_store = efi_query_variable_store; |
2135 | 2079 | ||
2136 | error = register_efivars(&__efivars, &ops, efi_kobj); | 2080 | error = register_efivars(&__efivars, &ops, efi_kobj); |
2137 | if (error) | 2081 | if (error) |