ldt.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:4k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  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.  * Manage the local descriptor table for user processes.
  9.  * This handles calls from both 32bit and 64bit mode.
  10.  */
  11. #include <linux/errno.h>
  12. #include <linux/sched.h>
  13. #include <linux/string.h>
  14. #include <linux/mm.h>
  15. #include <linux/smp.h>
  16. #include <linux/smp_lock.h>
  17. #include <linux/vmalloc.h>
  18. #include <asm/uaccess.h>
  19. #include <asm/system.h>
  20. #include <asm/ldt.h>
  21. #include <asm/desc.h>
  22. /*
  23.  * read_ldt() is not really atomic - this is not a problem since
  24.  * synchronization of reads and writes done to the LDT has to be
  25.  * assured by user-space anyway. Writes are atomic, to protect
  26.  * the security checks done on new descriptors.
  27.  */
  28. static int read_ldt(void * ptr, unsigned long bytecount)
  29. {
  30. int err;
  31. unsigned long size;
  32. struct mm_struct * mm = current->mm;
  33. err = 0;
  34. if (!mm->context.segments)
  35. goto out;
  36. size = LDT_ENTRIES*LDT_ENTRY_SIZE;
  37. if (size > bytecount)
  38. size = bytecount;
  39. err = size;
  40. if (copy_to_user(ptr, mm->context.segments, size))
  41. err = -EFAULT;
  42. out:
  43. return err;
  44. }
  45. static int read_default_ldt(void * ptr, unsigned long bytecount)
  46. {
  47. /* Arbitary number */ 
  48. if (bytecount > 128) 
  49. bytecount = 128; 
  50. if (clear_user(ptr, bytecount))
  51. return -EFAULT;
  52. return bytecount; 
  53. }
  54. static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
  55. {
  56. struct task_struct *me = current;
  57. struct mm_struct * mm = me->mm;
  58. __u32 entry_1, entry_2, *lp;
  59. int error;
  60. struct modify_ldt_ldt_s ldt_info;
  61. error = -EINVAL;
  62. if (bytecount != sizeof(ldt_info))
  63. goto out;
  64. error = -EFAULT; 
  65. if (copy_from_user(&ldt_info, ptr, bytecount))
  66. goto out;
  67. error = -EINVAL;
  68. if (ldt_info.entry_number >= LDT_ENTRIES)
  69. goto out;
  70. if (ldt_info.contents == 3) {
  71. if (oldmode)
  72. goto out;
  73. if (ldt_info.seg_not_present == 0)
  74. goto out;
  75. }
  76. me->thread.fsindex = 0; 
  77. me->thread.gsindex = 0; 
  78. me->thread.gs = 0; 
  79. me->thread.fs = 0; 
  80. /*
  81.  * the GDT index of the LDT is allocated dynamically, and is
  82.  * limited by MAX_LDT_DESCRIPTORS.
  83.  */
  84. down_write(&mm->mmap_sem);
  85. if (!mm->context.segments) {
  86. void * segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
  87. error = -ENOMEM;
  88. if (!segments)
  89. goto out_unlock;
  90. memset(segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
  91. wmb();
  92. mm->context.segments = segments;
  93. mm->context.cpuvalid = 1UL << smp_processor_id();
  94. load_LDT(mm);
  95. }
  96. lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.segments);
  97.     /* Allow LDTs to be cleared by the user. */
  98.     if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
  99. if (oldmode ||
  100.     (ldt_info.contents == 0 &&
  101.      ldt_info.read_exec_only == 1 &&
  102.      ldt_info.seg_32bit == 0 &&
  103.      ldt_info.limit_in_pages == 0 &&
  104.      ldt_info.seg_not_present == 1 &&
  105.      ldt_info.useable == 0 && 
  106.      ldt_info.lm == 0)) {
  107. entry_1 = 0;
  108. entry_2 = 0;
  109. goto install;
  110. }
  111. }
  112. entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
  113.   (ldt_info.limit & 0x0ffff);
  114. entry_2 = (ldt_info.base_addr & 0xff000000) |
  115.   ((ldt_info.base_addr & 0x00ff0000) >> 16) |
  116.   (ldt_info.limit & 0xf0000) |
  117.   ((ldt_info.read_exec_only ^ 1) << 9) |
  118.   (ldt_info.contents << 10) |
  119.   ((ldt_info.seg_not_present ^ 1) << 15) |
  120.   (ldt_info.seg_32bit << 22) |
  121.   (ldt_info.limit_in_pages << 23) |
  122.   (ldt_info.lm << 21) |
  123.   0x7000;
  124. if (!oldmode)
  125. entry_2 |= (ldt_info.useable << 20);
  126. /* Install the new entry ...  */
  127. install:
  128. write_lock(&mm->context.ldtlock);
  129. *lp = entry_1;
  130. *(lp+1) = entry_2;
  131. write_unlock(&mm->context.ldtlock);
  132. error = 0;
  133. out_unlock:
  134. up_write(&mm->mmap_sem);
  135. out:
  136. return error;
  137. }
  138. asmlinkage long sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
  139. {
  140. int ret = -ENOSYS;
  141. switch (func) {
  142. case 0:
  143. ret = read_ldt(ptr, bytecount);
  144. break;
  145. case 1:
  146. ret = write_ldt(ptr, bytecount, 1);
  147. break;
  148. case 2:
  149. ret = read_default_ldt(ptr, bytecount);
  150. break;
  151. case 0x11:
  152. ret = write_ldt(ptr, bytecount, 0);
  153. break;
  154. }
  155. return ret;
  156. }