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.c131
1 files changed, 97 insertions, 34 deletions
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 7320bf891706..fe62aa392239 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -426,6 +426,44 @@ get_var_data(struct efivars *efivars, struct efi_variable *var)
426 return status; 426 return status;
427} 427}
428 428
429static efi_status_t
430check_var_size_locked(struct efivars *efivars, u32 attributes,
431 unsigned long size)
432{
433 u64 storage_size, remaining_size, max_size;
434 efi_status_t status;
435 const struct efivar_operations *fops = efivars->ops;
436
437 if (!efivars->ops->query_variable_info)
438 return EFI_UNSUPPORTED;
439
440 status = fops->query_variable_info(attributes, &storage_size,
441 &remaining_size, &max_size);
442
443 if (status != EFI_SUCCESS)
444 return status;
445
446 if (!storage_size || size > remaining_size || size > max_size ||
447 (remaining_size - size) < (storage_size / 2))
448 return EFI_OUT_OF_RESOURCES;
449
450 return status;
451}
452
453
454static efi_status_t
455check_var_size(struct efivars *efivars, u32 attributes, unsigned long size)
456{
457 efi_status_t status;
458 unsigned long flags;
459
460 spin_lock_irqsave(&efivars->lock, flags);
461 status = check_var_size_locked(efivars, attributes, size);
462 spin_unlock_irqrestore(&efivars->lock, flags);
463
464 return status;
465}
466
429static ssize_t 467static ssize_t
430efivar_guid_read(struct efivar_entry *entry, char *buf) 468efivar_guid_read(struct efivar_entry *entry, char *buf)
431{ 469{
@@ -547,11 +585,16 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
547 } 585 }
548 586
549 spin_lock_irq(&efivars->lock); 587 spin_lock_irq(&efivars->lock);
550 status = efivars->ops->set_variable(new_var->VariableName, 588
551 &new_var->VendorGuid, 589 status = check_var_size_locked(efivars, new_var->Attributes,
552 new_var->Attributes, 590 new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
553 new_var->DataSize, 591
554 new_var->Data); 592 if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED)
593 status = efivars->ops->set_variable(new_var->VariableName,
594 &new_var->VendorGuid,
595 new_var->Attributes,
596 new_var->DataSize,
597 new_var->Data);
555 598
556 spin_unlock_irq(&efivars->lock); 599 spin_unlock_irq(&efivars->lock);
557 600
@@ -702,8 +745,7 @@ static ssize_t efivarfs_file_write(struct file *file,
702 u32 attributes; 745 u32 attributes;
703 struct inode *inode = file->f_mapping->host; 746 struct inode *inode = file->f_mapping->host;
704 unsigned long datasize = count - sizeof(attributes); 747 unsigned long datasize = count - sizeof(attributes);
705 unsigned long newdatasize; 748 unsigned long newdatasize, varsize;
706 u64 storage_size, remaining_size, max_size;
707 ssize_t bytes = 0; 749 ssize_t bytes = 0;
708 750
709 if (count < sizeof(attributes)) 751 if (count < sizeof(attributes))
@@ -722,28 +764,18 @@ static ssize_t efivarfs_file_write(struct file *file,
722 * amounts of memory. Pick a default size of 64K if 764 * amounts of memory. Pick a default size of 64K if
723 * QueryVariableInfo() isn't supported by the firmware. 765 * QueryVariableInfo() isn't supported by the firmware.
724 */ 766 */
725 spin_lock_irq(&efivars->lock);
726
727 if (!efivars->ops->query_variable_info)
728 status = EFI_UNSUPPORTED;
729 else {
730 const struct efivar_operations *fops = efivars->ops;
731 status = fops->query_variable_info(attributes, &storage_size,
732 &remaining_size, &max_size);
733 }
734 767
735 spin_unlock_irq(&efivars->lock); 768 varsize = datasize + utf16_strsize(var->var.VariableName, 1024);
769 status = check_var_size(efivars, attributes, varsize);
736 770
737 if (status != EFI_SUCCESS) { 771 if (status != EFI_SUCCESS) {
738 if (status != EFI_UNSUPPORTED) 772 if (status != EFI_UNSUPPORTED)
739 return efi_status_to_err(status); 773 return efi_status_to_err(status);
740 774
741 remaining_size = 65536; 775 if (datasize > 65536)
776 return -ENOSPC;
742 } 777 }
743 778
744 if (datasize > remaining_size)
745 return -ENOSPC;
746
747 data = kmalloc(datasize, GFP_KERNEL); 779 data = kmalloc(datasize, GFP_KERNEL);
748 if (!data) 780 if (!data)
749 return -ENOMEM; 781 return -ENOMEM;
@@ -765,6 +797,19 @@ static ssize_t efivarfs_file_write(struct file *file,
765 */ 797 */
766 spin_lock_irq(&efivars->lock); 798 spin_lock_irq(&efivars->lock);
767 799
800 /*
801 * Ensure that the available space hasn't shrunk below the safe level
802 */
803
804 status = check_var_size_locked(efivars, attributes, varsize);
805
806 if (status != EFI_SUCCESS && status != EFI_UNSUPPORTED) {
807 spin_unlock_irq(&efivars->lock);
808 kfree(data);
809
810 return efi_status_to_err(status);
811 }
812
768 status = efivars->ops->set_variable(var->var.VariableName, 813 status = efivars->ops->set_variable(var->var.VariableName,
769 &var->var.VendorGuid, 814 &var->var.VendorGuid,
770 attributes, datasize, 815 attributes, datasize,
@@ -929,8 +974,8 @@ static bool efivarfs_valid_name(const char *str, int len)
929 if (len < GUID_LEN + 2) 974 if (len < GUID_LEN + 2)
930 return false; 975 return false;
931 976
932 /* GUID should be right after the first '-' */ 977 /* GUID must be preceded by a '-' */
933 if (s - 1 != strchr(str, '-')) 978 if (*(s - 1) != '-')
934 return false; 979 return false;
935 980
936 /* 981 /*
@@ -1118,15 +1163,22 @@ static struct dentry_operations efivarfs_d_ops = {
1118 1163
1119static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name) 1164static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
1120{ 1165{
1166 struct dentry *d;
1121 struct qstr q; 1167 struct qstr q;
1168 int err;
1122 1169
1123 q.name = name; 1170 q.name = name;
1124 q.len = strlen(name); 1171 q.len = strlen(name);
1125 1172
1126 if (efivarfs_d_hash(NULL, NULL, &q)) 1173 err = efivarfs_d_hash(NULL, NULL, &q);
1127 return NULL; 1174 if (err)
1175 return ERR_PTR(err);
1176
1177 d = d_alloc(parent, &q);
1178 if (d)
1179 return d;
1128 1180
1129 return d_alloc(parent, &q); 1181 return ERR_PTR(-ENOMEM);
1130} 1182}
1131 1183
1132static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) 1184static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
@@ -1136,6 +1188,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
1136 struct efivar_entry *entry, *n; 1188 struct efivar_entry *entry, *n;
1137 struct efivars *efivars = &__efivars; 1189 struct efivars *efivars = &__efivars;
1138 char *name; 1190 char *name;
1191 int err = -ENOMEM;
1139 1192
1140 efivarfs_sb = sb; 1193 efivarfs_sb = sb;
1141 1194
@@ -1186,8 +1239,10 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
1186 goto fail_name; 1239 goto fail_name;
1187 1240
1188 dentry = efivarfs_alloc_dentry(root, name); 1241 dentry = efivarfs_alloc_dentry(root, name);
1189 if (!dentry) 1242 if (IS_ERR(dentry)) {
1243 err = PTR_ERR(dentry);
1190 goto fail_inode; 1244 goto fail_inode;
1245 }
1191 1246
1192 /* copied by the above to local storage in the dentry. */ 1247 /* copied by the above to local storage in the dentry. */
1193 kfree(name); 1248 kfree(name);
@@ -1214,7 +1269,7 @@ fail_inode:
1214fail_name: 1269fail_name:
1215 kfree(name); 1270 kfree(name);
1216fail: 1271fail:
1217 return -ENOMEM; 1272 return err;
1218} 1273}
1219 1274
1220static struct dentry *efivarfs_mount(struct file_system_type *fs_type, 1275static struct dentry *efivarfs_mount(struct file_system_type *fs_type,
@@ -1234,6 +1289,7 @@ static struct file_system_type efivarfs_type = {
1234 .mount = efivarfs_mount, 1289 .mount = efivarfs_mount,
1235 .kill_sb = efivarfs_kill_sb, 1290 .kill_sb = efivarfs_kill_sb,
1236}; 1291};
1292MODULE_ALIAS_FS("efivarfs");
1237 1293
1238/* 1294/*
1239 * Handle negative dentry. 1295 * Handle negative dentry.
@@ -1345,7 +1401,6 @@ static int efi_pstore_write(enum pstore_type_id type,
1345 efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 1401 efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
1346 struct efivars *efivars = psi->data; 1402 struct efivars *efivars = psi->data;
1347 int i, ret = 0; 1403 int i, ret = 0;
1348 u64 storage_space, remaining_space, max_variable_size;
1349 efi_status_t status = EFI_NOT_FOUND; 1404 efi_status_t status = EFI_NOT_FOUND;
1350 unsigned long flags; 1405 unsigned long flags;
1351 1406
@@ -1365,11 +1420,11 @@ static int efi_pstore_write(enum pstore_type_id type,
1365 * size: a size of logging data 1420 * size: a size of logging data
1366 * DUMP_NAME_LEN * 2: a maximum size of variable name 1421 * DUMP_NAME_LEN * 2: a maximum size of variable name
1367 */ 1422 */
1368 status = efivars->ops->query_variable_info(PSTORE_EFI_ATTRIBUTES, 1423
1369 &storage_space, 1424 status = check_var_size_locked(efivars, PSTORE_EFI_ATTRIBUTES,
1370 &remaining_space, 1425 size + DUMP_NAME_LEN * 2);
1371 &max_variable_size); 1426
1372 if (status || remaining_space < size + DUMP_NAME_LEN * 2) { 1427 if (status) {
1373 spin_unlock_irqrestore(&efivars->lock, flags); 1428 spin_unlock_irqrestore(&efivars->lock, flags);
1374 *id = part; 1429 *id = part;
1375 return -ENOSPC; 1430 return -ENOSPC;
@@ -1544,6 +1599,14 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
1544 return -EINVAL; 1599 return -EINVAL;
1545 } 1600 }
1546 1601
1602 status = check_var_size_locked(efivars, new_var->Attributes,
1603 new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
1604
1605 if (status && status != EFI_UNSUPPORTED) {
1606 spin_unlock_irq(&efivars->lock);
1607 return efi_status_to_err(status);
1608 }
1609
1547 /* now *really* create the variable via EFI */ 1610 /* now *really* create the variable via EFI */
1548 status = efivars->ops->set_variable(new_var->VariableName, 1611 status = efivars->ops->set_variable(new_var->VariableName,
1549 &new_var->VendorGuid, 1612 &new_var->VendorGuid,