diff options
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/sys-i386/ldt.c | 114 |
1 files changed, 62 insertions, 52 deletions
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index dc755b0b9db8..bd3c34aa52e5 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c | |||
@@ -4,96 +4,106 @@ | |||
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include "linux/config.h" | 6 | #include "linux/config.h" |
7 | #include "linux/sched.h" | ||
7 | #include "linux/slab.h" | 8 | #include "linux/slab.h" |
9 | #include "linux/types.h" | ||
8 | #include "asm/uaccess.h" | 10 | #include "asm/uaccess.h" |
9 | #include "asm/ptrace.h" | 11 | #include "asm/ptrace.h" |
12 | #include "asm/smp.h" | ||
13 | #include "asm/ldt.h" | ||
10 | #include "choose-mode.h" | 14 | #include "choose-mode.h" |
11 | #include "kern.h" | 15 | #include "kern.h" |
16 | #include "mode_kern.h" | ||
12 | 17 | ||
13 | #ifdef CONFIG_MODE_TT | 18 | #ifdef CONFIG_MODE_TT |
14 | extern int modify_ldt(int func, void *ptr, unsigned long bytecount); | ||
15 | 19 | ||
16 | /* XXX this needs copy_to_user and copy_from_user */ | 20 | extern int modify_ldt(int func, void *ptr, unsigned long bytecount); |
17 | 21 | ||
18 | int sys_modify_ldt_tt(int func, void __user *ptr, unsigned long bytecount) | 22 | static int do_modify_ldt_tt(int func, void *ptr, unsigned long bytecount) |
19 | { | 23 | { |
20 | if (!access_ok(VERIFY_READ, ptr, bytecount)) | ||
21 | return -EFAULT; | ||
22 | |||
23 | return modify_ldt(func, ptr, bytecount); | 24 | return modify_ldt(func, ptr, bytecount); |
24 | } | 25 | } |
26 | |||
25 | #endif | 27 | #endif |
26 | 28 | ||
27 | #ifdef CONFIG_MODE_SKAS | 29 | #ifdef CONFIG_MODE_SKAS |
28 | extern int userspace_pid[]; | ||
29 | 30 | ||
31 | #include "skas.h" | ||
30 | #include "skas_ptrace.h" | 32 | #include "skas_ptrace.h" |
31 | 33 | ||
32 | int sys_modify_ldt_skas(int func, void __user *ptr, unsigned long bytecount) | 34 | static int do_modify_ldt_skas(int func, void *ptr, unsigned long bytecount) |
33 | { | 35 | { |
34 | struct ptrace_ldt ldt; | 36 | struct ptrace_ldt ldt; |
35 | void *buf; | 37 | u32 cpu; |
36 | int res, n; | 38 | int res; |
37 | 39 | ||
38 | buf = kmalloc(bytecount, GFP_KERNEL); | 40 | ldt = ((struct ptrace_ldt) { .func = func, |
39 | if(buf == NULL) | 41 | .ptr = ptr, |
40 | return(-ENOMEM); | 42 | .bytecount = bytecount }); |
41 | 43 | ||
42 | res = 0; | 44 | cpu = get_cpu(); |
45 | res = ptrace(PTRACE_LDT, userspace_pid[cpu], 0, (unsigned long) &ldt); | ||
46 | put_cpu(); | ||
47 | |||
48 | return res; | ||
49 | } | ||
50 | #endif | ||
51 | |||
52 | int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) | ||
53 | { | ||
54 | struct user_desc info; | ||
55 | int res = 0; | ||
56 | void *buf = NULL; | ||
57 | void *p = NULL; /* What we pass to host. */ | ||
43 | 58 | ||
44 | switch(func){ | 59 | switch(func){ |
45 | case 1: | 60 | case 1: |
46 | case 0x11: | 61 | case 0x11: /* write_ldt */ |
47 | res = copy_from_user(buf, ptr, bytecount); | 62 | /* Do this check now to avoid overflows. */ |
48 | break; | 63 | if (bytecount != sizeof(struct user_desc)) { |
49 | } | 64 | res = -EINVAL; |
65 | goto out; | ||
66 | } | ||
67 | |||
68 | if(copy_from_user(&info, ptr, sizeof(info))) { | ||
69 | res = -EFAULT; | ||
70 | goto out; | ||
71 | } | ||
50 | 72 | ||
51 | if(res != 0){ | 73 | p = &info; |
52 | res = -EFAULT; | 74 | break; |
75 | case 0: | ||
76 | case 2: /* read_ldt */ | ||
77 | |||
78 | /* The use of info avoids kmalloc on the write case, not on the | ||
79 | * read one. */ | ||
80 | buf = kmalloc(bytecount, GFP_KERNEL); | ||
81 | if (!buf) { | ||
82 | res = -ENOMEM; | ||
83 | goto out; | ||
84 | } | ||
85 | p = buf; | ||
86 | default: | ||
87 | res = -ENOSYS; | ||
53 | goto out; | 88 | goto out; |
54 | } | 89 | } |
55 | 90 | ||
56 | ldt = ((struct ptrace_ldt) { .func = func, | 91 | res = CHOOSE_MODE_PROC(do_modify_ldt_tt, do_modify_ldt_skas, func, |
57 | .ptr = buf, | 92 | p, bytecount); |
58 | .bytecount = bytecount }); | ||
59 | #warning Need to look up userspace_pid by cpu | ||
60 | res = ptrace(PTRACE_LDT, userspace_pid[0], 0, (unsigned long) &ldt); | ||
61 | if(res < 0) | 93 | if(res < 0) |
62 | goto out; | 94 | goto out; |
63 | 95 | ||
64 | switch(func){ | 96 | switch(func){ |
65 | case 0: | 97 | case 0: |
66 | case 2: | 98 | case 2: |
67 | n = res; | 99 | /* Modify_ldt was for reading and returned the number of read |
68 | res = copy_to_user(ptr, buf, n); | 100 | * bytes.*/ |
69 | if(res != 0) | 101 | if(copy_to_user(ptr, p, res)) |
70 | res = -EFAULT; | 102 | res = -EFAULT; |
71 | else | ||
72 | res = n; | ||
73 | break; | 103 | break; |
74 | } | 104 | } |
75 | 105 | ||
76 | out: | 106 | out: |
77 | kfree(buf); | 107 | kfree(buf); |
78 | return(res); | 108 | return res; |
79 | } | ||
80 | #endif | ||
81 | |||
82 | int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) | ||
83 | { | ||
84 | return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func, | ||
85 | ptr, bytecount)); | ||
86 | } | 109 | } |
87 | |||
88 | |||
89 | |||
90 | /* | ||
91 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
92 | * Emacs will notice this stuff at the end of the file and automatically | ||
93 | * adjust the settings for this buffer only. This must remain at the end | ||
94 | * of the file. | ||
95 | * --------------------------------------------------------------------------- | ||
96 | * Local variables: | ||
97 | * c-file-style: "linux" | ||
98 | * End: | ||
99 | */ | ||