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 74*5f72cad6SGeliang Tang buf = memdup_user(src, len); 75*5f72cad6SGeliang Tang if (IS_ERR(buf)) { 76ff6301daSIvan Hu *dst = NULL; 77*5f72cad6SGeliang 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 545ff6301daSIvan Hu static long efi_runtime_query_variableinfo(unsigned long arg) 546ff6301daSIvan Hu { 547ff6301daSIvan Hu struct efi_queryvariableinfo __user *queryvariableinfo_user; 548ff6301daSIvan Hu struct efi_queryvariableinfo queryvariableinfo; 549ff6301daSIvan Hu efi_status_t status; 550ff6301daSIvan Hu u64 max_storage, remaining, max_size; 551ff6301daSIvan Hu 552ff6301daSIvan Hu queryvariableinfo_user = (struct efi_queryvariableinfo __user *)arg; 553ff6301daSIvan Hu 554ff6301daSIvan Hu if (copy_from_user(&queryvariableinfo, queryvariableinfo_user, 555ff6301daSIvan Hu sizeof(queryvariableinfo))) 556ff6301daSIvan Hu return -EFAULT; 557ff6301daSIvan Hu 558ff6301daSIvan Hu status = efi.query_variable_info(queryvariableinfo.attributes, 559ff6301daSIvan Hu &max_storage, &remaining, &max_size); 560ff6301daSIvan Hu 561ff6301daSIvan Hu if (put_user(status, queryvariableinfo.status)) 562ff6301daSIvan Hu return -EFAULT; 563ff6301daSIvan Hu 564ff6301daSIvan Hu if (status != EFI_SUCCESS) 565ff6301daSIvan Hu return -EINVAL; 566ff6301daSIvan Hu 567ff6301daSIvan Hu if (put_user(max_storage, 568ff6301daSIvan Hu queryvariableinfo.maximum_variable_storage_size)) 569ff6301daSIvan Hu return -EFAULT; 570ff6301daSIvan Hu 571ff6301daSIvan Hu if (put_user(remaining, 572ff6301daSIvan Hu queryvariableinfo.remaining_variable_storage_size)) 573ff6301daSIvan Hu return -EFAULT; 574ff6301daSIvan Hu 575ff6301daSIvan Hu if (put_user(max_size, queryvariableinfo.maximum_variable_size)) 576ff6301daSIvan Hu return -EFAULT; 577ff6301daSIvan Hu 578ff6301daSIvan Hu return 0; 579ff6301daSIvan Hu } 580ff6301daSIvan Hu 581ff6301daSIvan Hu static long efi_runtime_query_capsulecaps(unsigned long arg) 582ff6301daSIvan Hu { 583ff6301daSIvan Hu struct efi_querycapsulecapabilities __user *qcaps_user; 584ff6301daSIvan Hu struct efi_querycapsulecapabilities qcaps; 585ff6301daSIvan Hu efi_capsule_header_t *capsules; 586ff6301daSIvan Hu efi_status_t status; 587ff6301daSIvan Hu u64 max_size; 588ff6301daSIvan Hu int i, reset_type; 589ff6301daSIvan Hu int rv = 0; 590ff6301daSIvan Hu 591ff6301daSIvan Hu qcaps_user = (struct efi_querycapsulecapabilities __user *)arg; 592ff6301daSIvan Hu 593ff6301daSIvan Hu if (copy_from_user(&qcaps, qcaps_user, sizeof(qcaps))) 594ff6301daSIvan Hu return -EFAULT; 595ff6301daSIvan Hu 596ff6301daSIvan Hu capsules = kcalloc(qcaps.capsule_count + 1, 597ff6301daSIvan Hu sizeof(efi_capsule_header_t), GFP_KERNEL); 598ff6301daSIvan Hu if (!capsules) 599ff6301daSIvan Hu return -ENOMEM; 600ff6301daSIvan Hu 601ff6301daSIvan Hu for (i = 0; i < qcaps.capsule_count; i++) { 602ff6301daSIvan Hu efi_capsule_header_t *c; 603ff6301daSIvan Hu /* 604ff6301daSIvan Hu * We cannot dereference qcaps.capsule_header_array directly to 605ff6301daSIvan Hu * obtain the address of the capsule as it resides in the 606ff6301daSIvan Hu * user space 607ff6301daSIvan Hu */ 608ff6301daSIvan Hu if (get_user(c, qcaps.capsule_header_array + i)) { 609ff6301daSIvan Hu rv = -EFAULT; 610ff6301daSIvan Hu goto out; 611ff6301daSIvan Hu } 612ff6301daSIvan Hu if (copy_from_user(&capsules[i], c, 613ff6301daSIvan Hu sizeof(efi_capsule_header_t))) { 614ff6301daSIvan Hu rv = -EFAULT; 615ff6301daSIvan Hu goto out; 616ff6301daSIvan Hu } 617ff6301daSIvan Hu } 618ff6301daSIvan Hu 619ff6301daSIvan Hu qcaps.capsule_header_array = &capsules; 620ff6301daSIvan Hu 621ff6301daSIvan Hu status = efi.query_capsule_caps((efi_capsule_header_t **) 622ff6301daSIvan Hu qcaps.capsule_header_array, 623ff6301daSIvan Hu qcaps.capsule_count, 624ff6301daSIvan Hu &max_size, &reset_type); 625ff6301daSIvan Hu 626ff6301daSIvan Hu if (put_user(status, qcaps.status)) { 627ff6301daSIvan Hu rv = -EFAULT; 628ff6301daSIvan Hu goto out; 629ff6301daSIvan Hu } 630ff6301daSIvan Hu 631ff6301daSIvan Hu if (status != EFI_SUCCESS) { 632ff6301daSIvan Hu rv = -EINVAL; 633ff6301daSIvan Hu goto out; 634ff6301daSIvan Hu } 635ff6301daSIvan Hu 636ff6301daSIvan Hu if (put_user(max_size, qcaps.maximum_capsule_size)) { 637ff6301daSIvan Hu rv = -EFAULT; 638ff6301daSIvan Hu goto out; 639ff6301daSIvan Hu } 640ff6301daSIvan Hu 641ff6301daSIvan Hu if (put_user(reset_type, qcaps.reset_type)) 642ff6301daSIvan Hu rv = -EFAULT; 643ff6301daSIvan Hu 644ff6301daSIvan Hu out: 645ff6301daSIvan Hu kfree(capsules); 646ff6301daSIvan Hu return rv; 647ff6301daSIvan Hu } 648ff6301daSIvan Hu 649ff6301daSIvan Hu static long efi_test_ioctl(struct file *file, unsigned int cmd, 650ff6301daSIvan Hu unsigned long arg) 651ff6301daSIvan Hu { 652ff6301daSIvan Hu switch (cmd) { 653ff6301daSIvan Hu case EFI_RUNTIME_GET_VARIABLE: 654ff6301daSIvan Hu return efi_runtime_get_variable(arg); 655ff6301daSIvan Hu 656ff6301daSIvan Hu case EFI_RUNTIME_SET_VARIABLE: 657ff6301daSIvan Hu return efi_runtime_set_variable(arg); 658ff6301daSIvan Hu 659ff6301daSIvan Hu case EFI_RUNTIME_GET_TIME: 660ff6301daSIvan Hu return efi_runtime_get_time(arg); 661ff6301daSIvan Hu 662ff6301daSIvan Hu case EFI_RUNTIME_SET_TIME: 663ff6301daSIvan Hu return efi_runtime_set_time(arg); 664ff6301daSIvan Hu 665ff6301daSIvan Hu case EFI_RUNTIME_GET_WAKETIME: 666ff6301daSIvan Hu return efi_runtime_get_waketime(arg); 667ff6301daSIvan Hu 668ff6301daSIvan Hu case EFI_RUNTIME_SET_WAKETIME: 669ff6301daSIvan Hu return efi_runtime_set_waketime(arg); 670ff6301daSIvan Hu 671ff6301daSIvan Hu case EFI_RUNTIME_GET_NEXTVARIABLENAME: 672ff6301daSIvan Hu return efi_runtime_get_nextvariablename(arg); 673ff6301daSIvan Hu 674ff6301daSIvan Hu case EFI_RUNTIME_GET_NEXTHIGHMONOTONICCOUNT: 675ff6301daSIvan Hu return efi_runtime_get_nexthighmonocount(arg); 676ff6301daSIvan Hu 677ff6301daSIvan Hu case EFI_RUNTIME_QUERY_VARIABLEINFO: 678ff6301daSIvan Hu return efi_runtime_query_variableinfo(arg); 679ff6301daSIvan Hu 680ff6301daSIvan Hu case EFI_RUNTIME_QUERY_CAPSULECAPABILITIES: 681ff6301daSIvan Hu return efi_runtime_query_capsulecaps(arg); 682ff6301daSIvan Hu } 683ff6301daSIvan Hu 684ff6301daSIvan Hu return -ENOTTY; 685ff6301daSIvan Hu } 686ff6301daSIvan Hu 687ff6301daSIvan Hu static int efi_test_open(struct inode *inode, struct file *file) 688ff6301daSIvan Hu { 689ff6301daSIvan Hu /* 690ff6301daSIvan Hu * nothing special to do here 691ff6301daSIvan Hu * We do accept multiple open files at the same time as we 692ff6301daSIvan Hu * synchronize on the per call operation. 693ff6301daSIvan Hu */ 694ff6301daSIvan Hu return 0; 695ff6301daSIvan Hu } 696ff6301daSIvan Hu 697ff6301daSIvan Hu static int efi_test_close(struct inode *inode, struct file *file) 698ff6301daSIvan Hu { 699ff6301daSIvan Hu return 0; 700ff6301daSIvan Hu } 701ff6301daSIvan Hu 702ff6301daSIvan Hu /* 703ff6301daSIvan Hu * The various file operations we support. 704ff6301daSIvan Hu */ 705ff6301daSIvan Hu static const struct file_operations efi_test_fops = { 706ff6301daSIvan Hu .owner = THIS_MODULE, 707ff6301daSIvan Hu .unlocked_ioctl = efi_test_ioctl, 708ff6301daSIvan Hu .open = efi_test_open, 709ff6301daSIvan Hu .release = efi_test_close, 710ff6301daSIvan Hu .llseek = no_llseek, 711ff6301daSIvan Hu }; 712ff6301daSIvan Hu 713ff6301daSIvan Hu static struct miscdevice efi_test_dev = { 714ff6301daSIvan Hu MISC_DYNAMIC_MINOR, 715ff6301daSIvan Hu "efi_test", 716ff6301daSIvan Hu &efi_test_fops 717ff6301daSIvan Hu }; 718ff6301daSIvan Hu 719ff6301daSIvan Hu static int __init efi_test_init(void) 720ff6301daSIvan Hu { 721ff6301daSIvan Hu int ret; 722ff6301daSIvan Hu 723ff6301daSIvan Hu ret = misc_register(&efi_test_dev); 724ff6301daSIvan Hu if (ret) { 725ff6301daSIvan Hu pr_err("efi_test: can't misc_register on minor=%d\n", 726ff6301daSIvan Hu MISC_DYNAMIC_MINOR); 727ff6301daSIvan Hu return ret; 728ff6301daSIvan Hu } 729ff6301daSIvan Hu 730ff6301daSIvan Hu return 0; 731ff6301daSIvan Hu } 732ff6301daSIvan Hu 733ff6301daSIvan Hu static void __exit efi_test_exit(void) 734ff6301daSIvan Hu { 735ff6301daSIvan Hu misc_deregister(&efi_test_dev); 736ff6301daSIvan Hu } 737ff6301daSIvan Hu 738ff6301daSIvan Hu module_init(efi_test_init); 739ff6301daSIvan Hu module_exit(efi_test_exit); 740