bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, unsigned long data_size) { int i; 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].name[0] != '\0'; i++) { const char *name = variable_validate[i].name; int match = 0; if (efi_guidcmp(vendor, variable_validate[i].vendor)) continue; if (variable_matches(utf8_name, utf8_size+1, name, &match)) { if (variable_validate[i].validate == NULL) break; kfree(utf8_name); return variable_validate[i].validate(var_name, match, data, data_size); } } kfree(utf8_name); return true; }
/** * efivar_create_sysfs_entry - create a new entry in sysfs * @new_var: efivar entry to create * * Returns 0 on success, negative error code on failure */ static int efivar_create_sysfs_entry(struct efivar_entry *new_var) { int short_name_size; char *short_name; unsigned long utf8_name_size; efi_char16_t *variable_name = new_var->var.VariableName; int ret; /* * Length of the variable bytes in UTF8, plus the '-' separator, * plus the GUID, plus trailing NUL */ utf8_name_size = ucs2_utf8size(variable_name); short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1; short_name = kmalloc(short_name_size, GFP_KERNEL); if (!short_name) return -ENOMEM; ucs2_as_utf8(short_name, variable_name, short_name_size); /* This is ugly, but necessary to separate one vendor's private variables from another's. */ short_name[utf8_name_size] = '-'; efi_guid_to_str(&new_var->var.VendorGuid, short_name + utf8_name_size + 1); new_var->kobj.kset = efivars_kset; ret = kobject_init_and_add(&new_var->kobj, &efivar_ktype, NULL, "%s", short_name); kfree(short_name); if (ret) return ret; kobject_uevent(&new_var->kobj, KOBJ_ADD); efivar_entry_add(new_var, &efivar_sysfs_list); return 0; }
static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, unsigned long name_size, void *data) { struct super_block *sb = (struct super_block *)data; struct efivar_entry *entry; struct inode *inode = NULL; struct dentry *dentry, *root = sb->s_root; unsigned long size = 0; char *name; int len; int err = -ENOMEM; bool is_removable = false; entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return err; memcpy(entry->var.VariableName, name16, name_size); memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); len = ucs2_utf8size(entry->var.VariableName); /* name, plus '-', plus GUID, plus NUL*/ name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); if (!name) goto fail; ucs2_as_utf8(name, entry->var.VariableName, len); if (efivar_variable_is_removable(entry->var.VendorGuid, name, len)) is_removable = true; name[len] = '-'; efi_guid_unparse(&entry->var.VendorGuid, name + len + 1); name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0, is_removable); if (!inode) goto fail_name; dentry = efivarfs_alloc_dentry(root, name); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); goto fail_inode; } /* copied by the above to local storage in the dentry. */ kfree(name); efivar_entry_size(entry, &size); efivar_entry_add(entry, &efivarfs_list); mutex_lock(&inode->i_mutex); inode->i_private = entry; i_size_write(inode, size + sizeof(entry->var.Attributes)); mutex_unlock(&inode->i_mutex); d_add(dentry, inode); return 0; fail_inode: iput(inode); fail_name: kfree(name); fail: kfree(entry); return err; }