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