4 * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
5 * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
8 #include <linux/errno.h>
9 #include <linux/sched.h>
10 #include <linux/string.h>
12 #include <linux/smp.h>
13 #include <linux/smp_lock.h>
14 #include <linux/vmalloc.h>
16 #include <asm/uaccess.h>
17 #include <asm/system.h>
22 * read_ldt() is not really atomic - this is not a problem since
23 * synchronization of reads and writes done to the LDT has to be
24 * assured by user-space anyway. Writes are atomic, to protect
25 * the security checks done on new descriptors.
27 static int read_ldt(void * ptr
, unsigned long bytecount
)
31 struct mm_struct
* mm
= current
->mm
;
37 size
= LDT_ENTRIES
*LDT_ENTRY_SIZE
;
42 if (copy_to_user(ptr
, mm
->segments
, size
))
48 static int write_ldt(void * ptr
, unsigned long bytecount
, int oldmode
)
50 struct mm_struct
* mm
= current
->mm
;
51 __u32 entry_1
, entry_2
, *lp
;
53 struct modify_ldt_ldt_s ldt_info
;
56 if (bytecount
!= sizeof(ldt_info
))
59 if (copy_from_user(&ldt_info
, ptr
, sizeof(ldt_info
)))
63 if (ldt_info
.entry_number
>= LDT_ENTRIES
)
65 if (ldt_info
.contents
== 3) {
68 if (ldt_info
.seg_not_present
== 0)
73 * Horrible dependencies! Try to get rid of this. This is wrong,
74 * as it only reloads the ldt for the first process with this
75 * mm. The implications are that you should really make sure that
76 * you have a ldt before you do the first clone(), otherwise
77 * you get strange behaviour (the kernel is safe, it's just user
80 * we have two choices: either we preallocate the LDT descriptor
81 * and can do a shared modify_ldt(), or we postallocate it and do
82 * an smp message pass to update it. Currently we are a bit
83 * un-nice to user-space and reload the LDT only on the next
84 * schedule. (only an issue on SMP)
86 * the GDT index of the LDT is allocated dynamically, and is
87 * limited by MAX_LDT_DESCRIPTORS.
93 mm
->segments
= vmalloc(LDT_ENTRIES
*LDT_ENTRY_SIZE
);
96 memset(mm
->segments
, 0, LDT_ENTRIES
*LDT_ENTRY_SIZE
);
98 if (atomic_read(&mm
->mm_users
) > 1)
99 printk(KERN_WARNING
"LDT allocated for cloned task!\n");
101 * Possibly do an SMP cross-call to other CPUs to reload
107 lp
= (__u32
*) ((ldt_info
.entry_number
<< 3) + (char *) mm
->segments
);
109 /* Allow LDTs to be cleared by the user. */
110 if (ldt_info
.base_addr
== 0 && ldt_info
.limit
== 0) {
112 (ldt_info
.contents
== 0 &&
113 ldt_info
.read_exec_only
== 1 &&
114 ldt_info
.seg_32bit
== 0 &&
115 ldt_info
.limit_in_pages
== 0 &&
116 ldt_info
.seg_not_present
== 1 &&
117 ldt_info
.useable
== 0 )) {
124 entry_1
= ((ldt_info
.base_addr
& 0x0000ffff) << 16) |
125 (ldt_info
.limit
& 0x0ffff);
126 entry_2
= (ldt_info
.base_addr
& 0xff000000) |
127 ((ldt_info
.base_addr
& 0x00ff0000) >> 16) |
128 (ldt_info
.limit
& 0xf0000) |
129 ((ldt_info
.read_exec_only
^ 1) << 9) |
130 (ldt_info
.contents
<< 10) |
131 ((ldt_info
.seg_not_present
^ 1) << 15) |
132 (ldt_info
.seg_32bit
<< 22) |
133 (ldt_info
.limit_in_pages
<< 23) |
136 entry_2
|= (ldt_info
.useable
<< 20);
138 /* Install the new entry ... */
150 asmlinkage
int sys_modify_ldt(int func
, void *ptr
, unsigned long bytecount
)
156 ret
= read_ldt(ptr
, bytecount
);
159 ret
= write_ldt(ptr
, bytecount
, 1);
162 ret
= write_ldt(ptr
, bytecount
, 0);