ldt.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. * linux/arch/x86_64/kernel/ldt.c
  3. *
  4. * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
  5. * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
  6. * Copyright (C) 2002 Andi Kleen
  7. *
  8. * This handles calls from both 32bit and 64bit mode.
  9. */
  10. #include <linux/errno.h>
  11. #include <linux/sched.h>
  12. #include <linux/string.h>
  13. #include <linux/mm.h>
  14. #include <linux/smp.h>
  15. #include <linux/vmalloc.h>
  16. #include <linux/slab.h>
  17. #include <asm/uaccess.h>
  18. #include <asm/system.h>
  19. #include <asm/ldt.h>
  20. #include <asm/desc.h>
  21. #include <asm/proto.h>
  22. #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
  23. static void flush_ldt(void *null)
  24. {
  25. if (current->active_mm)
  26. load_LDT(&current->active_mm->context);
  27. }
  28. #endif
  29. static int alloc_ldt(mm_context_t *pc, unsigned mincount, int reload)
  30. {
  31. void *oldldt;
  32. void *newldt;
  33. unsigned oldsize;
  34. if (mincount <= (unsigned)pc->size)
  35. return 0;
  36. oldsize = pc->size;
  37. mincount = (mincount+511)&(~511);
  38. if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE)
  39. newldt = vmalloc(mincount*LDT_ENTRY_SIZE);
  40. else
  41. newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL);
  42. if (!newldt)
  43. return -ENOMEM;
  44. if (oldsize)
  45. memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE);
  46. oldldt = pc->ldt;
  47. memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE);
  48. wmb();
  49. pc->ldt = newldt;
  50. wmb();
  51. pc->size = mincount;
  52. wmb();
  53. if (reload) {
  54. #ifdef CONFIG_SMP
  55. cpumask_t mask;
  56. preempt_disable();
  57. mask = cpumask_of_cpu(smp_processor_id());
  58. load_LDT(pc);
  59. if (!cpus_equal(current->mm->cpu_vm_mask, mask))
  60. smp_call_function(flush_ldt, NULL, 1, 1);
  61. preempt_enable();
  62. #else
  63. load_LDT(pc);
  64. #endif
  65. }
  66. if (oldsize) {
  67. if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE)
  68. vfree(oldldt);
  69. else
  70. kfree(oldldt);
  71. }
  72. return 0;
  73. }
  74. static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
  75. {
  76. int err = alloc_ldt(new, old->size, 0);
  77. if (err < 0)
  78. return err;
  79. memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
  80. return 0;
  81. }
  82. /*
  83. * we do not have to muck with descriptors here, that is
  84. * done in switch_mm() as needed.
  85. */
  86. int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
  87. {
  88. struct mm_struct * old_mm;
  89. int retval = 0;
  90. init_MUTEX(&mm->context.sem);
  91. mm->context.size = 0;
  92. old_mm = current->mm;
  93. if (old_mm && old_mm->context.size > 0) {
  94. down(&old_mm->context.sem);
  95. retval = copy_ldt(&mm->context, &old_mm->context);
  96. up(&old_mm->context.sem);
  97. }
  98. return retval;
  99. }
  100. /*
  101. *
  102. * Don't touch the LDT register - we're already in the next thread.
  103. */
  104. void destroy_context(struct mm_struct *mm)
  105. {
  106. if (mm->context.size) {
  107. if ((unsigned)mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE)
  108. vfree(mm->context.ldt);
  109. else
  110. kfree(mm->context.ldt);
  111. mm->context.size = 0;
  112. }
  113. }
  114. static int read_ldt(void __user * ptr, unsigned long bytecount)
  115. {
  116. int err;
  117. unsigned long size;
  118. struct mm_struct * mm = current->mm;
  119. if (!mm->context.size)
  120. return 0;
  121. if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES)
  122. bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES;
  123. down(&mm->context.sem);
  124. size = mm->context.size*LDT_ENTRY_SIZE;
  125. if (size > bytecount)
  126. size = bytecount;
  127. err = 0;
  128. if (copy_to_user(ptr, mm->context.ldt, size))
  129. err = -EFAULT;
  130. up(&mm->context.sem);
  131. if (err < 0)
  132. goto error_return;
  133. if (size != bytecount) {
  134. /* zero-fill the rest */
  135. if (clear_user(ptr+size, bytecount-size) != 0) {
  136. err = -EFAULT;
  137. goto error_return;
  138. }
  139. }
  140. return bytecount;
  141. error_return:
  142. return err;
  143. }
  144. static int read_default_ldt(void __user * ptr, unsigned long bytecount)
  145. {
  146. /* Arbitrary number */
  147. /* x86-64 default LDT is all zeros */
  148. if (bytecount > 128)
  149. bytecount = 128;
  150. if (clear_user(ptr, bytecount))
  151. return -EFAULT;
  152. return bytecount;
  153. }
  154. static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
  155. {
  156. struct task_struct *me = current;
  157. struct mm_struct * mm = me->mm;
  158. __u32 entry_1, entry_2, *lp;
  159. int error;
  160. struct user_desc ldt_info;
  161. error = -EINVAL;
  162. if (bytecount != sizeof(ldt_info))
  163. goto out;
  164. error = -EFAULT;
  165. if (copy_from_user(&ldt_info, ptr, bytecount))
  166. goto out;
  167. error = -EINVAL;
  168. if (ldt_info.entry_number >= LDT_ENTRIES)
  169. goto out;
  170. if (ldt_info.contents == 3) {
  171. if (oldmode)
  172. goto out;
  173. if (ldt_info.seg_not_present == 0)
  174. goto out;
  175. }
  176. down(&mm->context.sem);
  177. if (ldt_info.entry_number >= (unsigned)mm->context.size) {
  178. error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
  179. if (error < 0)
  180. goto out_unlock;
  181. }
  182. lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt);
  183. /* Allow LDTs to be cleared by the user. */
  184. if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
  185. if (oldmode || LDT_empty(&ldt_info)) {
  186. entry_1 = 0;
  187. entry_2 = 0;
  188. goto install;
  189. }
  190. }
  191. entry_1 = LDT_entry_a(&ldt_info);
  192. entry_2 = LDT_entry_b(&ldt_info);
  193. if (oldmode)
  194. entry_2 &= ~(1 << 20);
  195. /* Install the new entry ... */
  196. install:
  197. *lp = entry_1;
  198. *(lp+1) = entry_2;
  199. error = 0;
  200. out_unlock:
  201. up(&mm->context.sem);
  202. out:
  203. return error;
  204. }
  205. asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
  206. {
  207. int ret = -ENOSYS;
  208. switch (func) {
  209. case 0:
  210. ret = read_ldt(ptr, bytecount);
  211. break;
  212. case 1:
  213. ret = write_ldt(ptr, bytecount, 1);
  214. break;
  215. case 2:
  216. ret = read_default_ldt(ptr, bytecount);
  217. break;
  218. case 0x11:
  219. ret = write_ldt(ptr, bytecount, 0);
  220. break;
  221. }
  222. return ret;
  223. }