gsgx_main.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*
  2. * (C) Copyright 2013 Intel Corporation
  3. * Author: Jarkko Sakkinen <jarkko.sakkinen@intel.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License
  7. * as published by the Free Software Foundation; version 2
  8. * of the License.
  9. */
  10. #include <linux/module.h>
  11. #include <linux/kernel.h>
  12. #include <linux/version.h>
  13. #include <linux/highmem.h>
  14. #include <linux/miscdevice.h>
  15. #include <linux/module.h>
  16. #include <linux/vmalloc.h>
  17. #include <linux/security.h>
  18. #include <asm/tlbflush.h>
  19. #include "gsgx.h"
  20. #define DRV_DESCRIPTION "Graphene SGX Driver"
  21. #define DRV_VERSION "0.10"
  22. MODULE_DESCRIPTION(DRV_DESCRIPTION);
  23. MODULE_AUTHOR("Chia-Che Tsai <chia-che.tsai@intel.com>");
  24. MODULE_VERSION(DRV_VERSION);
  25. IMPORT_KSYM(dac_mmap_min_addr);
  26. static long gsgx_ioctl_enclave_create(struct file *filep, unsigned int cmd,
  27. unsigned long arg)
  28. {
  29. struct gsgx_enclave_create *createp = (struct gsgx_enclave_create *) arg;
  30. struct isgx_create_param isgx_create;
  31. unsigned long old_mmap_min_addr = *KSYM(dac_mmap_min_addr);
  32. int ret;
  33. if (createp->addr != GSGX_ENCLAVE_CREATE_NO_ADDR &&
  34. createp->addr < old_mmap_min_addr) {
  35. *KSYM(dac_mmap_min_addr) = createp->addr;
  36. old_mmap_min_addr = 0;
  37. }
  38. isgx_create.secs = createp->secs;
  39. filep->private_data = (void *) createp->addr;
  40. ret = KSYM(isgx_ioctl_enclave_create)(filep, ISGX_IOCTL_ENCLAVE_CREATE,
  41. (unsigned long) &isgx_create);
  42. if (!ret)
  43. createp->addr = isgx_create.addr;
  44. if (old_mmap_min_addr)
  45. *KSYM(dac_mmap_min_addr) = old_mmap_min_addr;
  46. return ret;
  47. }
  48. static long gsgx_ioctl_enclave_add_pages(struct file *filep, unsigned int cmd,
  49. unsigned long arg)
  50. {
  51. struct gsgx_enclave_add_pages *addp = (struct gsgx_enclave_add_pages *) arg;
  52. struct isgx_add_param isgx_add;
  53. unsigned long off;
  54. int ret = 0;
  55. if (!addp->addr || (addp->addr & (PAGE_SIZE - 1)))
  56. return -EINVAL;
  57. if (!addp->size || (addp->size & (PAGE_SIZE - 1)))
  58. return -EINVAL;
  59. if (!addp->secinfo)
  60. return -EINVAL;
  61. isgx_add.secinfo = addp->secinfo;
  62. for (off = 0 ; off < addp->size ; off += PAGE_SIZE) {
  63. isgx_add.addr = addp->addr + off;
  64. isgx_add.user_addr =
  65. addp->flags & GSGX_ENCLAVE_ADD_PAGES_REPEAT_SRC ?
  66. addp->user_addr : addp->user_addr + off;
  67. isgx_add.flags =
  68. addp->flags & GSGX_ENCLAVE_ADD_PAGES_SKIP_EEXTEND ?
  69. ISGX_ADD_SKIP_EEXTEND : 0;
  70. ret = KSYM(isgx_ioctl_enclave_add_page)(filep,
  71. ISGX_IOCTL_ENCLAVE_ADD_PAGE, (unsigned long) &isgx_add);
  72. if (ret < 0)
  73. break;
  74. }
  75. return ret;
  76. }
  77. static long gsgx_ioctl_enclave_init(struct file *filep, unsigned int cmd,
  78. unsigned long arg)
  79. {
  80. struct gsgx_enclave_init *initp = (struct gsgx_enclave_init *) arg;
  81. struct isgx_init_param isgx_init;
  82. isgx_init.addr = initp->addr;
  83. isgx_init.sigstruct = initp->sigstruct;
  84. isgx_init.einittoken = initp->einittoken;
  85. return KSYM(isgx_ioctl_enclave_init)(filep, ISGX_IOCTL_ENCLAVE_INIT,
  86. (unsigned long) &isgx_init);
  87. }
  88. static long gsgx_ioctl_enclave_destroy(struct file *filep, unsigned int cmd,
  89. unsigned long arg)
  90. {
  91. struct gsgx_enclave_destroy *destroyp = (struct gsgx_enclave_destroy *) arg;
  92. struct isgx_destroy_param isgx_destroy;
  93. isgx_destroy.addr = destroyp->addr;
  94. return KSYM(isgx_ioctl_enclave_destroy)(filep, ISGX_IOCTL_ENCLAVE_DESTROY,
  95. (unsigned long) &isgx_destroy);
  96. }
  97. typedef long (*ioctl_t)(struct file *filep, unsigned int cmd, unsigned long arg);
  98. long gsgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
  99. {
  100. char data[256];
  101. ioctl_t handler = NULL;
  102. long ret;
  103. switch (cmd) {
  104. case GSGX_IOCTL_ENCLAVE_CREATE:
  105. handler = gsgx_ioctl_enclave_create;
  106. break;
  107. case GSGX_IOCTL_ENCLAVE_ADD_PAGES:
  108. handler = gsgx_ioctl_enclave_add_pages;
  109. break;
  110. case GSGX_IOCTL_ENCLAVE_INIT:
  111. handler = gsgx_ioctl_enclave_init;
  112. break;
  113. case GSGX_IOCTL_ENCLAVE_DESTROY:
  114. handler = gsgx_ioctl_enclave_destroy;
  115. break;
  116. default:
  117. return -EINVAL;
  118. }
  119. if (copy_from_user(data, (void __user *) arg, _IOC_SIZE(cmd)))
  120. return -EFAULT;
  121. ret = handler(filep, cmd, (unsigned long) ((void *) data));
  122. if (!ret && (cmd & IOC_OUT)) {
  123. if (copy_to_user((void __user *) arg, data, _IOC_SIZE(cmd)))
  124. return -EFAULT;
  125. }
  126. return ret;
  127. }
  128. static int gsgx_mmap(struct file *file, struct vm_area_struct *vma)
  129. {
  130. return KSYM(isgx_mmap)(file, vma);
  131. }
  132. static unsigned long gsgx_get_unmapped_area(struct file *file,
  133. unsigned long addr,
  134. unsigned long len,
  135. unsigned long pgoff,
  136. unsigned long flags)
  137. {
  138. if (file->private_data == (void *) GSGX_ENCLAVE_CREATE_NO_ADDR) {
  139. unsigned long unmapped_addr =
  140. KSYM(isgx_get_unmapped_area)(file, addr, len,
  141. pgoff, flags);
  142. file->private_data = (void *) unmapped_addr;
  143. return unmapped_addr;
  144. } else {
  145. unsigned long unmapped_addr = (unsigned long) file->private_data;
  146. struct mm_struct *mm = current->mm;
  147. struct vm_area_struct *vma = find_vma(mm, unmapped_addr);
  148. if (vma && vma->vm_start <= len)
  149. return -EINVAL;
  150. return unmapped_addr;
  151. }
  152. }
  153. static const struct file_operations gsgx_fops = {
  154. .owner = THIS_MODULE,
  155. .unlocked_ioctl = gsgx_ioctl,
  156. #ifdef CONFIG_COMPAT
  157. .compat_ioctl = gsgx_ioctl,
  158. #endif
  159. .mmap = gsgx_mmap,
  160. .get_unmapped_area = gsgx_get_unmapped_area,
  161. };
  162. static struct miscdevice gsgx_dev = {
  163. .minor = GSGX_MINOR,
  164. .name = "gsgx",
  165. .fops = &gsgx_fops,
  166. .mode = S_IRUGO | S_IWUGO,
  167. };
  168. IMPORT_KSYM_PROTO(isgx_ioctl_enclave_create, long,
  169. struct file *filep, unsigned int cmd, unsigned long arg);
  170. IMPORT_KSYM_PROTO(isgx_ioctl_enclave_init, long,
  171. struct file *filep, unsigned int cmd, unsigned long arg);
  172. IMPORT_KSYM_PROTO(isgx_ioctl_enclave_add_page, long,
  173. struct file *filep, unsigned int cmd, unsigned long arg);
  174. IMPORT_KSYM_PROTO(isgx_ioctl_enclave_destroy, long,
  175. struct file *filep, unsigned int cmd, unsigned long arg);
  176. IMPORT_KSYM(isgx_enclave_release);
  177. IMPORT_KSYM_PROTO(isgx_mmap, int, struct file *, struct vm_area_struct *);
  178. IMPORT_KSYM_PROTO(isgx_get_unmapped_area, unsigned long,
  179. struct file *, unsigned long, unsigned long,
  180. unsigned long, unsigned long);
  181. static int gsgx_lookup_ksyms(void)
  182. {
  183. int ret;
  184. if ((ret = LOOKUP_KSYM(dac_mmap_min_addr)))
  185. return ret;
  186. if ((ret = LOOKUP_KSYM(isgx_ioctl_enclave_create)))
  187. return ret;
  188. if ((ret = LOOKUP_KSYM(isgx_ioctl_enclave_init)))
  189. return ret;
  190. if ((ret = LOOKUP_KSYM(isgx_ioctl_enclave_add_page)))
  191. return ret;
  192. if ((ret = LOOKUP_KSYM(isgx_ioctl_enclave_destroy)))
  193. return ret;
  194. if ((ret = LOOKUP_KSYM(isgx_enclave_release)))
  195. return ret;
  196. if ((ret = LOOKUP_KSYM(isgx_mmap)))
  197. return ret;
  198. if ((ret = LOOKUP_KSYM(isgx_get_unmapped_area)))
  199. return ret;
  200. return 0;
  201. }
  202. struct file *isgx_dev;
  203. static int gsgx_setup(void)
  204. {
  205. unsigned cpu;
  206. int ret;
  207. isgx_dev = filp_open("/dev/isgx", O_RDONLY, 0);
  208. if (!isgx_dev) {
  209. return PTR_ERR(isgx_dev);
  210. }
  211. ret = misc_register(&gsgx_dev);
  212. if (ret) {
  213. pr_err("gsgx: misc_register() failed\n");
  214. gsgx_dev.this_device = NULL;
  215. return ret;
  216. }
  217. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
  218. for_each_online_cpu(cpu) {
  219. per_cpu(cpu_tlbstate.cr4, cpu) |= X86_CR4_FSGSBASE;
  220. }
  221. #else
  222. #endif
  223. return 0;
  224. }
  225. static void gsgx_teardown(void)
  226. {
  227. if (gsgx_dev.this_device)
  228. misc_deregister(&gsgx_dev);
  229. if (isgx_dev)
  230. filp_close(isgx_dev, NULL);
  231. }
  232. static int __init gsgx_init(void)
  233. {
  234. int ret;
  235. pr_info("gsgx: " DRV_DESCRIPTION " v" DRV_VERSION "\n");
  236. ret = gsgx_lookup_ksyms();
  237. if (ret) {
  238. pr_err("Likely module \"isgx\" is not loaded\n");
  239. return ret;
  240. }
  241. ret = gsgx_setup();
  242. if (ret) {
  243. pr_err("Likely module \"isgx\" is not loaded\n");
  244. gsgx_teardown();
  245. return ret;
  246. }
  247. return 0;
  248. }
  249. static void __exit gsgx_exit(void)
  250. {
  251. gsgx_teardown();
  252. }
  253. module_init(gsgx_init);
  254. module_exit(gsgx_exit);
  255. MODULE_LICENSE("GPL");