This source file includes following definitions.
- user_ucs2_strsize
- copy_ucs2_from_user_len
- get_ucs2_strsize_from_user
- copy_ucs2_from_user
- copy_ucs2_to_user_len
- efi_runtime_get_variable
- efi_runtime_set_variable
- efi_runtime_get_time
- efi_runtime_set_time
- efi_runtime_get_waketime
- efi_runtime_set_waketime
- efi_runtime_get_nextvariablename
- efi_runtime_get_nexthighmonocount
- efi_runtime_reset_system
- efi_runtime_query_variableinfo
- efi_runtime_query_capsulecaps
- efi_test_ioctl
- efi_test_open
- efi_test_close
- efi_test_init
- efi_test_exit
1
2
3
4
5
6
7
8
9
10
11
12 #include <linux/miscdevice.h>
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/proc_fs.h>
16 #include <linux/efi.h>
17 #include <linux/security.h>
18 #include <linux/slab.h>
19 #include <linux/uaccess.h>
20
21 #include "efi_test.h"
22
23 MODULE_AUTHOR("Ivan Hu <ivan.hu@canonical.com>");
24 MODULE_DESCRIPTION("EFI Test Driver");
25 MODULE_LICENSE("GPL");
26
27
28
29
30
31
32
33 static inline size_t user_ucs2_strsize(efi_char16_t __user *str)
34 {
35 efi_char16_t *s = str, c;
36 size_t len;
37
38 if (!str)
39 return 0;
40
41
42 len = sizeof(efi_char16_t);
43
44 if (get_user(c, s++)) {
45
46 return 0;
47 }
48
49 while (c != 0) {
50 if (get_user(c, s++)) {
51
52 return 0;
53 }
54 len += sizeof(efi_char16_t);
55 }
56 return len;
57 }
58
59
60
61
62 static inline int
63 copy_ucs2_from_user_len(efi_char16_t **dst, efi_char16_t __user *src,
64 size_t len)
65 {
66 efi_char16_t *buf;
67
68 if (!src) {
69 *dst = NULL;
70 return 0;
71 }
72
73 if (!access_ok(src, 1))
74 return -EFAULT;
75
76 buf = memdup_user(src, len);
77 if (IS_ERR(buf)) {
78 *dst = NULL;
79 return PTR_ERR(buf);
80 }
81 *dst = buf;
82
83 return 0;
84 }
85
86
87
88
89
90
91 static inline int
92 get_ucs2_strsize_from_user(efi_char16_t __user *src, size_t *len)
93 {
94 if (!access_ok(src, 1))
95 return -EFAULT;
96
97 *len = user_ucs2_strsize(src);
98 if (*len == 0)
99 return -EFAULT;
100
101 return 0;
102 }
103
104
105
106
107
108
109
110
111
112
113
114
115
116 static inline int
117 copy_ucs2_from_user(efi_char16_t **dst, efi_char16_t __user *src)
118 {
119 size_t len;
120
121 if (!access_ok(src, 1))
122 return -EFAULT;
123
124 len = user_ucs2_strsize(src);
125 if (len == 0)
126 return -EFAULT;
127 return copy_ucs2_from_user_len(dst, src, len);
128 }
129
130
131
132
133
134
135
136
137
138
139 static inline int
140 copy_ucs2_to_user_len(efi_char16_t __user *dst, efi_char16_t *src, size_t len)
141 {
142 if (!src)
143 return 0;
144
145 if (!access_ok(dst, 1))
146 return -EFAULT;
147
148 return copy_to_user(dst, src, len);
149 }
150
151 static long efi_runtime_get_variable(unsigned long arg)
152 {
153 struct efi_getvariable __user *getvariable_user;
154 struct efi_getvariable getvariable;
155 unsigned long datasize = 0, prev_datasize, *dz;
156 efi_guid_t vendor_guid, *vd = NULL;
157 efi_status_t status;
158 efi_char16_t *name = NULL;
159 u32 attr, *at;
160 void *data = NULL;
161 int rv = 0;
162
163 getvariable_user = (struct efi_getvariable __user *)arg;
164
165 if (copy_from_user(&getvariable, getvariable_user,
166 sizeof(getvariable)))
167 return -EFAULT;
168 if (getvariable.data_size &&
169 get_user(datasize, getvariable.data_size))
170 return -EFAULT;
171 if (getvariable.vendor_guid) {
172 if (copy_from_user(&vendor_guid, getvariable.vendor_guid,
173 sizeof(vendor_guid)))
174 return -EFAULT;
175 vd = &vendor_guid;
176 }
177
178 if (getvariable.variable_name) {
179 rv = copy_ucs2_from_user(&name, getvariable.variable_name);
180 if (rv)
181 return rv;
182 }
183
184 at = getvariable.attributes ? &attr : NULL;
185 dz = getvariable.data_size ? &datasize : NULL;
186
187 if (getvariable.data_size && getvariable.data) {
188 data = kmalloc(datasize, GFP_KERNEL);
189 if (!data) {
190 kfree(name);
191 return -ENOMEM;
192 }
193 }
194
195 prev_datasize = datasize;
196 status = efi.get_variable(name, vd, at, dz, data);
197 kfree(name);
198
199 if (put_user(status, getvariable.status)) {
200 rv = -EFAULT;
201 goto out;
202 }
203
204 if (status != EFI_SUCCESS) {
205 if (status == EFI_BUFFER_TOO_SMALL) {
206 if (dz && put_user(datasize, getvariable.data_size)) {
207 rv = -EFAULT;
208 goto out;
209 }
210 }
211 rv = -EINVAL;
212 goto out;
213 }
214
215 if (prev_datasize < datasize) {
216 rv = -EINVAL;
217 goto out;
218 }
219
220 if (data) {
221 if (copy_to_user(getvariable.data, data, datasize)) {
222 rv = -EFAULT;
223 goto out;
224 }
225 }
226
227 if (at && put_user(attr, getvariable.attributes)) {
228 rv = -EFAULT;
229 goto out;
230 }
231
232 if (dz && put_user(datasize, getvariable.data_size))
233 rv = -EFAULT;
234
235 out:
236 kfree(data);
237 return rv;
238
239 }
240
241 static long efi_runtime_set_variable(unsigned long arg)
242 {
243 struct efi_setvariable __user *setvariable_user;
244 struct efi_setvariable setvariable;
245 efi_guid_t vendor_guid;
246 efi_status_t status;
247 efi_char16_t *name = NULL;
248 void *data;
249 int rv = 0;
250
251 setvariable_user = (struct efi_setvariable __user *)arg;
252
253 if (copy_from_user(&setvariable, setvariable_user, sizeof(setvariable)))
254 return -EFAULT;
255 if (copy_from_user(&vendor_guid, setvariable.vendor_guid,
256 sizeof(vendor_guid)))
257 return -EFAULT;
258
259 if (setvariable.variable_name) {
260 rv = copy_ucs2_from_user(&name, setvariable.variable_name);
261 if (rv)
262 return rv;
263 }
264
265 data = memdup_user(setvariable.data, setvariable.data_size);
266 if (IS_ERR(data)) {
267 kfree(name);
268 return PTR_ERR(data);
269 }
270
271 status = efi.set_variable(name, &vendor_guid,
272 setvariable.attributes,
273 setvariable.data_size, data);
274
275 if (put_user(status, setvariable.status)) {
276 rv = -EFAULT;
277 goto out;
278 }
279
280 rv = status == EFI_SUCCESS ? 0 : -EINVAL;
281
282 out:
283 kfree(data);
284 kfree(name);
285
286 return rv;
287 }
288
289 static long efi_runtime_get_time(unsigned long arg)
290 {
291 struct efi_gettime __user *gettime_user;
292 struct efi_gettime gettime;
293 efi_status_t status;
294 efi_time_cap_t cap;
295 efi_time_t efi_time;
296
297 gettime_user = (struct efi_gettime __user *)arg;
298 if (copy_from_user(&gettime, gettime_user, sizeof(gettime)))
299 return -EFAULT;
300
301 status = efi.get_time(gettime.time ? &efi_time : NULL,
302 gettime.capabilities ? &cap : NULL);
303
304 if (put_user(status, gettime.status))
305 return -EFAULT;
306
307 if (status != EFI_SUCCESS)
308 return -EINVAL;
309
310 if (gettime.capabilities) {
311 efi_time_cap_t __user *cap_local;
312
313 cap_local = (efi_time_cap_t *)gettime.capabilities;
314 if (put_user(cap.resolution, &(cap_local->resolution)) ||
315 put_user(cap.accuracy, &(cap_local->accuracy)) ||
316 put_user(cap.sets_to_zero, &(cap_local->sets_to_zero)))
317 return -EFAULT;
318 }
319 if (gettime.time) {
320 if (copy_to_user(gettime.time, &efi_time, sizeof(efi_time_t)))
321 return -EFAULT;
322 }
323
324 return 0;
325 }
326
327 static long efi_runtime_set_time(unsigned long arg)
328 {
329 struct efi_settime __user *settime_user;
330 struct efi_settime settime;
331 efi_status_t status;
332 efi_time_t efi_time;
333
334 settime_user = (struct efi_settime __user *)arg;
335 if (copy_from_user(&settime, settime_user, sizeof(settime)))
336 return -EFAULT;
337 if (copy_from_user(&efi_time, settime.time,
338 sizeof(efi_time_t)))
339 return -EFAULT;
340 status = efi.set_time(&efi_time);
341
342 if (put_user(status, settime.status))
343 return -EFAULT;
344
345 return status == EFI_SUCCESS ? 0 : -EINVAL;
346 }
347
348 static long efi_runtime_get_waketime(unsigned long arg)
349 {
350 struct efi_getwakeuptime __user *getwakeuptime_user;
351 struct efi_getwakeuptime getwakeuptime;
352 efi_bool_t enabled, pending;
353 efi_status_t status;
354 efi_time_t efi_time;
355
356 getwakeuptime_user = (struct efi_getwakeuptime __user *)arg;
357 if (copy_from_user(&getwakeuptime, getwakeuptime_user,
358 sizeof(getwakeuptime)))
359 return -EFAULT;
360
361 status = efi.get_wakeup_time(
362 getwakeuptime.enabled ? (efi_bool_t *)&enabled : NULL,
363 getwakeuptime.pending ? (efi_bool_t *)&pending : NULL,
364 getwakeuptime.time ? &efi_time : NULL);
365
366 if (put_user(status, getwakeuptime.status))
367 return -EFAULT;
368
369 if (status != EFI_SUCCESS)
370 return -EINVAL;
371
372 if (getwakeuptime.enabled && put_user(enabled,
373 getwakeuptime.enabled))
374 return -EFAULT;
375
376 if (getwakeuptime.time) {
377 if (copy_to_user(getwakeuptime.time, &efi_time,
378 sizeof(efi_time_t)))
379 return -EFAULT;
380 }
381
382 return 0;
383 }
384
385 static long efi_runtime_set_waketime(unsigned long arg)
386 {
387 struct efi_setwakeuptime __user *setwakeuptime_user;
388 struct efi_setwakeuptime setwakeuptime;
389 efi_bool_t enabled;
390 efi_status_t status;
391 efi_time_t efi_time;
392
393 setwakeuptime_user = (struct efi_setwakeuptime __user *)arg;
394
395 if (copy_from_user(&setwakeuptime, setwakeuptime_user,
396 sizeof(setwakeuptime)))
397 return -EFAULT;
398
399 enabled = setwakeuptime.enabled;
400 if (setwakeuptime.time) {
401 if (copy_from_user(&efi_time, setwakeuptime.time,
402 sizeof(efi_time_t)))
403 return -EFAULT;
404
405 status = efi.set_wakeup_time(enabled, &efi_time);
406 } else
407 status = efi.set_wakeup_time(enabled, NULL);
408
409 if (put_user(status, setwakeuptime.status))
410 return -EFAULT;
411
412 return status == EFI_SUCCESS ? 0 : -EINVAL;
413 }
414
415 static long efi_runtime_get_nextvariablename(unsigned long arg)
416 {
417 struct efi_getnextvariablename __user *getnextvariablename_user;
418 struct efi_getnextvariablename getnextvariablename;
419 unsigned long name_size, prev_name_size = 0, *ns = NULL;
420 efi_status_t status;
421 efi_guid_t *vd = NULL;
422 efi_guid_t vendor_guid;
423 efi_char16_t *name = NULL;
424 int rv = 0;
425
426 getnextvariablename_user = (struct efi_getnextvariablename __user *)arg;
427
428 if (copy_from_user(&getnextvariablename, getnextvariablename_user,
429 sizeof(getnextvariablename)))
430 return -EFAULT;
431
432 if (getnextvariablename.variable_name_size) {
433 if (get_user(name_size, getnextvariablename.variable_name_size))
434 return -EFAULT;
435 ns = &name_size;
436 prev_name_size = name_size;
437 }
438
439 if (getnextvariablename.vendor_guid) {
440 if (copy_from_user(&vendor_guid,
441 getnextvariablename.vendor_guid,
442 sizeof(vendor_guid)))
443 return -EFAULT;
444 vd = &vendor_guid;
445 }
446
447 if (getnextvariablename.variable_name) {
448 size_t name_string_size = 0;
449
450 rv = get_ucs2_strsize_from_user(
451 getnextvariablename.variable_name,
452 &name_string_size);
453 if (rv)
454 return rv;
455
456
457
458
459
460
461
462
463 rv = copy_ucs2_from_user_len(&name,
464 getnextvariablename.variable_name,
465 prev_name_size > name_string_size ?
466 prev_name_size : name_string_size);
467 if (rv)
468 return rv;
469 }
470
471 status = efi.get_next_variable(ns, name, vd);
472
473 if (put_user(status, getnextvariablename.status)) {
474 rv = -EFAULT;
475 goto out;
476 }
477
478 if (status != EFI_SUCCESS) {
479 if (status == EFI_BUFFER_TOO_SMALL) {
480 if (ns && put_user(*ns,
481 getnextvariablename.variable_name_size)) {
482 rv = -EFAULT;
483 goto out;
484 }
485 }
486 rv = -EINVAL;
487 goto out;
488 }
489
490 if (name) {
491 if (copy_ucs2_to_user_len(getnextvariablename.variable_name,
492 name, prev_name_size)) {
493 rv = -EFAULT;
494 goto out;
495 }
496 }
497
498 if (ns) {
499 if (put_user(*ns, getnextvariablename.variable_name_size)) {
500 rv = -EFAULT;
501 goto out;
502 }
503 }
504
505 if (vd) {
506 if (copy_to_user(getnextvariablename.vendor_guid, vd,
507 sizeof(efi_guid_t)))
508 rv = -EFAULT;
509 }
510
511 out:
512 kfree(name);
513 return rv;
514 }
515
516 static long efi_runtime_get_nexthighmonocount(unsigned long arg)
517 {
518 struct efi_getnexthighmonotoniccount __user *getnexthighmonocount_user;
519 struct efi_getnexthighmonotoniccount getnexthighmonocount;
520 efi_status_t status;
521 u32 count;
522
523 getnexthighmonocount_user = (struct
524 efi_getnexthighmonotoniccount __user *)arg;
525
526 if (copy_from_user(&getnexthighmonocount,
527 getnexthighmonocount_user,
528 sizeof(getnexthighmonocount)))
529 return -EFAULT;
530
531 status = efi.get_next_high_mono_count(
532 getnexthighmonocount.high_count ? &count : NULL);
533
534 if (put_user(status, getnexthighmonocount.status))
535 return -EFAULT;
536
537 if (status != EFI_SUCCESS)
538 return -EINVAL;
539
540 if (getnexthighmonocount.high_count &&
541 put_user(count, getnexthighmonocount.high_count))
542 return -EFAULT;
543
544 return 0;
545 }
546
547 static long efi_runtime_reset_system(unsigned long arg)
548 {
549 struct efi_resetsystem __user *resetsystem_user;
550 struct efi_resetsystem resetsystem;
551 void *data = NULL;
552
553 resetsystem_user = (struct efi_resetsystem __user *)arg;
554 if (copy_from_user(&resetsystem, resetsystem_user,
555 sizeof(resetsystem)))
556 return -EFAULT;
557 if (resetsystem.data_size != 0) {
558 data = memdup_user((void *)resetsystem.data,
559 resetsystem.data_size);
560 if (IS_ERR(data))
561 return PTR_ERR(data);
562 }
563
564 efi.reset_system(resetsystem.reset_type, resetsystem.status,
565 resetsystem.data_size, (efi_char16_t *)data);
566
567 kfree(data);
568 return 0;
569 }
570
571 static long efi_runtime_query_variableinfo(unsigned long arg)
572 {
573 struct efi_queryvariableinfo __user *queryvariableinfo_user;
574 struct efi_queryvariableinfo queryvariableinfo;
575 efi_status_t status;
576 u64 max_storage, remaining, max_size;
577
578 queryvariableinfo_user = (struct efi_queryvariableinfo __user *)arg;
579
580 if (copy_from_user(&queryvariableinfo, queryvariableinfo_user,
581 sizeof(queryvariableinfo)))
582 return -EFAULT;
583
584 status = efi.query_variable_info(queryvariableinfo.attributes,
585 &max_storage, &remaining, &max_size);
586
587 if (put_user(status, queryvariableinfo.status))
588 return -EFAULT;
589
590 if (status != EFI_SUCCESS)
591 return -EINVAL;
592
593 if (put_user(max_storage,
594 queryvariableinfo.maximum_variable_storage_size))
595 return -EFAULT;
596
597 if (put_user(remaining,
598 queryvariableinfo.remaining_variable_storage_size))
599 return -EFAULT;
600
601 if (put_user(max_size, queryvariableinfo.maximum_variable_size))
602 return -EFAULT;
603
604 return 0;
605 }
606
607 static long efi_runtime_query_capsulecaps(unsigned long arg)
608 {
609 struct efi_querycapsulecapabilities __user *qcaps_user;
610 struct efi_querycapsulecapabilities qcaps;
611 efi_capsule_header_t *capsules;
612 efi_status_t status;
613 u64 max_size;
614 int i, reset_type;
615 int rv = 0;
616
617 qcaps_user = (struct efi_querycapsulecapabilities __user *)arg;
618
619 if (copy_from_user(&qcaps, qcaps_user, sizeof(qcaps)))
620 return -EFAULT;
621
622 if (qcaps.capsule_count == ULONG_MAX)
623 return -EINVAL;
624
625 capsules = kcalloc(qcaps.capsule_count + 1,
626 sizeof(efi_capsule_header_t), GFP_KERNEL);
627 if (!capsules)
628 return -ENOMEM;
629
630 for (i = 0; i < qcaps.capsule_count; i++) {
631 efi_capsule_header_t *c;
632
633
634
635
636
637 if (get_user(c, qcaps.capsule_header_array + i)) {
638 rv = -EFAULT;
639 goto out;
640 }
641 if (copy_from_user(&capsules[i], c,
642 sizeof(efi_capsule_header_t))) {
643 rv = -EFAULT;
644 goto out;
645 }
646 }
647
648 qcaps.capsule_header_array = &capsules;
649
650 status = efi.query_capsule_caps((efi_capsule_header_t **)
651 qcaps.capsule_header_array,
652 qcaps.capsule_count,
653 &max_size, &reset_type);
654
655 if (put_user(status, qcaps.status)) {
656 rv = -EFAULT;
657 goto out;
658 }
659
660 if (status != EFI_SUCCESS) {
661 rv = -EINVAL;
662 goto out;
663 }
664
665 if (put_user(max_size, qcaps.maximum_capsule_size)) {
666 rv = -EFAULT;
667 goto out;
668 }
669
670 if (put_user(reset_type, qcaps.reset_type))
671 rv = -EFAULT;
672
673 out:
674 kfree(capsules);
675 return rv;
676 }
677
678 static long efi_test_ioctl(struct file *file, unsigned int cmd,
679 unsigned long arg)
680 {
681 switch (cmd) {
682 case EFI_RUNTIME_GET_VARIABLE:
683 return efi_runtime_get_variable(arg);
684
685 case EFI_RUNTIME_SET_VARIABLE:
686 return efi_runtime_set_variable(arg);
687
688 case EFI_RUNTIME_GET_TIME:
689 return efi_runtime_get_time(arg);
690
691 case EFI_RUNTIME_SET_TIME:
692 return efi_runtime_set_time(arg);
693
694 case EFI_RUNTIME_GET_WAKETIME:
695 return efi_runtime_get_waketime(arg);
696
697 case EFI_RUNTIME_SET_WAKETIME:
698 return efi_runtime_set_waketime(arg);
699
700 case EFI_RUNTIME_GET_NEXTVARIABLENAME:
701 return efi_runtime_get_nextvariablename(arg);
702
703 case EFI_RUNTIME_GET_NEXTHIGHMONOTONICCOUNT:
704 return efi_runtime_get_nexthighmonocount(arg);
705
706 case EFI_RUNTIME_QUERY_VARIABLEINFO:
707 return efi_runtime_query_variableinfo(arg);
708
709 case EFI_RUNTIME_QUERY_CAPSULECAPABILITIES:
710 return efi_runtime_query_capsulecaps(arg);
711
712 case EFI_RUNTIME_RESET_SYSTEM:
713 return efi_runtime_reset_system(arg);
714 }
715
716 return -ENOTTY;
717 }
718
719 static int efi_test_open(struct inode *inode, struct file *file)
720 {
721 int ret = security_locked_down(LOCKDOWN_EFI_TEST);
722
723 if (ret)
724 return ret;
725
726 if (!capable(CAP_SYS_ADMIN))
727 return -EACCES;
728
729
730
731
732
733 return 0;
734 }
735
736 static int efi_test_close(struct inode *inode, struct file *file)
737 {
738 return 0;
739 }
740
741
742
743
744 static const struct file_operations efi_test_fops = {
745 .owner = THIS_MODULE,
746 .unlocked_ioctl = efi_test_ioctl,
747 .open = efi_test_open,
748 .release = efi_test_close,
749 .llseek = no_llseek,
750 };
751
752 static struct miscdevice efi_test_dev = {
753 MISC_DYNAMIC_MINOR,
754 "efi_test",
755 &efi_test_fops
756 };
757
758 static int __init efi_test_init(void)
759 {
760 int ret;
761
762 ret = misc_register(&efi_test_dev);
763 if (ret) {
764 pr_err("efi_test: can't misc_register on minor=%d\n",
765 MISC_DYNAMIC_MINOR);
766 return ret;
767 }
768
769 return 0;
770 }
771
772 static void __exit efi_test_exit(void)
773 {
774 misc_deregister(&efi_test_dev);
775 }
776
777 module_init(efi_test_init);
778 module_exit(efi_test_exit);