This source file includes following definitions.
- read_ldt
- limits_ok
- write_ldt
- sys_modify_ldt
1
2
3
4
5
6
7 #include <linux/errno.h>
8 #include <linux/sched.h>
9 #include <linux/string.h>
10 #include <linux/mm.h>
11 #include <asm/segment.h>
12 #include <asm/system.h>
13 #include <linux/ldt.h>
14
15 static int read_ldt(void * ptr, unsigned long bytecount)
16 {
17 int error;
18 void * address = current->ldt;
19 unsigned long size;
20
21 if (!ptr)
22 return -EINVAL;
23 size = LDT_ENTRIES*LDT_ENTRY_SIZE;
24 if (!address) {
25 address = &default_ldt;
26 size = sizeof(default_ldt);
27 }
28 if (size > bytecount)
29 size = bytecount;
30 error = verify_area(VERIFY_WRITE, ptr, size);
31 if (error)
32 return error;
33 memcpy_tofs(ptr, address, size);
34 return size;
35 }
36
37 static inline int limits_ok(struct modify_ldt_ldt_s *ldt_info)
38 {
39 unsigned long base, limit;
40
41 unsigned long first, last;
42
43 base = ldt_info->base_addr;
44 limit = ldt_info->limit;
45 if (ldt_info->limit_in_pages)
46 limit = limit * PAGE_SIZE + PAGE_SIZE - 1;
47
48 first = base;
49 last = limit + base;
50
51
52 if (ldt_info->contents == 1) {
53
54 first = base+limit+1;
55 last = base+65535;
56 if (ldt_info->seg_32bit)
57 last = base-1;
58 }
59 return (last >= first && last < TASK_SIZE);
60 }
61
62 static int write_ldt(void * ptr, unsigned long bytecount)
63 {
64 struct modify_ldt_ldt_s ldt_info;
65 unsigned long *lp;
66 int error, i;
67
68 if (bytecount != sizeof(ldt_info))
69 return -EINVAL;
70 error = verify_area(VERIFY_READ, ptr, sizeof(ldt_info));
71 if (error)
72 return error;
73
74 memcpy_fromfs(&ldt_info, ptr, sizeof(ldt_info));
75
76 if (ldt_info.contents == 3 || ldt_info.entry_number >= LDT_ENTRIES)
77 return -EINVAL;
78
79 if (!limits_ok(&ldt_info))
80 return -EINVAL;
81
82 if (!current->ldt) {
83 for (i=1 ; i<NR_TASKS ; i++) {
84 if (task[i] == current) {
85 if (!(current->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
86 return -ENOMEM;
87 memset(current->ldt, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
88 set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->ldt, LDT_ENTRIES);
89 load_ldt(i);
90 }
91 }
92 }
93
94 lp = (unsigned long *) ¤t->ldt[ldt_info.entry_number];
95
96 if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
97 *lp = 0;
98 *(lp+1) = 0;
99 return 0;
100 }
101 *lp = ((ldt_info.base_addr & 0x0000ffff) << 16) |
102 (ldt_info.limit & 0x0ffff);
103 *(lp+1) = (ldt_info.base_addr & 0xff000000) |
104 ((ldt_info.base_addr & 0x00ff0000)>>16) |
105 (ldt_info.limit & 0xf0000) |
106 (ldt_info.contents << 10) |
107 ((ldt_info.read_exec_only ^ 1) << 9) |
108 (ldt_info.seg_32bit << 22) |
109 (ldt_info.limit_in_pages << 23) |
110 ((ldt_info.seg_not_present ^1) << 15) |
111 0x7000;
112 return 0;
113 }
114
115 asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
116 {
117 if (func == 0)
118 return read_ldt(ptr, bytecount);
119 if (func == 1)
120 return write_ldt(ptr, bytecount);
121 return -ENOSYS;
122 }