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