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