LCOV - code coverage report
Current view: top level - drivers/firmware/efi - efivars.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 4 334 1.2 %
Date: 2022-04-01 14:58:12 Functions: 1 21 4.8 %
Branches: 1 152 0.7 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0+
       2                 :            : /*
       3                 :            :  * Originally from efivars.c,
       4                 :            :  *
       5                 :            :  * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
       6                 :            :  * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
       7                 :            :  *
       8                 :            :  * This code takes all variables accessible from EFI runtime and
       9                 :            :  *  exports them via sysfs
      10                 :            :  */
      11                 :            : 
      12                 :            : #include <linux/efi.h>
      13                 :            : #include <linux/module.h>
      14                 :            : #include <linux/slab.h>
      15                 :            : #include <linux/ucs2_string.h>
      16                 :            : #include <linux/compat.h>
      17                 :            : 
      18                 :            : #define EFIVARS_VERSION "0.08"
      19                 :            : #define EFIVARS_DATE "2004-May-17"
      20                 :            : 
      21                 :            : MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
      22                 :            : MODULE_DESCRIPTION("sysfs interface to EFI Variables");
      23                 :            : MODULE_LICENSE("GPL");
      24                 :            : MODULE_VERSION(EFIVARS_VERSION);
      25                 :            : MODULE_ALIAS("platform:efivars");
      26                 :            : 
      27                 :            : LIST_HEAD(efivar_sysfs_list);
      28                 :            : EXPORT_SYMBOL_GPL(efivar_sysfs_list);
      29                 :            : 
      30                 :            : static struct kset *efivars_kset;
      31                 :            : 
      32                 :            : static struct bin_attribute *efivars_new_var;
      33                 :            : static struct bin_attribute *efivars_del_var;
      34                 :            : 
      35                 :            : struct compat_efi_variable {
      36                 :            :         efi_char16_t  VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)];
      37                 :            :         efi_guid_t    VendorGuid;
      38                 :            :         __u32         DataSize;
      39                 :            :         __u8          Data[1024];
      40                 :            :         __u32         Status;
      41                 :            :         __u32         Attributes;
      42                 :            : } __packed;
      43                 :            : 
      44                 :            : struct efivar_attribute {
      45                 :            :         struct attribute attr;
      46                 :            :         ssize_t (*show) (struct efivar_entry *entry, char *buf);
      47                 :            :         ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
      48                 :            : };
      49                 :            : 
      50                 :            : #define EFIVAR_ATTR(_name, _mode, _show, _store) \
      51                 :            : struct efivar_attribute efivar_attr_##_name = { \
      52                 :            :         .attr = {.name = __stringify(_name), .mode = _mode}, \
      53                 :            :         .show = _show, \
      54                 :            :         .store = _store, \
      55                 :            : };
      56                 :            : 
      57                 :            : #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
      58                 :            : #define to_efivar_entry(obj)  container_of(obj, struct efivar_entry, kobj)
      59                 :            : 
      60                 :            : /*
      61                 :            :  * Prototype for sysfs creation function
      62                 :            :  */
      63                 :            : static int
      64                 :            : efivar_create_sysfs_entry(struct efivar_entry *new_var);
      65                 :            : 
      66                 :            : static ssize_t
      67                 :          0 : efivar_guid_read(struct efivar_entry *entry, char *buf)
      68                 :            : {
      69                 :          0 :         struct efi_variable *var = &entry->var;
      70                 :          0 :         char *str = buf;
      71                 :            : 
      72         [ #  # ]:          0 :         if (!entry || !buf)
      73                 :            :                 return 0;
      74                 :            : 
      75                 :          0 :         efi_guid_to_str(&var->VendorGuid, str);
      76                 :          0 :         str += strlen(str);
      77                 :          0 :         str += sprintf(str, "\n");
      78                 :            : 
      79                 :          0 :         return str - buf;
      80                 :            : }
      81                 :            : 
      82                 :            : static ssize_t
      83                 :          0 : efivar_attr_read(struct efivar_entry *entry, char *buf)
      84                 :            : {
      85                 :          0 :         struct efi_variable *var = &entry->var;
      86                 :          0 :         unsigned long size = sizeof(var->Data);
      87                 :          0 :         char *str = buf;
      88                 :          0 :         int ret;
      89                 :            : 
      90         [ #  # ]:          0 :         if (!entry || !buf)
      91                 :            :                 return -EINVAL;
      92                 :            : 
      93                 :          0 :         ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
      94                 :          0 :         var->DataSize = size;
      95         [ #  # ]:          0 :         if (ret)
      96                 :            :                 return -EIO;
      97                 :            : 
      98         [ #  # ]:          0 :         if (var->Attributes & EFI_VARIABLE_NON_VOLATILE)
      99                 :          0 :                 str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n");
     100         [ #  # ]:          0 :         if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)
     101                 :          0 :                 str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n");
     102         [ #  # ]:          0 :         if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
     103                 :          0 :                 str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n");
     104         [ #  # ]:          0 :         if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
     105                 :          0 :                 str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n");
     106         [ #  # ]:          0 :         if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
     107                 :          0 :                 str += sprintf(str,
     108                 :            :                         "EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n");
     109         [ #  # ]:          0 :         if (var->Attributes &
     110                 :            :                         EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
     111                 :          0 :                 str += sprintf(str,
     112                 :            :                         "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n");
     113         [ #  # ]:          0 :         if (var->Attributes & EFI_VARIABLE_APPEND_WRITE)
     114                 :          0 :                 str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n");
     115                 :          0 :         return str - buf;
     116                 :            : }
     117                 :            : 
     118                 :            : static ssize_t
     119                 :          0 : efivar_size_read(struct efivar_entry *entry, char *buf)
     120                 :            : {
     121                 :          0 :         struct efi_variable *var = &entry->var;
     122                 :          0 :         unsigned long size = sizeof(var->Data);
     123                 :          0 :         char *str = buf;
     124                 :          0 :         int ret;
     125                 :            : 
     126         [ #  # ]:          0 :         if (!entry || !buf)
     127                 :            :                 return -EINVAL;
     128                 :            : 
     129                 :          0 :         ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
     130                 :          0 :         var->DataSize = size;
     131         [ #  # ]:          0 :         if (ret)
     132                 :            :                 return -EIO;
     133                 :            : 
     134                 :          0 :         str += sprintf(str, "0x%lx\n", var->DataSize);
     135                 :          0 :         return str - buf;
     136                 :            : }
     137                 :            : 
     138                 :            : static ssize_t
     139                 :          0 : efivar_data_read(struct efivar_entry *entry, char *buf)
     140                 :            : {
     141                 :          0 :         struct efi_variable *var = &entry->var;
     142                 :          0 :         unsigned long size = sizeof(var->Data);
     143                 :          0 :         int ret;
     144                 :            : 
     145         [ #  # ]:          0 :         if (!entry || !buf)
     146                 :            :                 return -EINVAL;
     147                 :            : 
     148                 :          0 :         ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
     149                 :          0 :         var->DataSize = size;
     150         [ #  # ]:          0 :         if (ret)
     151                 :            :                 return -EIO;
     152                 :            : 
     153                 :          0 :         memcpy(buf, var->Data, var->DataSize);
     154                 :          0 :         return var->DataSize;
     155                 :            : }
     156                 :            : 
     157                 :            : static inline int
     158                 :          0 : sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor,
     159                 :            :              unsigned long size, u32 attributes, u8 *data)
     160                 :            : {
     161                 :            :         /*
     162                 :            :          * If only updating the variable data, then the name
     163                 :            :          * and guid should remain the same
     164                 :            :          */
     165         [ #  # ]:          0 :         if (memcmp(name, var->VariableName, sizeof(var->VariableName)) ||
     166         [ #  # ]:          0 :                 efi_guidcmp(vendor, var->VendorGuid)) {
     167                 :          0 :                 printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n");
     168                 :          0 :                 return -EINVAL;
     169                 :            :         }
     170                 :            : 
     171         [ #  # ]:          0 :         if ((size <= 0) || (attributes == 0)){
     172                 :          0 :                 printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n");
     173                 :          0 :                 return -EINVAL;
     174                 :            :         }
     175                 :            : 
     176   [ #  #  #  # ]:          0 :         if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
     177                 :          0 :             efivar_validate(vendor, name, data, size) == false) {
     178                 :          0 :                 printk(KERN_ERR "efivars: Malformed variable content\n");
     179                 :          0 :                 return -EINVAL;
     180                 :            :         }
     181                 :            : 
     182                 :            :         return 0;
     183                 :            : }
     184                 :            : 
     185                 :            : static void
     186                 :          0 : copy_out_compat(struct efi_variable *dst, struct compat_efi_variable *src)
     187                 :            : {
     188                 :          0 :         memcpy(dst->VariableName, src->VariableName, EFI_VAR_NAME_LEN);
     189                 :          0 :         memcpy(dst->Data, src->Data, sizeof(src->Data));
     190                 :            : 
     191                 :          0 :         dst->VendorGuid = src->VendorGuid;
     192                 :          0 :         dst->DataSize = src->DataSize;
     193                 :          0 :         dst->Attributes = src->Attributes;
     194                 :          0 : }
     195                 :            : 
     196                 :            : /*
     197                 :            :  * We allow each variable to be edited via rewriting the
     198                 :            :  * entire efi variable structure.
     199                 :            :  */
     200                 :            : static ssize_t
     201                 :          0 : efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
     202                 :            : {
     203                 :          0 :         struct efi_variable *new_var, *var = &entry->var;
     204                 :          0 :         efi_char16_t *name;
     205                 :          0 :         unsigned long size;
     206                 :          0 :         efi_guid_t vendor;
     207                 :          0 :         u32 attributes;
     208                 :          0 :         u8 *data;
     209                 :          0 :         int err;
     210                 :            : 
     211         [ #  # ]:          0 :         if (!entry || !buf)
     212                 :            :                 return -EINVAL;
     213                 :            : 
     214   [ #  #  #  # ]:          0 :         if (in_compat_syscall()) {
     215                 :          0 :                 struct compat_efi_variable *compat;
     216                 :            : 
     217         [ #  # ]:          0 :                 if (count != sizeof(*compat))
     218                 :            :                         return -EINVAL;
     219                 :            : 
     220                 :          0 :                 compat = (struct compat_efi_variable *)buf;
     221                 :          0 :                 attributes = compat->Attributes;
     222                 :          0 :                 vendor = compat->VendorGuid;
     223                 :          0 :                 name = compat->VariableName;
     224                 :          0 :                 size = compat->DataSize;
     225                 :          0 :                 data = compat->Data;
     226                 :            : 
     227                 :          0 :                 err = sanity_check(var, name, vendor, size, attributes, data);
     228         [ #  # ]:          0 :                 if (err)
     229                 :          0 :                         return err;
     230                 :            : 
     231                 :          0 :                 copy_out_compat(&entry->var, compat);
     232                 :            :         } else {
     233         [ #  # ]:          0 :                 if (count != sizeof(struct efi_variable))
     234                 :            :                         return -EINVAL;
     235                 :            : 
     236                 :          0 :                 new_var = (struct efi_variable *)buf;
     237                 :            : 
     238                 :          0 :                 attributes = new_var->Attributes;
     239                 :          0 :                 vendor = new_var->VendorGuid;
     240                 :          0 :                 name = new_var->VariableName;
     241                 :          0 :                 size = new_var->DataSize;
     242                 :          0 :                 data = new_var->Data;
     243                 :            : 
     244                 :          0 :                 err = sanity_check(var, name, vendor, size, attributes, data);
     245         [ #  # ]:          0 :                 if (err)
     246                 :          0 :                         return err;
     247                 :            : 
     248                 :          0 :                 memcpy(&entry->var, new_var, count);
     249                 :            :         }
     250                 :            : 
     251                 :          0 :         err = efivar_entry_set(entry, attributes, size, data, NULL);
     252         [ #  # ]:          0 :         if (err) {
     253                 :          0 :                 printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err);
     254                 :          0 :                 return -EIO;
     255                 :            :         }
     256                 :            : 
     257                 :          0 :         return count;
     258                 :            : }
     259                 :            : 
     260                 :            : static ssize_t
     261                 :          0 : efivar_show_raw(struct efivar_entry *entry, char *buf)
     262                 :            : {
     263                 :          0 :         struct efi_variable *var = &entry->var;
     264                 :          0 :         struct compat_efi_variable *compat;
     265                 :          0 :         unsigned long datasize = sizeof(var->Data);
     266                 :          0 :         size_t size;
     267                 :          0 :         int ret;
     268                 :            : 
     269         [ #  # ]:          0 :         if (!entry || !buf)
     270                 :            :                 return 0;
     271                 :            : 
     272                 :          0 :         ret = efivar_entry_get(entry, &var->Attributes, &datasize, var->Data);
     273                 :          0 :         var->DataSize = datasize;
     274         [ #  # ]:          0 :         if (ret)
     275                 :            :                 return -EIO;
     276                 :            : 
     277   [ #  #  #  # ]:          0 :         if (in_compat_syscall()) {
     278                 :          0 :                 compat = (struct compat_efi_variable *)buf;
     279                 :            : 
     280                 :          0 :                 size = sizeof(*compat);
     281                 :          0 :                 memcpy(compat->VariableName, var->VariableName,
     282                 :            :                         EFI_VAR_NAME_LEN);
     283                 :          0 :                 memcpy(compat->Data, var->Data, sizeof(compat->Data));
     284                 :            : 
     285                 :          0 :                 compat->VendorGuid = var->VendorGuid;
     286                 :          0 :                 compat->DataSize = var->DataSize;
     287                 :          0 :                 compat->Attributes = var->Attributes;
     288                 :            :         } else {
     289                 :          0 :                 size = sizeof(*var);
     290                 :          0 :                 memcpy(buf, var, size);
     291                 :            :         }
     292                 :            : 
     293                 :          0 :         return size;
     294                 :            : }
     295                 :            : 
     296                 :            : /*
     297                 :            :  * Generic read/write functions that call the specific functions of
     298                 :            :  * the attributes...
     299                 :            :  */
     300                 :          0 : static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr,
     301                 :            :                                 char *buf)
     302                 :            : {
     303                 :          0 :         struct efivar_entry *var = to_efivar_entry(kobj);
     304                 :          0 :         struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
     305                 :          0 :         ssize_t ret = -EIO;
     306                 :            : 
     307         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     308                 :            :                 return -EACCES;
     309                 :            : 
     310         [ #  # ]:          0 :         if (efivar_attr->show) {
     311                 :          0 :                 ret = efivar_attr->show(var, buf);
     312                 :            :         }
     313                 :            :         return ret;
     314                 :            : }
     315                 :            : 
     316                 :          0 : static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr,
     317                 :            :                                 const char *buf, size_t count)
     318                 :            : {
     319                 :          0 :         struct efivar_entry *var = to_efivar_entry(kobj);
     320                 :          0 :         struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
     321                 :          0 :         ssize_t ret = -EIO;
     322                 :            : 
     323         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     324                 :            :                 return -EACCES;
     325                 :            : 
     326         [ #  # ]:          0 :         if (efivar_attr->store)
     327                 :          0 :                 ret = efivar_attr->store(var, buf, count);
     328                 :            : 
     329                 :            :         return ret;
     330                 :            : }
     331                 :            : 
     332                 :            : static const struct sysfs_ops efivar_attr_ops = {
     333                 :            :         .show = efivar_attr_show,
     334                 :            :         .store = efivar_attr_store,
     335                 :            : };
     336                 :            : 
     337                 :          0 : static void efivar_release(struct kobject *kobj)
     338                 :            : {
     339                 :          0 :         struct efivar_entry *var = to_efivar_entry(kobj);
     340                 :          0 :         kfree(var);
     341                 :          0 : }
     342                 :            : 
     343                 :            : static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL);
     344                 :            : static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL);
     345                 :            : static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL);
     346                 :            : static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL);
     347                 :            : static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw);
     348                 :            : 
     349                 :            : static struct attribute *def_attrs[] = {
     350                 :            :         &efivar_attr_guid.attr,
     351                 :            :         &efivar_attr_size.attr,
     352                 :            :         &efivar_attr_attributes.attr,
     353                 :            :         &efivar_attr_data.attr,
     354                 :            :         &efivar_attr_raw_var.attr,
     355                 :            :         NULL,
     356                 :            : };
     357                 :            : 
     358                 :            : static struct kobj_type efivar_ktype = {
     359                 :            :         .release = efivar_release,
     360                 :            :         .sysfs_ops = &efivar_attr_ops,
     361                 :            :         .default_attrs = def_attrs,
     362                 :            : };
     363                 :            : 
     364                 :          0 : static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
     365                 :            :                              struct bin_attribute *bin_attr,
     366                 :            :                              char *buf, loff_t pos, size_t count)
     367                 :            : {
     368                 :          0 :         struct compat_efi_variable *compat = (struct compat_efi_variable *)buf;
     369                 :          0 :         struct efi_variable *new_var = (struct efi_variable *)buf;
     370                 :          0 :         struct efivar_entry *new_entry;
     371         [ #  # ]:          0 :         bool need_compat = in_compat_syscall();
     372                 :          0 :         efi_char16_t *name;
     373                 :          0 :         unsigned long size;
     374                 :          0 :         u32 attributes;
     375                 :          0 :         u8 *data;
     376                 :          0 :         int err;
     377                 :            : 
     378         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     379                 :            :                 return -EACCES;
     380                 :            : 
     381         [ #  # ]:          0 :         if (need_compat) {
     382         [ #  # ]:          0 :                 if (count != sizeof(*compat))
     383                 :            :                         return -EINVAL;
     384                 :            : 
     385                 :          0 :                 attributes = compat->Attributes;
     386                 :          0 :                 name = compat->VariableName;
     387                 :          0 :                 size = compat->DataSize;
     388                 :          0 :                 data = compat->Data;
     389                 :            :         } else {
     390         [ #  # ]:          0 :                 if (count != sizeof(*new_var))
     391                 :            :                         return -EINVAL;
     392                 :            : 
     393                 :          0 :                 attributes = new_var->Attributes;
     394                 :          0 :                 name = new_var->VariableName;
     395                 :          0 :                 size = new_var->DataSize;
     396                 :          0 :                 data = new_var->Data;
     397                 :            :         }
     398                 :            : 
     399   [ #  #  #  # ]:          0 :         if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
     400                 :          0 :             efivar_validate(new_var->VendorGuid, name, data,
     401                 :            :                             size) == false) {
     402                 :          0 :                 printk(KERN_ERR "efivars: Malformed variable content\n");
     403                 :          0 :                 return -EINVAL;
     404                 :            :         }
     405                 :            : 
     406                 :          0 :         new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
     407         [ #  # ]:          0 :         if (!new_entry)
     408                 :            :                 return -ENOMEM;
     409                 :            : 
     410         [ #  # ]:          0 :         if (need_compat)
     411                 :          0 :                 copy_out_compat(&new_entry->var, compat);
     412                 :            :         else
     413                 :          0 :                 memcpy(&new_entry->var, new_var, sizeof(*new_var));
     414                 :            : 
     415                 :          0 :         err = efivar_entry_set(new_entry, attributes, size,
     416                 :            :                                data, &efivar_sysfs_list);
     417         [ #  # ]:          0 :         if (err) {
     418         [ #  # ]:          0 :                 if (err == -EEXIST)
     419                 :          0 :                         err = -EINVAL;
     420                 :          0 :                 goto out;
     421                 :            :         }
     422                 :            : 
     423         [ #  # ]:          0 :         if (efivar_create_sysfs_entry(new_entry)) {
     424                 :          0 :                 printk(KERN_WARNING "efivars: failed to create sysfs entry.\n");
     425                 :          0 :                 kfree(new_entry);
     426                 :            :         }
     427                 :          0 :         return count;
     428                 :            : 
     429                 :            : out:
     430                 :          0 :         kfree(new_entry);
     431                 :          0 :         return err;
     432                 :            : }
     433                 :            : 
     434                 :          0 : static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
     435                 :            :                              struct bin_attribute *bin_attr,
     436                 :            :                              char *buf, loff_t pos, size_t count)
     437                 :            : {
     438                 :          0 :         struct efi_variable *del_var = (struct efi_variable *)buf;
     439                 :          0 :         struct compat_efi_variable *compat;
     440                 :          0 :         struct efivar_entry *entry;
     441                 :          0 :         efi_char16_t *name;
     442                 :          0 :         efi_guid_t vendor;
     443                 :          0 :         int err = 0;
     444                 :            : 
     445         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     446                 :            :                 return -EACCES;
     447                 :            : 
     448   [ #  #  #  # ]:          0 :         if (in_compat_syscall()) {
     449         [ #  # ]:          0 :                 if (count != sizeof(*compat))
     450                 :            :                         return -EINVAL;
     451                 :            : 
     452                 :          0 :                 compat = (struct compat_efi_variable *)buf;
     453                 :          0 :                 name = compat->VariableName;
     454                 :          0 :                 vendor = compat->VendorGuid;
     455                 :            :         } else {
     456         [ #  # ]:          0 :                 if (count != sizeof(*del_var))
     457                 :            :                         return -EINVAL;
     458                 :            : 
     459                 :          0 :                 name = del_var->VariableName;
     460                 :          0 :                 vendor = del_var->VendorGuid;
     461                 :            :         }
     462                 :            : 
     463         [ #  # ]:          0 :         if (efivar_entry_iter_begin())
     464                 :            :                 return -EINTR;
     465                 :          0 :         entry = efivar_entry_find(name, vendor, &efivar_sysfs_list, true);
     466         [ #  # ]:          0 :         if (!entry)
     467                 :            :                 err = -EINVAL;
     468         [ #  # ]:          0 :         else if (__efivar_entry_delete(entry))
     469                 :            :                 err = -EIO;
     470                 :            : 
     471                 :          0 :         if (err) {
     472                 :          0 :                 efivar_entry_iter_end();
     473                 :          0 :                 return err;
     474                 :            :         }
     475                 :            : 
     476         [ #  # ]:          0 :         if (!entry->scanning) {
     477                 :          0 :                 efivar_entry_iter_end();
     478                 :          0 :                 efivar_unregister(entry);
     479                 :            :         } else
     480                 :          0 :                 efivar_entry_iter_end();
     481                 :            : 
     482                 :            :         /* It's dead Jim.... */
     483                 :          0 :         return count;
     484                 :            : }
     485                 :            : 
     486                 :            : /**
     487                 :            :  * efivar_create_sysfs_entry - create a new entry in sysfs
     488                 :            :  * @new_var: efivar entry to create
     489                 :            :  *
     490                 :            :  * Returns 0 on success, negative error code on failure
     491                 :            :  */
     492                 :            : static int
     493                 :          0 : efivar_create_sysfs_entry(struct efivar_entry *new_var)
     494                 :            : {
     495                 :          0 :         int short_name_size;
     496                 :          0 :         char *short_name;
     497                 :          0 :         unsigned long utf8_name_size;
     498                 :          0 :         efi_char16_t *variable_name = new_var->var.VariableName;
     499                 :          0 :         int ret;
     500                 :            : 
     501                 :            :         /*
     502                 :            :          * Length of the variable bytes in UTF8, plus the '-' separator,
     503                 :            :          * plus the GUID, plus trailing NUL
     504                 :            :          */
     505                 :          0 :         utf8_name_size = ucs2_utf8size(variable_name);
     506                 :          0 :         short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1;
     507                 :            : 
     508         [ #  # ]:          0 :         short_name = kmalloc(short_name_size, GFP_KERNEL);
     509         [ #  # ]:          0 :         if (!short_name)
     510                 :            :                 return -ENOMEM;
     511                 :            : 
     512                 :          0 :         ucs2_as_utf8(short_name, variable_name, short_name_size);
     513                 :            : 
     514                 :            :         /* This is ugly, but necessary to separate one vendor's
     515                 :            :            private variables from another's.         */
     516                 :          0 :         short_name[utf8_name_size] = '-';
     517                 :          0 :         efi_guid_to_str(&new_var->var.VendorGuid,
     518                 :          0 :                          short_name + utf8_name_size + 1);
     519                 :            : 
     520                 :          0 :         new_var->kobj.kset = efivars_kset;
     521                 :            : 
     522                 :          0 :         ret = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
     523                 :            :                                    NULL, "%s", short_name);
     524                 :          0 :         kfree(short_name);
     525         [ #  # ]:          0 :         if (ret)
     526                 :            :                 return ret;
     527                 :            : 
     528                 :          0 :         kobject_uevent(&new_var->kobj, KOBJ_ADD);
     529         [ #  # ]:          0 :         if (efivar_entry_add(new_var, &efivar_sysfs_list)) {
     530                 :          0 :                 efivar_unregister(new_var);
     531                 :          0 :                 return -EINTR;
     532                 :            :         }
     533                 :            : 
     534                 :            :         return 0;
     535                 :            : }
     536                 :            : 
     537                 :            : static int
     538                 :          0 : create_efivars_bin_attributes(void)
     539                 :            : {
     540                 :          0 :         struct bin_attribute *attr;
     541                 :          0 :         int error;
     542                 :            : 
     543                 :            :         /* new_var */
     544                 :          0 :         attr = kzalloc(sizeof(*attr), GFP_KERNEL);
     545         [ #  # ]:          0 :         if (!attr)
     546                 :            :                 return -ENOMEM;
     547                 :            : 
     548                 :          0 :         attr->attr.name = "new_var";
     549                 :          0 :         attr->attr.mode = 0200;
     550                 :          0 :         attr->write = efivar_create;
     551                 :          0 :         efivars_new_var = attr;
     552                 :            : 
     553                 :            :         /* del_var */
     554                 :          0 :         attr = kzalloc(sizeof(*attr), GFP_KERNEL);
     555         [ #  # ]:          0 :         if (!attr) {
     556                 :          0 :                 error = -ENOMEM;
     557                 :          0 :                 goto out_free;
     558                 :            :         }
     559                 :          0 :         attr->attr.name = "del_var";
     560                 :          0 :         attr->attr.mode = 0200;
     561                 :          0 :         attr->write = efivar_delete;
     562                 :          0 :         efivars_del_var = attr;
     563                 :            : 
     564                 :          0 :         sysfs_bin_attr_init(efivars_new_var);
     565                 :          0 :         sysfs_bin_attr_init(efivars_del_var);
     566                 :            : 
     567                 :            :         /* Register */
     568                 :          0 :         error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_new_var);
     569         [ #  # ]:          0 :         if (error) {
     570                 :          0 :                 printk(KERN_ERR "efivars: unable to create new_var sysfs file"
     571                 :            :                         " due to error %d\n", error);
     572                 :          0 :                 goto out_free;
     573                 :            :         }
     574                 :            : 
     575                 :          0 :         error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_del_var);
     576         [ #  # ]:          0 :         if (error) {
     577                 :          0 :                 printk(KERN_ERR "efivars: unable to create del_var sysfs file"
     578                 :            :                         " due to error %d\n", error);
     579                 :          0 :                 sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var);
     580                 :          0 :                 goto out_free;
     581                 :            :         }
     582                 :            : 
     583                 :            :         return 0;
     584                 :          0 : out_free:
     585                 :          0 :         kfree(efivars_del_var);
     586                 :          0 :         efivars_del_var = NULL;
     587                 :          0 :         kfree(efivars_new_var);
     588                 :          0 :         efivars_new_var = NULL;
     589                 :          0 :         return error;
     590                 :            : }
     591                 :            : 
     592                 :          0 : static int efivar_update_sysfs_entry(efi_char16_t *name, efi_guid_t vendor,
     593                 :            :                                      unsigned long name_size, void *data)
     594                 :            : {
     595                 :          0 :         struct efivar_entry *entry = data;
     596                 :            : 
     597         [ #  # ]:          0 :         if (efivar_entry_find(name, vendor, &efivar_sysfs_list, false))
     598                 :            :                 return 0;
     599                 :            : 
     600                 :          0 :         memcpy(entry->var.VariableName, name, name_size);
     601                 :          0 :         memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
     602                 :            : 
     603                 :          0 :         return 1;
     604                 :            : }
     605                 :            : 
     606                 :          0 : static void efivar_update_sysfs_entries(struct work_struct *work)
     607                 :            : {
     608                 :          0 :         struct efivar_entry *entry;
     609                 :          0 :         int err;
     610                 :            : 
     611                 :            :         /* Add new sysfs entries */
     612                 :          0 :         while (1) {
     613                 :          0 :                 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
     614         [ #  # ]:          0 :                 if (!entry)
     615                 :            :                         return;
     616                 :            : 
     617                 :          0 :                 err = efivar_init(efivar_update_sysfs_entry, entry,
     618                 :            :                                   false, &efivar_sysfs_list);
     619         [ #  # ]:          0 :                 if (!err)
     620                 :            :                         break;
     621                 :            : 
     622                 :          0 :                 efivar_create_sysfs_entry(entry);
     623                 :            :         }
     624                 :            : 
     625                 :          0 :         kfree(entry);
     626                 :            : }
     627                 :            : 
     628                 :          0 : static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor,
     629                 :            :                                   unsigned long name_size, void *data)
     630                 :            : {
     631                 :          0 :         struct efivar_entry *entry;
     632                 :            : 
     633                 :          0 :         entry = kzalloc(sizeof(*entry), GFP_KERNEL);
     634         [ #  # ]:          0 :         if (!entry)
     635                 :            :                 return -ENOMEM;
     636                 :            : 
     637                 :          0 :         memcpy(entry->var.VariableName, name, name_size);
     638                 :          0 :         memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
     639                 :            : 
     640                 :          0 :         efivar_create_sysfs_entry(entry);
     641                 :            : 
     642                 :          0 :         return 0;
     643                 :            : }
     644                 :            : 
     645                 :          0 : static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data)
     646                 :            : {
     647                 :          0 :         int err = efivar_entry_remove(entry);
     648                 :            : 
     649         [ #  # ]:          0 :         if (err)
     650                 :            :                 return err;
     651                 :          0 :         efivar_unregister(entry);
     652                 :          0 :         return 0;
     653                 :            : }
     654                 :            : 
     655                 :          0 : static void efivars_sysfs_exit(void)
     656                 :            : {
     657                 :            :         /* Remove all entries and destroy */
     658                 :          0 :         int err;
     659                 :            : 
     660                 :          0 :         err = __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list,
     661                 :            :                                   NULL, NULL);
     662         [ #  # ]:          0 :         if (err) {
     663                 :          0 :                 pr_err("efivars: Failed to destroy sysfs entries\n");
     664                 :          0 :                 return;
     665                 :            :         }
     666                 :            : 
     667         [ #  # ]:          0 :         if (efivars_new_var)
     668                 :          0 :                 sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var);
     669         [ #  # ]:          0 :         if (efivars_del_var)
     670                 :          0 :                 sysfs_remove_bin_file(&efivars_kset->kobj, efivars_del_var);
     671                 :          0 :         kfree(efivars_new_var);
     672                 :          0 :         kfree(efivars_del_var);
     673                 :          0 :         kset_unregister(efivars_kset);
     674                 :            : }
     675                 :            : 
     676                 :          3 : int efivars_sysfs_init(void)
     677                 :            : {
     678                 :          3 :         struct kobject *parent_kobj = efivars_kobject();
     679                 :          3 :         int error = 0;
     680                 :            : 
     681         [ -  + ]:          3 :         if (!efi_enabled(EFI_RUNTIME_SERVICES))
     682                 :            :                 return -ENODEV;
     683                 :            : 
     684                 :            :         /* No efivars has been registered yet */
     685         [ #  # ]:          0 :         if (!parent_kobj)
     686                 :            :                 return 0;
     687                 :            : 
     688                 :          0 :         printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
     689                 :            :                EFIVARS_DATE);
     690                 :            : 
     691                 :          0 :         efivars_kset = kset_create_and_add("vars", NULL, parent_kobj);
     692         [ #  # ]:          0 :         if (!efivars_kset) {
     693                 :          0 :                 printk(KERN_ERR "efivars: Subsystem registration failed.\n");
     694                 :          0 :                 return -ENOMEM;
     695                 :            :         }
     696                 :            : 
     697                 :          0 :         efivar_init(efivars_sysfs_callback, NULL, true, &efivar_sysfs_list);
     698                 :            : 
     699                 :          0 :         error = create_efivars_bin_attributes();
     700         [ #  # ]:          0 :         if (error) {
     701                 :          0 :                 efivars_sysfs_exit();
     702                 :          0 :                 return error;
     703                 :            :         }
     704                 :            : 
     705                 :          0 :         INIT_WORK(&efivar_work, efivar_update_sysfs_entries);
     706                 :            : 
     707                 :          0 :         return 0;
     708                 :            : }
     709                 :            : EXPORT_SYMBOL_GPL(efivars_sysfs_init);
     710                 :            : 
     711                 :            : module_init(efivars_sysfs_init);
     712                 :            : module_exit(efivars_sysfs_exit);

Generated by: LCOV version 1.14