0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/capability.h>
0010 #include <linux/types.h>
0011 #include <linux/errno.h>
0012 #include <linux/init.h>
0013 #include <linux/mm.h>
0014 #include <linux/module.h>
0015 #include <linux/string.h>
0016 #include <linux/smp.h>
0017 #include <linux/efi.h>
0018 #include <linux/device.h>
0019 #include <linux/slab.h>
0020 #include <linux/ctype.h>
0021 #include <linux/ucs2_string.h>
0022
0023 #include "internal.h"
0024
0025 MODULE_IMPORT_NS(EFIVAR);
0026
0027 static bool
0028 validate_device_path(efi_char16_t *var_name, int match, u8 *buffer,
0029 unsigned long len)
0030 {
0031 struct efi_generic_dev_path *node;
0032 int offset = 0;
0033
0034 node = (struct efi_generic_dev_path *)buffer;
0035
0036 if (len < sizeof(*node))
0037 return false;
0038
0039 while (offset <= len - sizeof(*node) &&
0040 node->length >= sizeof(*node) &&
0041 node->length <= len - offset) {
0042 offset += node->length;
0043
0044 if ((node->type == EFI_DEV_END_PATH ||
0045 node->type == EFI_DEV_END_PATH2) &&
0046 node->sub_type == EFI_DEV_END_ENTIRE)
0047 return true;
0048
0049 node = (struct efi_generic_dev_path *)(buffer + offset);
0050 }
0051
0052
0053
0054
0055
0056
0057 return false;
0058 }
0059
0060 static bool
0061 validate_boot_order(efi_char16_t *var_name, int match, u8 *buffer,
0062 unsigned long len)
0063 {
0064
0065 if ((len % 2) != 0)
0066 return false;
0067
0068 return true;
0069 }
0070
0071 static bool
0072 validate_load_option(efi_char16_t *var_name, int match, u8 *buffer,
0073 unsigned long len)
0074 {
0075 u16 filepathlength;
0076 int i, desclength = 0, namelen;
0077
0078 namelen = ucs2_strnlen(var_name, EFI_VAR_NAME_LEN);
0079
0080
0081 for (i = match; i < match+4; i++) {
0082 if (var_name[i] > 127 ||
0083 hex_to_bin(var_name[i] & 0xff) < 0)
0084 return true;
0085 }
0086
0087
0088 if (namelen > match + 4)
0089 return false;
0090
0091
0092 if (len < 8)
0093 return false;
0094
0095 filepathlength = buffer[4] | buffer[5] << 8;
0096
0097
0098
0099
0100
0101 desclength = ucs2_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2;
0102
0103
0104 if (!desclength)
0105 return false;
0106
0107
0108
0109
0110
0111
0112 if ((desclength + filepathlength + 6) > len)
0113 return false;
0114
0115
0116
0117
0118 return validate_device_path(var_name, match, buffer + desclength + 6,
0119 filepathlength);
0120 }
0121
0122 static bool
0123 validate_uint16(efi_char16_t *var_name, int match, u8 *buffer,
0124 unsigned long len)
0125 {
0126
0127 if (len != 2)
0128 return false;
0129
0130 return true;
0131 }
0132
0133 static bool
0134 validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer,
0135 unsigned long len)
0136 {
0137 int i;
0138
0139 for (i = 0; i < len; i++) {
0140 if (buffer[i] > 127)
0141 return false;
0142
0143 if (buffer[i] == 0)
0144 return true;
0145 }
0146
0147 return false;
0148 }
0149
0150 struct variable_validate {
0151 efi_guid_t vendor;
0152 char *name;
0153 bool (*validate)(efi_char16_t *var_name, int match, u8 *data,
0154 unsigned long len);
0155 };
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168 static const struct variable_validate variable_validate[] = {
0169 { EFI_GLOBAL_VARIABLE_GUID, "BootNext", validate_uint16 },
0170 { EFI_GLOBAL_VARIABLE_GUID, "BootOrder", validate_boot_order },
0171 { EFI_GLOBAL_VARIABLE_GUID, "Boot*", validate_load_option },
0172 { EFI_GLOBAL_VARIABLE_GUID, "DriverOrder", validate_boot_order },
0173 { EFI_GLOBAL_VARIABLE_GUID, "Driver*", validate_load_option },
0174 { EFI_GLOBAL_VARIABLE_GUID, "ConIn", validate_device_path },
0175 { EFI_GLOBAL_VARIABLE_GUID, "ConInDev", validate_device_path },
0176 { EFI_GLOBAL_VARIABLE_GUID, "ConOut", validate_device_path },
0177 { EFI_GLOBAL_VARIABLE_GUID, "ConOutDev", validate_device_path },
0178 { EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path },
0179 { EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path },
0180 { EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string },
0181 { EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL },
0182 { EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string },
0183 { EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 },
0184 { LINUX_EFI_CRASH_GUID, "*", NULL },
0185 { NULL_GUID, "", NULL },
0186 };
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199 static bool
0200 variable_matches(const char *var_name, size_t len, const char *match_name,
0201 int *match)
0202 {
0203 for (*match = 0; ; (*match)++) {
0204 char c = match_name[*match];
0205
0206 switch (c) {
0207 case '*':
0208
0209 return true;
0210
0211 case '\0':
0212
0213 return (*match == len);
0214
0215 default:
0216
0217
0218
0219
0220
0221 if (*match < len && c == var_name[*match])
0222 continue;
0223 return false;
0224 }
0225 }
0226 }
0227
0228 bool
0229 efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
0230 unsigned long data_size)
0231 {
0232 int i;
0233 unsigned long utf8_size;
0234 u8 *utf8_name;
0235
0236 utf8_size = ucs2_utf8size(var_name);
0237 utf8_name = kmalloc(utf8_size + 1, GFP_KERNEL);
0238 if (!utf8_name)
0239 return false;
0240
0241 ucs2_as_utf8(utf8_name, var_name, utf8_size);
0242 utf8_name[utf8_size] = '\0';
0243
0244 for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
0245 const char *name = variable_validate[i].name;
0246 int match = 0;
0247
0248 if (efi_guidcmp(vendor, variable_validate[i].vendor))
0249 continue;
0250
0251 if (variable_matches(utf8_name, utf8_size+1, name, &match)) {
0252 if (variable_validate[i].validate == NULL)
0253 break;
0254 kfree(utf8_name);
0255 return variable_validate[i].validate(var_name, match,
0256 data, data_size);
0257 }
0258 }
0259 kfree(utf8_name);
0260 return true;
0261 }
0262
0263 bool
0264 efivar_variable_is_removable(efi_guid_t vendor, const char *var_name,
0265 size_t len)
0266 {
0267 int i;
0268 bool found = false;
0269 int match = 0;
0270
0271
0272
0273
0274 for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
0275 if (efi_guidcmp(variable_validate[i].vendor, vendor))
0276 continue;
0277
0278 if (variable_matches(var_name, len,
0279 variable_validate[i].name, &match)) {
0280 found = true;
0281 break;
0282 }
0283 }
0284
0285
0286
0287
0288 return found;
0289 }
0290
0291 static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor,
0292 struct list_head *head)
0293 {
0294 struct efivar_entry *entry, *n;
0295 unsigned long strsize1, strsize2;
0296 bool found = false;
0297
0298 strsize1 = ucs2_strsize(variable_name, 1024);
0299 list_for_each_entry_safe(entry, n, head, list) {
0300 strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
0301 if (strsize1 == strsize2 &&
0302 !memcmp(variable_name, &(entry->var.VariableName),
0303 strsize2) &&
0304 !efi_guidcmp(entry->var.VendorGuid,
0305 *vendor)) {
0306 found = true;
0307 break;
0308 }
0309 }
0310 return found;
0311 }
0312
0313
0314
0315
0316
0317
0318 static unsigned long var_name_strnsize(efi_char16_t *variable_name,
0319 unsigned long variable_name_size)
0320 {
0321 unsigned long len;
0322 efi_char16_t c;
0323
0324
0325
0326
0327
0328
0329 for (len = 2; len <= variable_name_size; len += sizeof(c)) {
0330 c = variable_name[(len / sizeof(c)) - 1];
0331 if (!c)
0332 break;
0333 }
0334
0335 return min(len, variable_name_size);
0336 }
0337
0338
0339
0340
0341
0342 static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid,
0343 unsigned long len16)
0344 {
0345 size_t i, len8 = len16 / sizeof(efi_char16_t);
0346 char *str8;
0347
0348 str8 = kzalloc(len8, GFP_KERNEL);
0349 if (!str8)
0350 return;
0351
0352 for (i = 0; i < len8; i++)
0353 str8[i] = str16[i];
0354
0355 printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n",
0356 str8, vendor_guid);
0357 kfree(str8);
0358 }
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372 int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
0373 void *data, bool duplicates, struct list_head *head)
0374 {
0375 unsigned long variable_name_size = 1024;
0376 efi_char16_t *variable_name;
0377 efi_status_t status;
0378 efi_guid_t vendor_guid;
0379 int err = 0;
0380
0381 variable_name = kzalloc(variable_name_size, GFP_KERNEL);
0382 if (!variable_name) {
0383 printk(KERN_ERR "efivars: Memory allocation failed.\n");
0384 return -ENOMEM;
0385 }
0386
0387 err = efivar_lock();
0388 if (err)
0389 goto free;
0390
0391
0392
0393
0394
0395
0396 do {
0397 variable_name_size = 1024;
0398
0399 status = efivar_get_next_variable(&variable_name_size,
0400 variable_name,
0401 &vendor_guid);
0402 switch (status) {
0403 case EFI_SUCCESS:
0404 variable_name_size = var_name_strnsize(variable_name,
0405 variable_name_size);
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415 if (duplicates &&
0416 variable_is_present(variable_name, &vendor_guid,
0417 head)) {
0418 dup_variable_bug(variable_name, &vendor_guid,
0419 variable_name_size);
0420 status = EFI_NOT_FOUND;
0421 } else {
0422 err = func(variable_name, vendor_guid,
0423 variable_name_size, data);
0424 if (err)
0425 status = EFI_NOT_FOUND;
0426 }
0427 break;
0428 case EFI_UNSUPPORTED:
0429 err = -EOPNOTSUPP;
0430 status = EFI_NOT_FOUND;
0431 break;
0432 case EFI_NOT_FOUND:
0433 break;
0434 default:
0435 printk(KERN_WARNING "efivars: get_next_variable: status=%lx\n",
0436 status);
0437 status = EFI_NOT_FOUND;
0438 break;
0439 }
0440
0441 } while (status != EFI_NOT_FOUND);
0442
0443 efivar_unlock();
0444 free:
0445 kfree(variable_name);
0446
0447 return err;
0448 }
0449
0450
0451
0452
0453
0454
0455
0456
0457 int efivar_entry_add(struct efivar_entry *entry, struct list_head *head)
0458 {
0459 int err;
0460
0461 err = efivar_lock();
0462 if (err)
0463 return err;
0464 list_add(&entry->list, head);
0465 efivar_unlock();
0466
0467 return 0;
0468 }
0469
0470
0471
0472
0473
0474
0475 void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head)
0476 {
0477 list_add(&entry->list, head);
0478 }
0479
0480
0481
0482
0483
0484
0485
0486 void efivar_entry_remove(struct efivar_entry *entry)
0487 {
0488 list_del(&entry->list);
0489 }
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502 static void efivar_entry_list_del_unlock(struct efivar_entry *entry)
0503 {
0504 list_del(&entry->list);
0505 efivar_unlock();
0506 }
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519 int efivar_entry_delete(struct efivar_entry *entry)
0520 {
0521 efi_status_t status;
0522 int err;
0523
0524 err = efivar_lock();
0525 if (err)
0526 return err;
0527
0528 status = efivar_set_variable_locked(entry->var.VariableName,
0529 &entry->var.VendorGuid,
0530 0, 0, NULL, false);
0531 if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) {
0532 efivar_unlock();
0533 return efi_status_to_err(status);
0534 }
0535
0536 efivar_entry_list_del_unlock(entry);
0537 return 0;
0538 }
0539
0540
0541
0542
0543
0544
0545 int efivar_entry_size(struct efivar_entry *entry, unsigned long *size)
0546 {
0547 efi_status_t status;
0548 int err;
0549
0550 *size = 0;
0551
0552 err = efivar_lock();
0553 if (err)
0554 return err;
0555
0556 status = efivar_get_variable(entry->var.VariableName,
0557 &entry->var.VendorGuid, NULL, size, NULL);
0558 efivar_unlock();
0559
0560 if (status != EFI_BUFFER_TOO_SMALL)
0561 return efi_status_to_err(status);
0562
0563 return 0;
0564 }
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577 int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
0578 unsigned long *size, void *data)
0579 {
0580 efi_status_t status;
0581
0582 status = efivar_get_variable(entry->var.VariableName,
0583 &entry->var.VendorGuid,
0584 attributes, size, data);
0585
0586 return efi_status_to_err(status);
0587 }
0588
0589
0590
0591
0592
0593
0594
0595
0596 int efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
0597 unsigned long *size, void *data)
0598 {
0599 int err;
0600
0601 err = efivar_lock();
0602 if (err)
0603 return err;
0604 err = __efivar_entry_get(entry, attributes, size, data);
0605 efivar_unlock();
0606
0607 return 0;
0608 }
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632 int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
0633 unsigned long *size, void *data, bool *set)
0634 {
0635 efi_char16_t *name = entry->var.VariableName;
0636 efi_guid_t *vendor = &entry->var.VendorGuid;
0637 efi_status_t status;
0638 int err;
0639
0640 *set = false;
0641
0642 if (efivar_validate(*vendor, name, data, *size) == false)
0643 return -EINVAL;
0644
0645
0646
0647
0648
0649
0650 err = efivar_lock();
0651 if (err)
0652 return err;
0653
0654
0655
0656
0657 status = check_var_size(attributes, *size + ucs2_strsize(name, 1024));
0658 if (status != EFI_SUCCESS) {
0659 if (status != EFI_UNSUPPORTED) {
0660 err = efi_status_to_err(status);
0661 goto out;
0662 }
0663
0664 if (*size > 65536) {
0665 err = -ENOSPC;
0666 goto out;
0667 }
0668 }
0669
0670 status = efivar_set_variable_locked(name, vendor, attributes, *size,
0671 data, false);
0672 if (status != EFI_SUCCESS) {
0673 err = efi_status_to_err(status);
0674 goto out;
0675 }
0676
0677 *set = true;
0678
0679
0680
0681
0682
0683
0684
0685 *size = 0;
0686 status = efivar_get_variable(entry->var.VariableName,
0687 &entry->var.VendorGuid,
0688 NULL, size, NULL);
0689
0690 if (status == EFI_NOT_FOUND)
0691 efivar_entry_list_del_unlock(entry);
0692 else
0693 efivar_unlock();
0694
0695 if (status && status != EFI_BUFFER_TOO_SMALL)
0696 return efi_status_to_err(status);
0697
0698 return 0;
0699
0700 out:
0701 efivar_unlock();
0702 return err;
0703
0704 }
0705
0706
0707
0708
0709
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719
0720 int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
0721 struct list_head *head, void *data)
0722 {
0723 struct efivar_entry *entry, *n;
0724 int err = 0;
0725
0726 err = efivar_lock();
0727 if (err)
0728 return err;
0729
0730 list_for_each_entry_safe(entry, n, head, list) {
0731 err = func(entry, data);
0732 if (err)
0733 break;
0734 }
0735 efivar_unlock();
0736
0737 return err;
0738 }