ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ia64 / ia32 / ia32_ldt.c
1 /*
2  * Copyright (C) 2001 Hewlett-Packard Co
3  *      David Mosberger-Tang <davidm@hpl.hp.com>
4  *
5  * Adapted from arch/i386/kernel/ldt.c
6  */
7
8 #include <linux/errno.h>
9 #include <linux/sched.h>
10 #include <linux/string.h>
11 #include <linux/mm.h>
12 #include <linux/smp.h>
13 #include <linux/smp_lock.h>
14 #include <linux/vmalloc.h>
15
16 #include <asm/uaccess.h>
17
18 #include "ia32priv.h"
19
20 #define P(p)    ((void *) (unsigned long) (p))
21
22 /*
23  * read_ldt() is not really atomic - this is not a problem since synchronization of reads
24  * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic,
25  * to protect the security checks done on new descriptors.
26  */
27 static int
28 read_ldt (void *ptr, unsigned long bytecount)
29 {
30         char *src, *dst, buf[256];      /* temporary buffer (don't overflow kernel stack!) */
31         unsigned long bytes_left, n;
32
33         if (bytecount > IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE)
34                 bytecount = IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE;
35
36         bytes_left = bytecount;
37
38         src = (void *) IA32_LDT_OFFSET;
39         dst = ptr;
40
41         while (bytes_left) {
42                 n = sizeof(buf);
43                 if (n > bytes_left)
44                         n = bytes_left;
45
46                 /*
47                  * We know we're reading valid memory, but we still must guard against
48                  * running out of memory.
49                  */
50                 if (__copy_from_user(buf, src, n))
51                         return -EFAULT;
52
53                 if (copy_to_user(dst, buf, n))
54                         return -EFAULT;
55
56                 src += n;
57                 dst += n;
58                 bytes_left -= n;
59         }
60         return bytecount;
61 }
62
63 static int
64 read_default_ldt (void * ptr, unsigned long bytecount)
65 {
66         unsigned long size;
67         int err;
68
69         /* XXX fix me: should return equivalent of default_ldt[0] */
70         err = 0;
71         size = 8;
72         if (size > bytecount)
73                 size = bytecount;
74
75         err = size;
76         if (clear_user(ptr, size))
77                 err = -EFAULT;
78
79         return err;
80 }
81
82 static int
83 write_ldt (void * ptr, unsigned long bytecount, int oldmode)
84 {
85         struct ia32_user_desc ldt_info;
86         __u64 entry;
87         int ret;
88
89         if (bytecount != sizeof(ldt_info))
90                 return -EINVAL;
91         if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
92                 return -EFAULT;
93
94         if (ldt_info.entry_number >= IA32_LDT_ENTRIES)
95                 return -EINVAL;
96         if (ldt_info.contents == 3) {
97                 if (oldmode)
98                         return -EINVAL;
99                 if (ldt_info.seg_not_present == 0)
100                         return -EINVAL;
101         }
102
103         if (ldt_info.base_addr == 0 && ldt_info.limit == 0
104             && (oldmode || (ldt_info.contents == 0 && ldt_info.read_exec_only == 1
105                             && ldt_info.seg_32bit == 0 && ldt_info.limit_in_pages == 0
106                             && ldt_info.seg_not_present == 1 && ldt_info.useable == 0)))
107                 /* allow LDTs to be cleared by the user */
108                 entry = 0;
109         else
110                 /* we must set the "Accessed" bit as IVE doesn't emulate it */
111                 entry = IA32_SEG_DESCRIPTOR(ldt_info.base_addr, ldt_info.limit,
112                                             (((ldt_info.read_exec_only ^ 1) << 1)
113                                              | (ldt_info.contents << 2)) | 1,
114                                             1, 3, ldt_info.seg_not_present ^ 1,
115                                             (oldmode ? 0 : ldt_info.useable),
116                                             ldt_info.seg_32bit,
117                                             ldt_info.limit_in_pages);
118         /*
119          * Install the new entry.  We know we're accessing valid (mapped) user-level
120          * memory, but we still need to guard against out-of-memory, hence we must use
121          * put_user().
122          */
123         ret = __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number);
124         ia32_load_segment_descriptors(current);
125         return ret;
126 }
127
128 asmlinkage int
129 sys32_modify_ldt (int func, unsigned int ptr, unsigned int bytecount)
130 {
131         int ret = -ENOSYS;
132
133         switch (func) {
134               case 0:
135                 ret = read_ldt(P(ptr), bytecount);
136                 break;
137               case 1:
138                 ret = write_ldt(P(ptr), bytecount, 1);
139                 break;
140               case 2:
141                 ret = read_default_ldt(P(ptr), bytecount);
142                 break;
143               case 0x11:
144                 ret = write_ldt(P(ptr), bytecount, 0);
145                 break;
146         }
147         return ret;
148 }