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; 15846b9b713SIvan 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 268*c208ed91SIvan Hu data = memdup_user(setvariable.data, setvariable.data_size); 269*c208ed91SIvan Hu if (IS_ERR(data)) { 270ff6301daSIvan Hu kfree(name); 271*c208ed91SIvan Hu return PTR_ERR(data); 272ff6301daSIvan Hu } 273ff6301daSIvan Hu 274ff6301daSIvan Hu status = efi.set_variable(name, &vendor_guid, 275ff6301daSIvan Hu setvariable.attributes, 276ff6301daSIvan Hu setvariable.data_size, data); 277ff6301daSIvan Hu 278ff6301daSIvan Hu if (put_user(status, setvariable.status)) { 279ff6301daSIvan Hu rv = -EFAULT; 280ff6301daSIvan Hu goto out; 281ff6301daSIvan Hu } 282ff6301daSIvan Hu 283ff6301daSIvan Hu rv = status == EFI_SUCCESS ? 0 : -EINVAL; 284ff6301daSIvan Hu 285ff6301daSIvan Hu out: 286ff6301daSIvan Hu kfree(data); 287ff6301daSIvan Hu kfree(name); 288ff6301daSIvan Hu 289ff6301daSIvan Hu return rv; 290ff6301daSIvan Hu } 291ff6301daSIvan Hu 292ff6301daSIvan Hu static long efi_runtime_get_time(unsigned long arg) 293ff6301daSIvan Hu { 294ff6301daSIvan Hu struct efi_gettime __user *gettime_user; 295ff6301daSIvan Hu struct efi_gettime gettime; 296ff6301daSIvan Hu efi_status_t status; 297ff6301daSIvan Hu efi_time_cap_t cap; 298ff6301daSIvan Hu efi_time_t efi_time; 299ff6301daSIvan Hu 300ff6301daSIvan Hu gettime_user = (struct efi_gettime __user *)arg; 301ff6301daSIvan Hu if (copy_from_user(&gettime, gettime_user, sizeof(gettime))) 302ff6301daSIvan Hu return -EFAULT; 303ff6301daSIvan Hu 304ff6301daSIvan Hu status = efi.get_time(gettime.time ? &efi_time : NULL, 305ff6301daSIvan Hu gettime.capabilities ? &cap : NULL); 306ff6301daSIvan Hu 307ff6301daSIvan Hu if (put_user(status, gettime.status)) 308ff6301daSIvan Hu return -EFAULT; 309ff6301daSIvan Hu 310ff6301daSIvan Hu if (status != EFI_SUCCESS) 311ff6301daSIvan Hu return -EINVAL; 312ff6301daSIvan Hu 313ff6301daSIvan Hu if (gettime.capabilities) { 314ff6301daSIvan Hu efi_time_cap_t __user *cap_local; 315ff6301daSIvan Hu 316ff6301daSIvan Hu cap_local = (efi_time_cap_t *)gettime.capabilities; 317ff6301daSIvan Hu if (put_user(cap.resolution, &(cap_local->resolution)) || 318ff6301daSIvan Hu put_user(cap.accuracy, &(cap_local->accuracy)) || 319ff6301daSIvan Hu put_user(cap.sets_to_zero, &(cap_local->sets_to_zero))) 320ff6301daSIvan Hu return -EFAULT; 321ff6301daSIvan Hu } 322ff6301daSIvan Hu if (gettime.time) { 323ff6301daSIvan Hu if (copy_to_user(gettime.time, &efi_time, sizeof(efi_time_t))) 324ff6301daSIvan Hu return -EFAULT; 325ff6301daSIvan Hu } 326ff6301daSIvan Hu 327ff6301daSIvan Hu return 0; 328ff6301daSIvan Hu } 329ff6301daSIvan Hu 330ff6301daSIvan Hu static long efi_runtime_set_time(unsigned long arg) 331ff6301daSIvan Hu { 332ff6301daSIvan Hu struct efi_settime __user *settime_user; 333ff6301daSIvan Hu struct efi_settime settime; 334ff6301daSIvan Hu efi_status_t status; 335ff6301daSIvan Hu efi_time_t efi_time; 336ff6301daSIvan Hu 337ff6301daSIvan Hu settime_user = (struct efi_settime __user *)arg; 338ff6301daSIvan Hu if (copy_from_user(&settime, settime_user, sizeof(settime))) 339ff6301daSIvan Hu return -EFAULT; 340ff6301daSIvan Hu if (copy_from_user(&efi_time, settime.time, 341ff6301daSIvan Hu sizeof(efi_time_t))) 342ff6301daSIvan Hu return -EFAULT; 343ff6301daSIvan Hu status = efi.set_time(&efi_time); 344ff6301daSIvan Hu 345ff6301daSIvan Hu if (put_user(status, settime.status)) 346ff6301daSIvan Hu return -EFAULT; 347ff6301daSIvan Hu 348ff6301daSIvan Hu return status == EFI_SUCCESS ? 0 : -EINVAL; 349ff6301daSIvan Hu } 350ff6301daSIvan Hu 351ff6301daSIvan Hu static long efi_runtime_get_waketime(unsigned long arg) 352ff6301daSIvan Hu { 353ff6301daSIvan Hu struct efi_getwakeuptime __user *getwakeuptime_user; 354ff6301daSIvan Hu struct efi_getwakeuptime getwakeuptime; 355ff6301daSIvan Hu efi_bool_t enabled, pending; 356ff6301daSIvan Hu efi_status_t status; 357ff6301daSIvan Hu efi_time_t efi_time; 358ff6301daSIvan Hu 359ff6301daSIvan Hu getwakeuptime_user = (struct efi_getwakeuptime __user *)arg; 360ff6301daSIvan Hu if (copy_from_user(&getwakeuptime, getwakeuptime_user, 361ff6301daSIvan Hu sizeof(getwakeuptime))) 362ff6301daSIvan Hu return -EFAULT; 363ff6301daSIvan Hu 364ff6301daSIvan Hu status = efi.get_wakeup_time( 365ff6301daSIvan Hu getwakeuptime.enabled ? (efi_bool_t *)&enabled : NULL, 366ff6301daSIvan Hu getwakeuptime.pending ? (efi_bool_t *)&pending : NULL, 367ff6301daSIvan Hu getwakeuptime.time ? &efi_time : NULL); 368ff6301daSIvan Hu 369ff6301daSIvan Hu if (put_user(status, getwakeuptime.status)) 370ff6301daSIvan Hu return -EFAULT; 371ff6301daSIvan Hu 372ff6301daSIvan Hu if (status != EFI_SUCCESS) 373ff6301daSIvan Hu return -EINVAL; 374ff6301daSIvan Hu 375ff6301daSIvan Hu if (getwakeuptime.enabled && put_user(enabled, 376ff6301daSIvan Hu getwakeuptime.enabled)) 377ff6301daSIvan Hu return -EFAULT; 378ff6301daSIvan Hu 379ff6301daSIvan Hu if (getwakeuptime.time) { 380ff6301daSIvan Hu if (copy_to_user(getwakeuptime.time, &efi_time, 381ff6301daSIvan Hu sizeof(efi_time_t))) 382ff6301daSIvan Hu return -EFAULT; 383ff6301daSIvan Hu } 384ff6301daSIvan Hu 385ff6301daSIvan Hu return 0; 386ff6301daSIvan Hu } 387ff6301daSIvan Hu 388ff6301daSIvan Hu static long efi_runtime_set_waketime(unsigned long arg) 389ff6301daSIvan Hu { 390ff6301daSIvan Hu struct efi_setwakeuptime __user *setwakeuptime_user; 391ff6301daSIvan Hu struct efi_setwakeuptime setwakeuptime; 392ff6301daSIvan Hu efi_bool_t enabled; 393ff6301daSIvan Hu efi_status_t status; 394ff6301daSIvan Hu efi_time_t efi_time; 395ff6301daSIvan Hu 396ff6301daSIvan Hu setwakeuptime_user = (struct efi_setwakeuptime __user *)arg; 397ff6301daSIvan Hu 398ff6301daSIvan Hu if (copy_from_user(&setwakeuptime, setwakeuptime_user, 399ff6301daSIvan Hu sizeof(setwakeuptime))) 400ff6301daSIvan Hu return -EFAULT; 401ff6301daSIvan Hu 402ff6301daSIvan Hu enabled = setwakeuptime.enabled; 403ff6301daSIvan Hu if (setwakeuptime.time) { 404ff6301daSIvan Hu if (copy_from_user(&efi_time, setwakeuptime.time, 405ff6301daSIvan Hu sizeof(efi_time_t))) 406ff6301daSIvan Hu return -EFAULT; 407ff6301daSIvan Hu 408ff6301daSIvan Hu status = efi.set_wakeup_time(enabled, &efi_time); 409ff6301daSIvan Hu } else 410ff6301daSIvan Hu status = efi.set_wakeup_time(enabled, NULL); 411ff6301daSIvan Hu 412ff6301daSIvan Hu if (put_user(status, setwakeuptime.status)) 413ff6301daSIvan Hu return -EFAULT; 414ff6301daSIvan Hu 415ff6301daSIvan Hu return status == EFI_SUCCESS ? 0 : -EINVAL; 416ff6301daSIvan Hu } 417ff6301daSIvan Hu 418ff6301daSIvan Hu static long efi_runtime_get_nextvariablename(unsigned long arg) 419ff6301daSIvan Hu { 420ff6301daSIvan Hu struct efi_getnextvariablename __user *getnextvariablename_user; 421ff6301daSIvan Hu struct efi_getnextvariablename getnextvariablename; 422ff6301daSIvan Hu unsigned long name_size, prev_name_size = 0, *ns = NULL; 423ff6301daSIvan Hu efi_status_t status; 424ff6301daSIvan Hu efi_guid_t *vd = NULL; 425ff6301daSIvan Hu efi_guid_t vendor_guid; 426ff6301daSIvan Hu efi_char16_t *name = NULL; 4279c30a219SIvan Hu int rv = 0; 428ff6301daSIvan Hu 429ff6301daSIvan Hu getnextvariablename_user = (struct efi_getnextvariablename __user *)arg; 430ff6301daSIvan Hu 431ff6301daSIvan Hu if (copy_from_user(&getnextvariablename, getnextvariablename_user, 432ff6301daSIvan Hu sizeof(getnextvariablename))) 433ff6301daSIvan Hu return -EFAULT; 434ff6301daSIvan Hu 435ff6301daSIvan Hu if (getnextvariablename.variable_name_size) { 436ff6301daSIvan Hu if (get_user(name_size, getnextvariablename.variable_name_size)) 437ff6301daSIvan Hu return -EFAULT; 438ff6301daSIvan Hu ns = &name_size; 439ff6301daSIvan Hu prev_name_size = name_size; 440ff6301daSIvan Hu } 441ff6301daSIvan Hu 442ff6301daSIvan Hu if (getnextvariablename.vendor_guid) { 443ff6301daSIvan Hu if (copy_from_user(&vendor_guid, 444ff6301daSIvan Hu getnextvariablename.vendor_guid, 445ff6301daSIvan Hu sizeof(vendor_guid))) 446ff6301daSIvan Hu return -EFAULT; 447ff6301daSIvan Hu vd = &vendor_guid; 448ff6301daSIvan Hu } 449ff6301daSIvan Hu 450ff6301daSIvan Hu if (getnextvariablename.variable_name) { 451ff6301daSIvan Hu size_t name_string_size = 0; 452ff6301daSIvan Hu 453ff6301daSIvan Hu rv = get_ucs2_strsize_from_user( 454ff6301daSIvan Hu getnextvariablename.variable_name, 455ff6301daSIvan Hu &name_string_size); 456ff6301daSIvan Hu if (rv) 457ff6301daSIvan Hu return rv; 458ff6301daSIvan Hu /* 459ff6301daSIvan Hu * The name_size may be smaller than the real buffer size where 460ff6301daSIvan Hu * variable name located in some use cases. The most typical 461ff6301daSIvan Hu * case is passing a 0 to get the required buffer size for the 462ff6301daSIvan Hu * 1st time call. So we need to copy the content from user 463ff6301daSIvan Hu * space for at least the string size of variable name, or else 464ff6301daSIvan Hu * the name passed to UEFI may not be terminated as we expected. 465ff6301daSIvan Hu */ 466ff6301daSIvan Hu rv = copy_ucs2_from_user_len(&name, 467ff6301daSIvan Hu getnextvariablename.variable_name, 468ff6301daSIvan Hu prev_name_size > name_string_size ? 469ff6301daSIvan Hu prev_name_size : name_string_size); 470ff6301daSIvan Hu if (rv) 471ff6301daSIvan Hu return rv; 472ff6301daSIvan Hu } 473ff6301daSIvan Hu 474ff6301daSIvan Hu status = efi.get_next_variable(ns, name, vd); 475ff6301daSIvan Hu 476ff6301daSIvan Hu if (put_user(status, getnextvariablename.status)) { 477ff6301daSIvan Hu rv = -EFAULT; 478ff6301daSIvan Hu goto out; 479ff6301daSIvan Hu } 480ff6301daSIvan Hu 481ff6301daSIvan Hu if (status != EFI_SUCCESS) { 482ff6301daSIvan Hu if (status == EFI_BUFFER_TOO_SMALL) { 483ff6301daSIvan Hu if (ns && put_user(*ns, 484ff6301daSIvan Hu getnextvariablename.variable_name_size)) { 485ff6301daSIvan Hu rv = -EFAULT; 486ff6301daSIvan Hu goto out; 487ff6301daSIvan Hu } 488ff6301daSIvan Hu } 489ff6301daSIvan Hu rv = -EINVAL; 490ff6301daSIvan Hu goto out; 491ff6301daSIvan Hu } 492ff6301daSIvan Hu 493ff6301daSIvan Hu if (name) { 494ff6301daSIvan Hu if (copy_ucs2_to_user_len(getnextvariablename.variable_name, 495ff6301daSIvan Hu name, prev_name_size)) { 496ff6301daSIvan Hu rv = -EFAULT; 497ff6301daSIvan Hu goto out; 498ff6301daSIvan Hu } 499ff6301daSIvan Hu } 500ff6301daSIvan Hu 501ff6301daSIvan Hu if (ns) { 502ff6301daSIvan Hu if (put_user(*ns, getnextvariablename.variable_name_size)) { 503ff6301daSIvan Hu rv = -EFAULT; 504ff6301daSIvan Hu goto out; 505ff6301daSIvan Hu } 506ff6301daSIvan Hu } 507ff6301daSIvan Hu 508ff6301daSIvan Hu if (vd) { 509ff6301daSIvan Hu if (copy_to_user(getnextvariablename.vendor_guid, vd, 510ff6301daSIvan Hu sizeof(efi_guid_t))) 511ff6301daSIvan Hu rv = -EFAULT; 512ff6301daSIvan Hu } 513ff6301daSIvan Hu 514ff6301daSIvan Hu out: 515ff6301daSIvan Hu kfree(name); 516ff6301daSIvan Hu return rv; 517ff6301daSIvan Hu } 518ff6301daSIvan Hu 519ff6301daSIvan Hu static long efi_runtime_get_nexthighmonocount(unsigned long arg) 520ff6301daSIvan Hu { 521ff6301daSIvan Hu struct efi_getnexthighmonotoniccount __user *getnexthighmonocount_user; 522ff6301daSIvan Hu struct efi_getnexthighmonotoniccount getnexthighmonocount; 523ff6301daSIvan Hu efi_status_t status; 524ff6301daSIvan Hu u32 count; 525ff6301daSIvan Hu 526ff6301daSIvan Hu getnexthighmonocount_user = (struct 527ff6301daSIvan Hu efi_getnexthighmonotoniccount __user *)arg; 528ff6301daSIvan Hu 529ff6301daSIvan Hu if (copy_from_user(&getnexthighmonocount, 530ff6301daSIvan Hu getnexthighmonocount_user, 531ff6301daSIvan Hu sizeof(getnexthighmonocount))) 532ff6301daSIvan Hu return -EFAULT; 533ff6301daSIvan Hu 534ff6301daSIvan Hu status = efi.get_next_high_mono_count( 535ff6301daSIvan Hu getnexthighmonocount.high_count ? &count : NULL); 536ff6301daSIvan Hu 537ff6301daSIvan Hu if (put_user(status, getnexthighmonocount.status)) 538ff6301daSIvan Hu return -EFAULT; 539ff6301daSIvan Hu 540ff6301daSIvan Hu if (status != EFI_SUCCESS) 541ff6301daSIvan Hu return -EINVAL; 542ff6301daSIvan Hu 543ff6301daSIvan Hu if (getnexthighmonocount.high_count && 544ff6301daSIvan Hu put_user(count, getnexthighmonocount.high_count)) 545ff6301daSIvan Hu return -EFAULT; 546ff6301daSIvan Hu 547ff6301daSIvan Hu return 0; 548ff6301daSIvan Hu } 549ff6301daSIvan Hu 550ff6301daSIvan Hu static long efi_runtime_query_variableinfo(unsigned long arg) 551ff6301daSIvan Hu { 552ff6301daSIvan Hu struct efi_queryvariableinfo __user *queryvariableinfo_user; 553ff6301daSIvan Hu struct efi_queryvariableinfo queryvariableinfo; 554ff6301daSIvan Hu efi_status_t status; 555ff6301daSIvan Hu u64 max_storage, remaining, max_size; 556ff6301daSIvan Hu 557ff6301daSIvan Hu queryvariableinfo_user = (struct efi_queryvariableinfo __user *)arg; 558ff6301daSIvan Hu 559ff6301daSIvan Hu if (copy_from_user(&queryvariableinfo, queryvariableinfo_user, 560ff6301daSIvan Hu sizeof(queryvariableinfo))) 561ff6301daSIvan Hu return -EFAULT; 562ff6301daSIvan Hu 563ff6301daSIvan Hu status = efi.query_variable_info(queryvariableinfo.attributes, 564ff6301daSIvan Hu &max_storage, &remaining, &max_size); 565ff6301daSIvan Hu 566ff6301daSIvan Hu if (put_user(status, queryvariableinfo.status)) 567ff6301daSIvan Hu return -EFAULT; 568ff6301daSIvan Hu 569ff6301daSIvan Hu if (status != EFI_SUCCESS) 570ff6301daSIvan Hu return -EINVAL; 571ff6301daSIvan Hu 572ff6301daSIvan Hu if (put_user(max_storage, 573ff6301daSIvan Hu queryvariableinfo.maximum_variable_storage_size)) 574ff6301daSIvan Hu return -EFAULT; 575ff6301daSIvan Hu 576ff6301daSIvan Hu if (put_user(remaining, 577ff6301daSIvan Hu queryvariableinfo.remaining_variable_storage_size)) 578ff6301daSIvan Hu return -EFAULT; 579ff6301daSIvan Hu 580ff6301daSIvan Hu if (put_user(max_size, queryvariableinfo.maximum_variable_size)) 581ff6301daSIvan Hu return -EFAULT; 582ff6301daSIvan Hu 583ff6301daSIvan Hu return 0; 584ff6301daSIvan Hu } 585ff6301daSIvan Hu 586ff6301daSIvan Hu static long efi_runtime_query_capsulecaps(unsigned long arg) 587ff6301daSIvan Hu { 588ff6301daSIvan Hu struct efi_querycapsulecapabilities __user *qcaps_user; 589ff6301daSIvan Hu struct efi_querycapsulecapabilities qcaps; 590ff6301daSIvan Hu efi_capsule_header_t *capsules; 591ff6301daSIvan Hu efi_status_t status; 592ff6301daSIvan Hu u64 max_size; 593ff6301daSIvan Hu int i, reset_type; 594ff6301daSIvan Hu int rv = 0; 595ff6301daSIvan Hu 596ff6301daSIvan Hu qcaps_user = (struct efi_querycapsulecapabilities __user *)arg; 597ff6301daSIvan Hu 598ff6301daSIvan Hu if (copy_from_user(&qcaps, qcaps_user, sizeof(qcaps))) 599ff6301daSIvan Hu return -EFAULT; 600ff6301daSIvan Hu 601ff6301daSIvan Hu capsules = kcalloc(qcaps.capsule_count + 1, 602ff6301daSIvan Hu sizeof(efi_capsule_header_t), GFP_KERNEL); 603ff6301daSIvan Hu if (!capsules) 604ff6301daSIvan Hu return -ENOMEM; 605ff6301daSIvan Hu 606ff6301daSIvan Hu for (i = 0; i < qcaps.capsule_count; i++) { 607ff6301daSIvan Hu efi_capsule_header_t *c; 608ff6301daSIvan Hu /* 609ff6301daSIvan Hu * We cannot dereference qcaps.capsule_header_array directly to 610ff6301daSIvan Hu * obtain the address of the capsule as it resides in the 611ff6301daSIvan Hu * user space 612ff6301daSIvan Hu */ 613ff6301daSIvan Hu if (get_user(c, qcaps.capsule_header_array + i)) { 614ff6301daSIvan Hu rv = -EFAULT; 615ff6301daSIvan Hu goto out; 616ff6301daSIvan Hu } 617ff6301daSIvan Hu if (copy_from_user(&capsules[i], c, 618ff6301daSIvan Hu sizeof(efi_capsule_header_t))) { 619ff6301daSIvan Hu rv = -EFAULT; 620ff6301daSIvan Hu goto out; 621ff6301daSIvan Hu } 622ff6301daSIvan Hu } 623ff6301daSIvan Hu 624ff6301daSIvan Hu qcaps.capsule_header_array = &capsules; 625ff6301daSIvan Hu 626ff6301daSIvan Hu status = efi.query_capsule_caps((efi_capsule_header_t **) 627ff6301daSIvan Hu qcaps.capsule_header_array, 628ff6301daSIvan Hu qcaps.capsule_count, 629ff6301daSIvan Hu &max_size, &reset_type); 630ff6301daSIvan Hu 631ff6301daSIvan Hu if (put_user(status, qcaps.status)) { 632ff6301daSIvan Hu rv = -EFAULT; 633ff6301daSIvan Hu goto out; 634ff6301daSIvan Hu } 635ff6301daSIvan Hu 636ff6301daSIvan Hu if (status != EFI_SUCCESS) { 637ff6301daSIvan Hu rv = -EINVAL; 638ff6301daSIvan Hu goto out; 639ff6301daSIvan Hu } 640ff6301daSIvan Hu 641ff6301daSIvan Hu if (put_user(max_size, qcaps.maximum_capsule_size)) { 642ff6301daSIvan Hu rv = -EFAULT; 643ff6301daSIvan Hu goto out; 644ff6301daSIvan Hu } 645ff6301daSIvan Hu 646ff6301daSIvan Hu if (put_user(reset_type, qcaps.reset_type)) 647ff6301daSIvan Hu rv = -EFAULT; 648ff6301daSIvan Hu 649ff6301daSIvan Hu out: 650ff6301daSIvan Hu kfree(capsules); 651ff6301daSIvan Hu return rv; 652ff6301daSIvan Hu } 653ff6301daSIvan Hu 654ff6301daSIvan Hu static long efi_test_ioctl(struct file *file, unsigned int cmd, 655ff6301daSIvan Hu unsigned long arg) 656ff6301daSIvan Hu { 657ff6301daSIvan Hu switch (cmd) { 658ff6301daSIvan Hu case EFI_RUNTIME_GET_VARIABLE: 659ff6301daSIvan Hu return efi_runtime_get_variable(arg); 660ff6301daSIvan Hu 661ff6301daSIvan Hu case EFI_RUNTIME_SET_VARIABLE: 662ff6301daSIvan Hu return efi_runtime_set_variable(arg); 663ff6301daSIvan Hu 664ff6301daSIvan Hu case EFI_RUNTIME_GET_TIME: 665ff6301daSIvan Hu return efi_runtime_get_time(arg); 666ff6301daSIvan Hu 667ff6301daSIvan Hu case EFI_RUNTIME_SET_TIME: 668ff6301daSIvan Hu return efi_runtime_set_time(arg); 669ff6301daSIvan Hu 670ff6301daSIvan Hu case EFI_RUNTIME_GET_WAKETIME: 671ff6301daSIvan Hu return efi_runtime_get_waketime(arg); 672ff6301daSIvan Hu 673ff6301daSIvan Hu case EFI_RUNTIME_SET_WAKETIME: 674ff6301daSIvan Hu return efi_runtime_set_waketime(arg); 675ff6301daSIvan Hu 676ff6301daSIvan Hu case EFI_RUNTIME_GET_NEXTVARIABLENAME: 677ff6301daSIvan Hu return efi_runtime_get_nextvariablename(arg); 678ff6301daSIvan Hu 679ff6301daSIvan Hu case EFI_RUNTIME_GET_NEXTHIGHMONOTONICCOUNT: 680ff6301daSIvan Hu return efi_runtime_get_nexthighmonocount(arg); 681ff6301daSIvan Hu 682ff6301daSIvan Hu case EFI_RUNTIME_QUERY_VARIABLEINFO: 683ff6301daSIvan Hu return efi_runtime_query_variableinfo(arg); 684ff6301daSIvan Hu 685ff6301daSIvan Hu case EFI_RUNTIME_QUERY_CAPSULECAPABILITIES: 686ff6301daSIvan Hu return efi_runtime_query_capsulecaps(arg); 687ff6301daSIvan Hu } 688ff6301daSIvan Hu 689ff6301daSIvan Hu return -ENOTTY; 690ff6301daSIvan Hu } 691ff6301daSIvan Hu 692ff6301daSIvan Hu static int efi_test_open(struct inode *inode, struct file *file) 693ff6301daSIvan Hu { 694ff6301daSIvan Hu /* 695ff6301daSIvan Hu * nothing special to do here 696ff6301daSIvan Hu * We do accept multiple open files at the same time as we 697ff6301daSIvan Hu * synchronize on the per call operation. 698ff6301daSIvan Hu */ 699ff6301daSIvan Hu return 0; 700ff6301daSIvan Hu } 701ff6301daSIvan Hu 702ff6301daSIvan Hu static int efi_test_close(struct inode *inode, struct file *file) 703ff6301daSIvan Hu { 704ff6301daSIvan Hu return 0; 705ff6301daSIvan Hu } 706ff6301daSIvan Hu 707ff6301daSIvan Hu /* 708ff6301daSIvan Hu * The various file operations we support. 709ff6301daSIvan Hu */ 710ff6301daSIvan Hu static const struct file_operations efi_test_fops = { 711ff6301daSIvan Hu .owner = THIS_MODULE, 712ff6301daSIvan Hu .unlocked_ioctl = efi_test_ioctl, 713ff6301daSIvan Hu .open = efi_test_open, 714ff6301daSIvan Hu .release = efi_test_close, 715ff6301daSIvan Hu .llseek = no_llseek, 716ff6301daSIvan Hu }; 717ff6301daSIvan Hu 718ff6301daSIvan Hu static struct miscdevice efi_test_dev = { 719ff6301daSIvan Hu MISC_DYNAMIC_MINOR, 720ff6301daSIvan Hu "efi_test", 721ff6301daSIvan Hu &efi_test_fops 722ff6301daSIvan Hu }; 723ff6301daSIvan Hu 724ff6301daSIvan Hu static int __init efi_test_init(void) 725ff6301daSIvan Hu { 726ff6301daSIvan Hu int ret; 727ff6301daSIvan Hu 728ff6301daSIvan Hu ret = misc_register(&efi_test_dev); 729ff6301daSIvan Hu if (ret) { 730ff6301daSIvan Hu pr_err("efi_test: can't misc_register on minor=%d\n", 731ff6301daSIvan Hu MISC_DYNAMIC_MINOR); 732ff6301daSIvan Hu return ret; 733ff6301daSIvan Hu } 734ff6301daSIvan Hu 735ff6301daSIvan Hu return 0; 736ff6301daSIvan Hu } 737ff6301daSIvan Hu 738ff6301daSIvan Hu static void __exit efi_test_exit(void) 739ff6301daSIvan Hu { 740ff6301daSIvan Hu misc_deregister(&efi_test_dev); 741ff6301daSIvan Hu } 742ff6301daSIvan Hu 743ff6301daSIvan Hu module_init(efi_test_init); 744ff6301daSIvan Hu module_exit(efi_test_exit); 745