aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/efivars.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware/efivars.c')
-rw-r--r--drivers/firmware/efivars.c98
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 *);
172static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries); 173static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);
173static bool efivar_wq_enabled = true; 174static bool efivar_wq_enabled = true;
174 175
175/* Return the number of unicode characters in data */
176static unsigned long
177utf16_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
186static inline unsigned long
187utf16_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 */
196static inline unsigned long
197utf16_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
202static inline int
203utf16_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
220static bool 176static bool
221validate_device_path(struct efi_variable *var, int match, u8 *buffer, 177validate_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
436check_var_size_locked(struct efivars *efivars, u32 attributes, 392check_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)