0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/miscdevice.h>
0013 #include <linux/module.h>
0014 #include <linux/init.h>
0015 #include <linux/proc_fs.h>
0016 #include <linux/efi.h>
0017 #include <linux/security.h>
0018 #include <linux/slab.h>
0019 #include <linux/uaccess.h>
0020
0021 #include "efi_test.h"
0022
0023 MODULE_AUTHOR("Ivan Hu <ivan.hu@canonical.com>");
0024 MODULE_DESCRIPTION("EFI Test Driver");
0025 MODULE_LICENSE("GPL");
0026
0027
0028
0029
0030
0031
0032
0033 static inline size_t user_ucs2_strsize(efi_char16_t __user *str)
0034 {
0035 efi_char16_t *s = str, c;
0036 size_t len;
0037
0038 if (!str)
0039 return 0;
0040
0041
0042 len = sizeof(efi_char16_t);
0043
0044 if (get_user(c, s++)) {
0045
0046 return 0;
0047 }
0048
0049 while (c != 0) {
0050 if (get_user(c, s++)) {
0051
0052 return 0;
0053 }
0054 len += sizeof(efi_char16_t);
0055 }
0056 return len;
0057 }
0058
0059
0060
0061
0062 static inline int
0063 copy_ucs2_from_user_len(efi_char16_t **dst, efi_char16_t __user *src,
0064 size_t len)
0065 {
0066 efi_char16_t *buf;
0067
0068 if (!src) {
0069 *dst = NULL;
0070 return 0;
0071 }
0072
0073 buf = memdup_user(src, len);
0074 if (IS_ERR(buf)) {
0075 *dst = NULL;
0076 return PTR_ERR(buf);
0077 }
0078 *dst = buf;
0079
0080 return 0;
0081 }
0082
0083
0084
0085
0086
0087
0088 static inline int
0089 get_ucs2_strsize_from_user(efi_char16_t __user *src, size_t *len)
0090 {
0091 *len = user_ucs2_strsize(src);
0092 if (*len == 0)
0093 return -EFAULT;
0094
0095 return 0;
0096 }
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110 static inline int
0111 copy_ucs2_from_user(efi_char16_t **dst, efi_char16_t __user *src)
0112 {
0113 size_t len;
0114
0115 len = user_ucs2_strsize(src);
0116 if (len == 0)
0117 return -EFAULT;
0118 return copy_ucs2_from_user_len(dst, src, len);
0119 }
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130 static inline int
0131 copy_ucs2_to_user_len(efi_char16_t __user *dst, efi_char16_t *src, size_t len)
0132 {
0133 if (!src)
0134 return 0;
0135
0136 return copy_to_user(dst, src, len);
0137 }
0138
0139 static long efi_runtime_get_variable(unsigned long arg)
0140 {
0141 struct efi_getvariable __user *getvariable_user;
0142 struct efi_getvariable getvariable;
0143 unsigned long datasize = 0, prev_datasize, *dz;
0144 efi_guid_t vendor_guid, *vd = NULL;
0145 efi_status_t status;
0146 efi_char16_t *name = NULL;
0147 u32 attr, *at;
0148 void *data = NULL;
0149 int rv = 0;
0150
0151 getvariable_user = (struct efi_getvariable __user *)arg;
0152
0153 if (copy_from_user(&getvariable, getvariable_user,
0154 sizeof(getvariable)))
0155 return -EFAULT;
0156 if (getvariable.data_size &&
0157 get_user(datasize, getvariable.data_size))
0158 return -EFAULT;
0159 if (getvariable.vendor_guid) {
0160 if (copy_from_user(&vendor_guid, getvariable.vendor_guid,
0161 sizeof(vendor_guid)))
0162 return -EFAULT;
0163 vd = &vendor_guid;
0164 }
0165
0166 if (getvariable.variable_name) {
0167 rv = copy_ucs2_from_user(&name, getvariable.variable_name);
0168 if (rv)
0169 return rv;
0170 }
0171
0172 at = getvariable.attributes ? &attr : NULL;
0173 dz = getvariable.data_size ? &datasize : NULL;
0174
0175 if (getvariable.data_size && getvariable.data) {
0176 data = kmalloc(datasize, GFP_KERNEL);
0177 if (!data) {
0178 kfree(name);
0179 return -ENOMEM;
0180 }
0181 }
0182
0183 prev_datasize = datasize;
0184 status = efi.get_variable(name, vd, at, dz, data);
0185 kfree(name);
0186
0187 if (put_user(status, getvariable.status)) {
0188 rv = -EFAULT;
0189 goto out;
0190 }
0191
0192 if (status != EFI_SUCCESS) {
0193 if (status == EFI_BUFFER_TOO_SMALL) {
0194 if (dz && put_user(datasize, getvariable.data_size)) {
0195 rv = -EFAULT;
0196 goto out;
0197 }
0198 }
0199 rv = -EINVAL;
0200 goto out;
0201 }
0202
0203 if (prev_datasize < datasize) {
0204 rv = -EINVAL;
0205 goto out;
0206 }
0207
0208 if (data) {
0209 if (copy_to_user(getvariable.data, data, datasize)) {
0210 rv = -EFAULT;
0211 goto out;
0212 }
0213 }
0214
0215 if (at && put_user(attr, getvariable.attributes)) {
0216 rv = -EFAULT;
0217 goto out;
0218 }
0219
0220 if (dz && put_user(datasize, getvariable.data_size))
0221 rv = -EFAULT;
0222
0223 out:
0224 kfree(data);
0225 return rv;
0226
0227 }
0228
0229 static long efi_runtime_set_variable(unsigned long arg)
0230 {
0231 struct efi_setvariable __user *setvariable_user;
0232 struct efi_setvariable setvariable;
0233 efi_guid_t vendor_guid;
0234 efi_status_t status;
0235 efi_char16_t *name = NULL;
0236 void *data;
0237 int rv = 0;
0238
0239 setvariable_user = (struct efi_setvariable __user *)arg;
0240
0241 if (copy_from_user(&setvariable, setvariable_user, sizeof(setvariable)))
0242 return -EFAULT;
0243 if (copy_from_user(&vendor_guid, setvariable.vendor_guid,
0244 sizeof(vendor_guid)))
0245 return -EFAULT;
0246
0247 if (setvariable.variable_name) {
0248 rv = copy_ucs2_from_user(&name, setvariable.variable_name);
0249 if (rv)
0250 return rv;
0251 }
0252
0253 data = memdup_user(setvariable.data, setvariable.data_size);
0254 if (IS_ERR(data)) {
0255 kfree(name);
0256 return PTR_ERR(data);
0257 }
0258
0259 status = efi.set_variable(name, &vendor_guid,
0260 setvariable.attributes,
0261 setvariable.data_size, data);
0262
0263 if (put_user(status, setvariable.status)) {
0264 rv = -EFAULT;
0265 goto out;
0266 }
0267
0268 rv = status == EFI_SUCCESS ? 0 : -EINVAL;
0269
0270 out:
0271 kfree(data);
0272 kfree(name);
0273
0274 return rv;
0275 }
0276
0277 static long efi_runtime_get_time(unsigned long arg)
0278 {
0279 struct efi_gettime __user *gettime_user;
0280 struct efi_gettime gettime;
0281 efi_status_t status;
0282 efi_time_cap_t cap;
0283 efi_time_t efi_time;
0284
0285 gettime_user = (struct efi_gettime __user *)arg;
0286 if (copy_from_user(&gettime, gettime_user, sizeof(gettime)))
0287 return -EFAULT;
0288
0289 status = efi.get_time(gettime.time ? &efi_time : NULL,
0290 gettime.capabilities ? &cap : NULL);
0291
0292 if (put_user(status, gettime.status))
0293 return -EFAULT;
0294
0295 if (status != EFI_SUCCESS)
0296 return -EINVAL;
0297
0298 if (gettime.capabilities) {
0299 efi_time_cap_t __user *cap_local;
0300
0301 cap_local = (efi_time_cap_t *)gettime.capabilities;
0302 if (put_user(cap.resolution, &(cap_local->resolution)) ||
0303 put_user(cap.accuracy, &(cap_local->accuracy)) ||
0304 put_user(cap.sets_to_zero, &(cap_local->sets_to_zero)))
0305 return -EFAULT;
0306 }
0307 if (gettime.time) {
0308 if (copy_to_user(gettime.time, &efi_time, sizeof(efi_time_t)))
0309 return -EFAULT;
0310 }
0311
0312 return 0;
0313 }
0314
0315 static long efi_runtime_set_time(unsigned long arg)
0316 {
0317 struct efi_settime __user *settime_user;
0318 struct efi_settime settime;
0319 efi_status_t status;
0320 efi_time_t efi_time;
0321
0322 settime_user = (struct efi_settime __user *)arg;
0323 if (copy_from_user(&settime, settime_user, sizeof(settime)))
0324 return -EFAULT;
0325 if (copy_from_user(&efi_time, settime.time,
0326 sizeof(efi_time_t)))
0327 return -EFAULT;
0328 status = efi.set_time(&efi_time);
0329
0330 if (put_user(status, settime.status))
0331 return -EFAULT;
0332
0333 return status == EFI_SUCCESS ? 0 : -EINVAL;
0334 }
0335
0336 static long efi_runtime_get_waketime(unsigned long arg)
0337 {
0338 struct efi_getwakeuptime __user *getwakeuptime_user;
0339 struct efi_getwakeuptime getwakeuptime;
0340 efi_bool_t enabled, pending;
0341 efi_status_t status;
0342 efi_time_t efi_time;
0343
0344 getwakeuptime_user = (struct efi_getwakeuptime __user *)arg;
0345 if (copy_from_user(&getwakeuptime, getwakeuptime_user,
0346 sizeof(getwakeuptime)))
0347 return -EFAULT;
0348
0349 status = efi.get_wakeup_time(
0350 getwakeuptime.enabled ? (efi_bool_t *)&enabled : NULL,
0351 getwakeuptime.pending ? (efi_bool_t *)&pending : NULL,
0352 getwakeuptime.time ? &efi_time : NULL);
0353
0354 if (put_user(status, getwakeuptime.status))
0355 return -EFAULT;
0356
0357 if (status != EFI_SUCCESS)
0358 return -EINVAL;
0359
0360 if (getwakeuptime.enabled && put_user(enabled,
0361 getwakeuptime.enabled))
0362 return -EFAULT;
0363
0364 if (getwakeuptime.time) {
0365 if (copy_to_user(getwakeuptime.time, &efi_time,
0366 sizeof(efi_time_t)))
0367 return -EFAULT;
0368 }
0369
0370 return 0;
0371 }
0372
0373 static long efi_runtime_set_waketime(unsigned long arg)
0374 {
0375 struct efi_setwakeuptime __user *setwakeuptime_user;
0376 struct efi_setwakeuptime setwakeuptime;
0377 efi_bool_t enabled;
0378 efi_status_t status;
0379 efi_time_t efi_time;
0380
0381 setwakeuptime_user = (struct efi_setwakeuptime __user *)arg;
0382
0383 if (copy_from_user(&setwakeuptime, setwakeuptime_user,
0384 sizeof(setwakeuptime)))
0385 return -EFAULT;
0386
0387 enabled = setwakeuptime.enabled;
0388 if (setwakeuptime.time) {
0389 if (copy_from_user(&efi_time, setwakeuptime.time,
0390 sizeof(efi_time_t)))
0391 return -EFAULT;
0392
0393 status = efi.set_wakeup_time(enabled, &efi_time);
0394 } else
0395 status = efi.set_wakeup_time(enabled, NULL);
0396
0397 if (put_user(status, setwakeuptime.status))
0398 return -EFAULT;
0399
0400 return status == EFI_SUCCESS ? 0 : -EINVAL;
0401 }
0402
0403 static long efi_runtime_get_nextvariablename(unsigned long arg)
0404 {
0405 struct efi_getnextvariablename __user *getnextvariablename_user;
0406 struct efi_getnextvariablename getnextvariablename;
0407 unsigned long name_size, prev_name_size = 0, *ns = NULL;
0408 efi_status_t status;
0409 efi_guid_t *vd = NULL;
0410 efi_guid_t vendor_guid;
0411 efi_char16_t *name = NULL;
0412 int rv = 0;
0413
0414 getnextvariablename_user = (struct efi_getnextvariablename __user *)arg;
0415
0416 if (copy_from_user(&getnextvariablename, getnextvariablename_user,
0417 sizeof(getnextvariablename)))
0418 return -EFAULT;
0419
0420 if (getnextvariablename.variable_name_size) {
0421 if (get_user(name_size, getnextvariablename.variable_name_size))
0422 return -EFAULT;
0423 ns = &name_size;
0424 prev_name_size = name_size;
0425 }
0426
0427 if (getnextvariablename.vendor_guid) {
0428 if (copy_from_user(&vendor_guid,
0429 getnextvariablename.vendor_guid,
0430 sizeof(vendor_guid)))
0431 return -EFAULT;
0432 vd = &vendor_guid;
0433 }
0434
0435 if (getnextvariablename.variable_name) {
0436 size_t name_string_size = 0;
0437
0438 rv = get_ucs2_strsize_from_user(
0439 getnextvariablename.variable_name,
0440 &name_string_size);
0441 if (rv)
0442 return rv;
0443
0444
0445
0446
0447
0448
0449
0450
0451 rv = copy_ucs2_from_user_len(&name,
0452 getnextvariablename.variable_name,
0453 prev_name_size > name_string_size ?
0454 prev_name_size : name_string_size);
0455 if (rv)
0456 return rv;
0457 }
0458
0459 status = efi.get_next_variable(ns, name, vd);
0460
0461 if (put_user(status, getnextvariablename.status)) {
0462 rv = -EFAULT;
0463 goto out;
0464 }
0465
0466 if (status != EFI_SUCCESS) {
0467 if (status == EFI_BUFFER_TOO_SMALL) {
0468 if (ns && put_user(*ns,
0469 getnextvariablename.variable_name_size)) {
0470 rv = -EFAULT;
0471 goto out;
0472 }
0473 }
0474 rv = -EINVAL;
0475 goto out;
0476 }
0477
0478 if (name) {
0479 if (copy_ucs2_to_user_len(getnextvariablename.variable_name,
0480 name, prev_name_size)) {
0481 rv = -EFAULT;
0482 goto out;
0483 }
0484 }
0485
0486 if (ns) {
0487 if (put_user(*ns, getnextvariablename.variable_name_size)) {
0488 rv = -EFAULT;
0489 goto out;
0490 }
0491 }
0492
0493 if (vd) {
0494 if (copy_to_user(getnextvariablename.vendor_guid, vd,
0495 sizeof(efi_guid_t)))
0496 rv = -EFAULT;
0497 }
0498
0499 out:
0500 kfree(name);
0501 return rv;
0502 }
0503
0504 static long efi_runtime_get_nexthighmonocount(unsigned long arg)
0505 {
0506 struct efi_getnexthighmonotoniccount __user *getnexthighmonocount_user;
0507 struct efi_getnexthighmonotoniccount getnexthighmonocount;
0508 efi_status_t status;
0509 u32 count;
0510
0511 getnexthighmonocount_user = (struct
0512 efi_getnexthighmonotoniccount __user *)arg;
0513
0514 if (copy_from_user(&getnexthighmonocount,
0515 getnexthighmonocount_user,
0516 sizeof(getnexthighmonocount)))
0517 return -EFAULT;
0518
0519 status = efi.get_next_high_mono_count(
0520 getnexthighmonocount.high_count ? &count : NULL);
0521
0522 if (put_user(status, getnexthighmonocount.status))
0523 return -EFAULT;
0524
0525 if (status != EFI_SUCCESS)
0526 return -EINVAL;
0527
0528 if (getnexthighmonocount.high_count &&
0529 put_user(count, getnexthighmonocount.high_count))
0530 return -EFAULT;
0531
0532 return 0;
0533 }
0534
0535 static long efi_runtime_reset_system(unsigned long arg)
0536 {
0537 struct efi_resetsystem __user *resetsystem_user;
0538 struct efi_resetsystem resetsystem;
0539 void *data = NULL;
0540
0541 resetsystem_user = (struct efi_resetsystem __user *)arg;
0542 if (copy_from_user(&resetsystem, resetsystem_user,
0543 sizeof(resetsystem)))
0544 return -EFAULT;
0545 if (resetsystem.data_size != 0) {
0546 data = memdup_user((void *)resetsystem.data,
0547 resetsystem.data_size);
0548 if (IS_ERR(data))
0549 return PTR_ERR(data);
0550 }
0551
0552 efi.reset_system(resetsystem.reset_type, resetsystem.status,
0553 resetsystem.data_size, (efi_char16_t *)data);
0554
0555 kfree(data);
0556 return 0;
0557 }
0558
0559 static long efi_runtime_query_variableinfo(unsigned long arg)
0560 {
0561 struct efi_queryvariableinfo __user *queryvariableinfo_user;
0562 struct efi_queryvariableinfo queryvariableinfo;
0563 efi_status_t status;
0564 u64 max_storage, remaining, max_size;
0565
0566 queryvariableinfo_user = (struct efi_queryvariableinfo __user *)arg;
0567
0568 if (copy_from_user(&queryvariableinfo, queryvariableinfo_user,
0569 sizeof(queryvariableinfo)))
0570 return -EFAULT;
0571
0572 status = efi.query_variable_info(queryvariableinfo.attributes,
0573 &max_storage, &remaining, &max_size);
0574
0575 if (put_user(status, queryvariableinfo.status))
0576 return -EFAULT;
0577
0578 if (status != EFI_SUCCESS)
0579 return -EINVAL;
0580
0581 if (put_user(max_storage,
0582 queryvariableinfo.maximum_variable_storage_size))
0583 return -EFAULT;
0584
0585 if (put_user(remaining,
0586 queryvariableinfo.remaining_variable_storage_size))
0587 return -EFAULT;
0588
0589 if (put_user(max_size, queryvariableinfo.maximum_variable_size))
0590 return -EFAULT;
0591
0592 return 0;
0593 }
0594
0595 static long efi_runtime_query_capsulecaps(unsigned long arg)
0596 {
0597 struct efi_querycapsulecapabilities __user *qcaps_user;
0598 struct efi_querycapsulecapabilities qcaps;
0599 efi_capsule_header_t *capsules;
0600 efi_status_t status;
0601 u64 max_size;
0602 int i, reset_type;
0603 int rv = 0;
0604
0605 qcaps_user = (struct efi_querycapsulecapabilities __user *)arg;
0606
0607 if (copy_from_user(&qcaps, qcaps_user, sizeof(qcaps)))
0608 return -EFAULT;
0609
0610 if (qcaps.capsule_count == ULONG_MAX)
0611 return -EINVAL;
0612
0613 capsules = kcalloc(qcaps.capsule_count + 1,
0614 sizeof(efi_capsule_header_t), GFP_KERNEL);
0615 if (!capsules)
0616 return -ENOMEM;
0617
0618 for (i = 0; i < qcaps.capsule_count; i++) {
0619 efi_capsule_header_t *c;
0620
0621
0622
0623
0624
0625 if (get_user(c, qcaps.capsule_header_array + i)) {
0626 rv = -EFAULT;
0627 goto out;
0628 }
0629 if (copy_from_user(&capsules[i], c,
0630 sizeof(efi_capsule_header_t))) {
0631 rv = -EFAULT;
0632 goto out;
0633 }
0634 }
0635
0636 qcaps.capsule_header_array = &capsules;
0637
0638 status = efi.query_capsule_caps((efi_capsule_header_t **)
0639 qcaps.capsule_header_array,
0640 qcaps.capsule_count,
0641 &max_size, &reset_type);
0642
0643 if (put_user(status, qcaps.status)) {
0644 rv = -EFAULT;
0645 goto out;
0646 }
0647
0648 if (status != EFI_SUCCESS) {
0649 rv = -EINVAL;
0650 goto out;
0651 }
0652
0653 if (put_user(max_size, qcaps.maximum_capsule_size)) {
0654 rv = -EFAULT;
0655 goto out;
0656 }
0657
0658 if (put_user(reset_type, qcaps.reset_type))
0659 rv = -EFAULT;
0660
0661 out:
0662 kfree(capsules);
0663 return rv;
0664 }
0665
0666 static long efi_runtime_get_supported_mask(unsigned long arg)
0667 {
0668 unsigned int __user *supported_mask;
0669 int rv = 0;
0670
0671 supported_mask = (unsigned int *)arg;
0672
0673 if (put_user(efi.runtime_supported_mask, supported_mask))
0674 rv = -EFAULT;
0675
0676 return rv;
0677 }
0678
0679 static long efi_test_ioctl(struct file *file, unsigned int cmd,
0680 unsigned long arg)
0681 {
0682 switch (cmd) {
0683 case EFI_RUNTIME_GET_VARIABLE:
0684 return efi_runtime_get_variable(arg);
0685
0686 case EFI_RUNTIME_SET_VARIABLE:
0687 return efi_runtime_set_variable(arg);
0688
0689 case EFI_RUNTIME_GET_TIME:
0690 return efi_runtime_get_time(arg);
0691
0692 case EFI_RUNTIME_SET_TIME:
0693 return efi_runtime_set_time(arg);
0694
0695 case EFI_RUNTIME_GET_WAKETIME:
0696 return efi_runtime_get_waketime(arg);
0697
0698 case EFI_RUNTIME_SET_WAKETIME:
0699 return efi_runtime_set_waketime(arg);
0700
0701 case EFI_RUNTIME_GET_NEXTVARIABLENAME:
0702 return efi_runtime_get_nextvariablename(arg);
0703
0704 case EFI_RUNTIME_GET_NEXTHIGHMONOTONICCOUNT:
0705 return efi_runtime_get_nexthighmonocount(arg);
0706
0707 case EFI_RUNTIME_QUERY_VARIABLEINFO:
0708 return efi_runtime_query_variableinfo(arg);
0709
0710 case EFI_RUNTIME_QUERY_CAPSULECAPABILITIES:
0711 return efi_runtime_query_capsulecaps(arg);
0712
0713 case EFI_RUNTIME_RESET_SYSTEM:
0714 return efi_runtime_reset_system(arg);
0715
0716 case EFI_RUNTIME_GET_SUPPORTED_MASK:
0717 return efi_runtime_get_supported_mask(arg);
0718 }
0719
0720 return -ENOTTY;
0721 }
0722
0723 static int efi_test_open(struct inode *inode, struct file *file)
0724 {
0725 int ret = security_locked_down(LOCKDOWN_EFI_TEST);
0726
0727 if (ret)
0728 return ret;
0729
0730 if (!capable(CAP_SYS_ADMIN))
0731 return -EACCES;
0732
0733
0734
0735
0736
0737 return 0;
0738 }
0739
0740 static int efi_test_close(struct inode *inode, struct file *file)
0741 {
0742 return 0;
0743 }
0744
0745
0746
0747
0748 static const struct file_operations efi_test_fops = {
0749 .owner = THIS_MODULE,
0750 .unlocked_ioctl = efi_test_ioctl,
0751 .open = efi_test_open,
0752 .release = efi_test_close,
0753 .llseek = no_llseek,
0754 };
0755
0756 static struct miscdevice efi_test_dev = {
0757 MISC_DYNAMIC_MINOR,
0758 "efi_test",
0759 &efi_test_fops
0760 };
0761
0762 static int __init efi_test_init(void)
0763 {
0764 int ret;
0765
0766 ret = misc_register(&efi_test_dev);
0767 if (ret) {
0768 pr_err("efi_test: can't misc_register on minor=%d\n",
0769 MISC_DYNAMIC_MINOR);
0770 return ret;
0771 }
0772
0773 return 0;
0774 }
0775
0776 static void __exit efi_test_exit(void)
0777 {
0778 misc_deregister(&efi_test_dev);
0779 }
0780
0781 module_init(efi_test_init);
0782 module_exit(efi_test_exit);