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