MODULE_VERSION(EFIVARS_VERSION);
#define DUMP_NAME_LEN 52
-#define GUID_LEN 37
+
+/*
+ * Length of a GUID string (strlen("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"))
+ * not including trailing NUL
+ */
+#define GUID_LEN 36
/*
* The maximum size of VariableName + Data = 1024
goto out;
}
+ /*
+ * The lock here protects the get_variable call, the conditional
+ * set_variable call, and removal of the variable from the efivars
+ * list (in the case of an authenticated delete).
+ */
+ spin_lock(&efivars->lock);
+
status = efivars->ops->set_variable(var->var.VariableName,
&var->var.VendorGuid,
attributes, datasize,
data);
- switch (status) {
- case EFI_SUCCESS:
- break;
- case EFI_INVALID_PARAMETER:
- count = -EINVAL;
- goto out;
- case EFI_OUT_OF_RESOURCES:
- count = -ENOSPC;
- goto out;
- case EFI_DEVICE_ERROR:
- count = -EIO;
- goto out;
- case EFI_WRITE_PROTECTED:
- count = -EROFS;
- goto out;
- case EFI_SECURITY_VIOLATION:
- count = -EACCES;
- goto out;
- case EFI_NOT_FOUND:
- count = -ENOENT;
- goto out;
- default:
- count = -EINVAL;
- goto out;
+ if (status != EFI_SUCCESS) {
+ spin_unlock(&efivars->lock);
+ kfree(data);
+
+ switch (status) {
+ case EFI_INVALID_PARAMETER:
+ count = -EINVAL;
+ break;
+ case EFI_OUT_OF_RESOURCES:
+ count = -ENOSPC;
+ break;
+ case EFI_DEVICE_ERROR:
+ count = -EIO;
+ break;
+ case EFI_WRITE_PROTECTED:
+ count = -EROFS;
+ break;
+ case EFI_SECURITY_VIOLATION:
+ count = -EACCES;
+ break;
+ case EFI_NOT_FOUND:
+ count = -ENOENT;
+ break;
+ default:
+ count = -EINVAL;
+ }
+ return count;
}
/*
NULL);
if (status == EFI_BUFFER_TOO_SMALL) {
+ spin_unlock(&efivars->lock);
mutex_lock(&inode->i_mutex);
i_size_write(inode, newdatasize + sizeof(attributes));
mutex_unlock(&inode->i_mutex);
} else if (status == EFI_NOT_FOUND) {
- spin_lock(&efivars->lock);
list_del(&var->list);
spin_unlock(&efivars->lock);
efivar_unregister(var);
dput(file->f_dentry);
} else {
+ spin_unlock(&efivars->lock);
pr_warn("efivarfs: inconsistent EFI variable implementation? "
"status = %lx\n", status);
}
void *data;
ssize_t size = 0;
+ spin_lock(&efivars->lock);
status = efivars->ops->get_variable(var->var.VariableName,
&var->var.VendorGuid,
&attributes, &datasize, NULL);
+ spin_unlock(&efivars->lock);
if (status != EFI_BUFFER_TOO_SMALL)
return 0;
if (!data)
return 0;
+ spin_lock(&efivars->lock);
status = efivars->ops->get_variable(var->var.VariableName,
&var->var.VendorGuid,
&attributes, &datasize,
(data + 4));
+ spin_unlock(&efivars->lock);
+
if (status != EFI_SUCCESS)
goto out_free;
static int efivarfs_create(struct inode *dir, struct dentry *dentry,
umode_t mode, bool excl)
{
- struct inode *inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
+ struct inode *inode;
struct efivars *efivars = &__efivars;
struct efivar_entry *var;
int namelen, i = 0, err = 0;
- if (dentry->d_name.len < 38)
+ /*
+ * We need a GUID, plus at least one letter for the variable name,
+ * plus the '-' separator
+ */
+ if (dentry->d_name.len < GUID_LEN + 2)
return -EINVAL;
+ inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
if (!inode)
return -ENOSPC;
var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
+ if (!var) {
+ err = -ENOMEM;
+ goto out;
+ }
- if (!var)
- return -ENOMEM;
-
- namelen = dentry->d_name.len - GUID_LEN;
+ /* length of the variable name itself: remove GUID and separator */
+ namelen = dentry->d_name.len - GUID_LEN - 1;
efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1,
&var->var.VendorGuid);
d_instantiate(dentry, inode);
dget(dentry);
out:
- if (err)
+ if (err) {
kfree(var);
+ iput(inode);
+ }
return err;
}
struct dentry *root;
struct efivar_entry *entry, *n;
struct efivars *efivars = &__efivars;
- int err;
+ char *name;
efivarfs_sb = sb;
sb->s_time_gran = 1;
inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0);
- if (!inode) {
- err = -ENOMEM;
- goto fail;
- }
+ if (!inode)
+ return -ENOMEM;
inode->i_op = &efivarfs_dir_inode_operations;
root = d_make_root(inode);
sb->s_root = root;
- if (!root) {
- err = -ENOMEM;
- goto fail;
- }
+ if (!root)
+ return -ENOMEM;
list_for_each_entry_safe(entry, n, &efivars->list, list) {
- struct inode *inode;
struct dentry *dentry, *root = efivarfs_sb->s_root;
- char *name;
unsigned long size = 0;
int len, i;
+ inode = NULL;
+
len = utf16_strlen(entry->var.VariableName);
- /* GUID plus trailing NULL */
- name = kmalloc(len + 38, GFP_ATOMIC);
+ /* name, plus '-', plus GUID, plus NUL*/
+ name = kmalloc(len + 1 + GUID_LEN + 1, GFP_ATOMIC);
+ if (!name)
+ goto fail;
for (i = 0; i < len; i++)
name[i] = entry->var.VariableName[i] & 0xFF;
efi_guid_unparse(&entry->var.VendorGuid, name + len + 1);
- name[len+GUID_LEN] = '\0';
+ name[len+GUID_LEN+1] = '\0';
inode = efivarfs_get_inode(efivarfs_sb, root->d_inode,
S_IFREG | 0644, 0);
+ if (!inode)
+ goto fail_name;
+
dentry = d_alloc_name(root, name);
+ if (!dentry)
+ goto fail_inode;
+ /* copied by the above to local storage in the dentry. */
+ kfree(name);
+
+ spin_lock(&efivars->lock);
efivars->ops->get_variable(entry->var.VariableName,
&entry->var.VendorGuid,
&entry->var.Attributes,
&size,
NULL);
+ spin_unlock(&efivars->lock);
mutex_lock(&inode->i_mutex);
inode->i_private = entry;
}
return 0;
-fail:
+
+fail_inode:
iput(inode);
- return err;
+fail_name:
+ kfree(name);
+fail:
+ return -ENOMEM;
}
static struct dentry *efivarfs_mount(struct file_system_type *fs_type,
efi_char16_t *variable_name,
efi_guid_t *vendor_guid)
{
- int i, short_name_size = variable_name_size / sizeof(efi_char16_t) + 38;
+ int i, short_name_size;
char *short_name;
struct efivar_entry *new_efivar;
- short_name = kzalloc(short_name_size + 1, GFP_KERNEL);
+ /*
+ * Length of the variable bytes in ASCII, plus the '-' separator,
+ * plus the GUID, plus trailing NUL
+ */
+ short_name_size = variable_name_size / sizeof(efi_char16_t)
+ + 1 + GUID_LEN + 1;
+
+ short_name = kzalloc(short_name_size, GFP_KERNEL);
new_efivar = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
if (!short_name || !new_efivar) {