diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-21 16:41:46 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-11-28 22:44:46 -0500 |
commit | 20ecc91c3230b747cd13d9a2f43a45f6445a3906 (patch) | |
tree | 3892c3eafe47e78f153549158c24d26cf1b7ecc8 /arch/m68k | |
parent | dfe09ae0e5fe40679af05b1ba810d469844c97b3 (diff) |
m68k: sanitize copy_thread(), fork/vfork/clone wrappers, switch to generic fork/vfork
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/m68k')
-rw-r--r-- | arch/m68k/include/asm/unistd.h | 2 | ||||
-rw-r--r-- | arch/m68k/kernel/entry.S | 23 | ||||
-rw-r--r-- | arch/m68k/kernel/process.c | 86 | ||||
-rw-r--r-- | arch/m68k/kernel/syscalltable.S | 6 |
4 files changed, 46 insertions, 71 deletions
diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index 0aa165405966..a021d67cdd72 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h | |||
@@ -32,6 +32,8 @@ | |||
32 | #define __ARCH_WANT_SYS_RT_SIGACTION | 32 | #define __ARCH_WANT_SYS_RT_SIGACTION |
33 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 33 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
34 | #define __ARCH_WANT_SYS_EXECVE | 34 | #define __ARCH_WANT_SYS_EXECVE |
35 | #define __ARCH_WANT_SYS_FORK | ||
36 | #define __ARCH_WANT_SYS_VFORK | ||
35 | 37 | ||
36 | /* | 38 | /* |
37 | * "Conditional" syscalls | 39 | * "Conditional" syscalls |
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 45b2f293f8cf..a78f5649e8de 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S | |||
@@ -44,34 +44,29 @@ | |||
44 | 44 | ||
45 | .globl system_call, buserr, trap, resume | 45 | .globl system_call, buserr, trap, resume |
46 | .globl sys_call_table | 46 | .globl sys_call_table |
47 | .globl sys_fork, sys_clone, sys_vfork | 47 | .globl __sys_fork, __sys_clone, __sys_vfork |
48 | .globl ret_from_interrupt, bad_interrupt | 48 | .globl ret_from_interrupt, bad_interrupt |
49 | .globl auto_irqhandler_fixup | 49 | .globl auto_irqhandler_fixup |
50 | .globl user_irqvec_fixup | 50 | .globl user_irqvec_fixup |
51 | 51 | ||
52 | .text | 52 | .text |
53 | ENTRY(sys_fork) | 53 | ENTRY(__sys_fork) |
54 | SAVE_SWITCH_STACK | 54 | SAVE_SWITCH_STACK |
55 | pea %sp@(SWITCH_STACK_SIZE) | 55 | jbsr sys_fork |
56 | jbsr m68k_fork | 56 | lea %sp@(24),%sp |
57 | addql #4,%sp | ||
58 | RESTORE_SWITCH_STACK | ||
59 | rts | 57 | rts |
60 | 58 | ||
61 | ENTRY(sys_clone) | 59 | ENTRY(__sys_clone) |
62 | SAVE_SWITCH_STACK | 60 | SAVE_SWITCH_STACK |
63 | pea %sp@(SWITCH_STACK_SIZE) | 61 | pea %sp@(SWITCH_STACK_SIZE) |
64 | jbsr m68k_clone | 62 | jbsr m68k_clone |
65 | addql #4,%sp | 63 | lea %sp@(28),%sp |
66 | RESTORE_SWITCH_STACK | ||
67 | rts | 64 | rts |
68 | 65 | ||
69 | ENTRY(sys_vfork) | 66 | ENTRY(__sys_vfork) |
70 | SAVE_SWITCH_STACK | 67 | SAVE_SWITCH_STACK |
71 | pea %sp@(SWITCH_STACK_SIZE) | 68 | jbsr sys_vfork |
72 | jbsr m68k_vfork | 69 | lea %sp@(24),%sp |
73 | addql #4,%sp | ||
74 | RESTORE_SWITCH_STACK | ||
75 | rts | 70 | rts |
76 | 71 | ||
77 | ENTRY(sys_sigreturn) | 72 | ENTRY(sys_sigreturn) |
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index c51bb172e14d..aa9b11000273 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c | |||
@@ -136,57 +136,36 @@ void flush_thread(void) | |||
136 | } | 136 | } |
137 | 137 | ||
138 | /* | 138 | /* |
139 | * "m68k_fork()".. By the time we get here, the | 139 | * Why not generic sys_clone, you ask? m68k passes all arguments on stack. |
140 | * non-volatile registers have also been saved on the | 140 | * And we need all registers saved, which means a bunch of stuff pushed |
141 | * stack. We do some ugly pointer stuff here.. (see | 141 | * on top of pt_regs, which means that sys_clone() arguments would be |
142 | * also copy_thread) | 142 | * buried. We could, of course, copy them, but it's too costly for no |
143 | * good reason - generic clone() would have to copy them *again* for | ||
144 | * do_fork() anyway. So in this case it's actually better to pass pt_regs * | ||
145 | * and extract arguments for do_fork() from there. Eventually we might | ||
146 | * go for calling do_fork() directly from the wrapper, but only after we | ||
147 | * are finished with do_fork() prototype conversion. | ||
143 | */ | 148 | */ |
144 | |||
145 | asmlinkage int m68k_fork(struct pt_regs *regs) | ||
146 | { | ||
147 | #ifdef CONFIG_MMU | ||
148 | return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
149 | #else | ||
150 | return -EINVAL; | ||
151 | #endif | ||
152 | } | ||
153 | |||
154 | asmlinkage int m68k_vfork(struct pt_regs *regs) | ||
155 | { | ||
156 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, | ||
157 | NULL, NULL); | ||
158 | } | ||
159 | |||
160 | asmlinkage int m68k_clone(struct pt_regs *regs) | 149 | asmlinkage int m68k_clone(struct pt_regs *regs) |
161 | { | 150 | { |
162 | unsigned long clone_flags; | 151 | /* regs will be equal to current_pt_regs() */ |
163 | unsigned long newsp; | 152 | return do_fork(regs->d1, regs->d2, regs, 0, |
164 | int __user *parent_tidptr, *child_tidptr; | 153 | (int __user *)regs->d3, (int __user *)regs->d4); |
165 | |||
166 | /* syscall2 puts clone_flags in d1 and usp in d2 */ | ||
167 | clone_flags = regs->d1; | ||
168 | newsp = regs->d2; | ||
169 | parent_tidptr = (int __user *)regs->d3; | ||
170 | child_tidptr = (int __user *)regs->d4; | ||
171 | if (!newsp) | ||
172 | newsp = rdusp(); | ||
173 | return do_fork(clone_flags, newsp, regs, 0, | ||
174 | parent_tidptr, child_tidptr); | ||
175 | } | 154 | } |
176 | 155 | ||
177 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 156 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
178 | unsigned long arg, | 157 | unsigned long arg, |
179 | struct task_struct * p, struct pt_regs * regs) | 158 | struct task_struct * p, struct pt_regs * unused) |
180 | { | 159 | { |
181 | struct pt_regs * childregs; | 160 | struct fork_frame { |
182 | struct switch_stack *childstack; | 161 | struct switch_stack sw; |
162 | struct pt_regs regs; | ||
163 | } *frame; | ||
183 | 164 | ||
184 | childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; | 165 | frame = (struct fork_frame *) (task_stack_page(p) + THREAD_SIZE) - 1; |
185 | childstack = ((struct switch_stack *) childregs) - 1; | ||
186 | 166 | ||
187 | p->thread.usp = usp; | 167 | p->thread.ksp = (unsigned long)frame; |
188 | p->thread.ksp = (unsigned long)childstack; | 168 | p->thread.esp0 = (unsigned long)&frame->regs; |
189 | p->thread.esp0 = (unsigned long)childregs; | ||
190 | 169 | ||
191 | /* | 170 | /* |
192 | * Must save the current SFC/DFC value, NOT the value when | 171 | * Must save the current SFC/DFC value, NOT the value when |
@@ -194,25 +173,24 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
194 | */ | 173 | */ |
195 | p->thread.fs = get_fs().seg; | 174 | p->thread.fs = get_fs().seg; |
196 | 175 | ||
197 | if (unlikely(!regs)) { | 176 | if (unlikely(p->flags & PF_KTHREAD)) { |
198 | /* kernel thread */ | 177 | /* kernel thread */ |
199 | memset(childstack, 0, | 178 | memset(frame, 0, sizeof(struct fork_frame)); |
200 | sizeof(struct switch_stack) + sizeof(struct pt_regs)); | 179 | frame->regs.sr = PS_S; |
201 | childregs->sr = PS_S; | 180 | frame->sw.a3 = usp; /* function */ |
202 | childstack->a3 = usp; /* function */ | 181 | frame->sw.d7 = arg; |
203 | childstack->d7 = arg; | 182 | frame->sw.retpc = (unsigned long)ret_from_kernel_thread; |
204 | childstack->retpc = (unsigned long)ret_from_kernel_thread; | ||
205 | p->thread.usp = 0; | 183 | p->thread.usp = 0; |
206 | return 0; | 184 | return 0; |
207 | } | 185 | } |
208 | *childregs = *regs; | 186 | memcpy(frame, container_of(current_pt_regs(), struct fork_frame, regs), |
209 | childregs->d0 = 0; | 187 | sizeof(struct fork_frame)); |
210 | 188 | frame->regs.d0 = 0; | |
211 | *childstack = ((struct switch_stack *) regs)[-1]; | 189 | frame->sw.retpc = (unsigned long)ret_from_fork; |
212 | childstack->retpc = (unsigned long)ret_from_fork; | 190 | p->thread.usp = usp ?: rdusp(); |
213 | 191 | ||
214 | if (clone_flags & CLONE_SETTLS) | 192 | if (clone_flags & CLONE_SETTLS) |
215 | task_thread_info(p)->tp_value = regs->d5; | 193 | task_thread_info(p)->tp_value = frame->regs.d5; |
216 | 194 | ||
217 | #ifdef CONFIG_FPU | 195 | #ifdef CONFIG_FPU |
218 | if (!FPU_IS_EMU) { | 196 | if (!FPU_IS_EMU) { |
diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S index 4fc2e29b771b..c30da5b3f2db 100644 --- a/arch/m68k/kernel/syscalltable.S +++ b/arch/m68k/kernel/syscalltable.S | |||
@@ -22,7 +22,7 @@ ALIGN | |||
22 | ENTRY(sys_call_table) | 22 | ENTRY(sys_call_table) |
23 | .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ | 23 | .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ |
24 | .long sys_exit | 24 | .long sys_exit |
25 | .long sys_fork | 25 | .long __sys_fork |
26 | .long sys_read | 26 | .long sys_read |
27 | .long sys_write | 27 | .long sys_write |
28 | .long sys_open /* 5 */ | 28 | .long sys_open /* 5 */ |
@@ -140,7 +140,7 @@ ENTRY(sys_call_table) | |||
140 | .long sys_ipc | 140 | .long sys_ipc |
141 | .long sys_fsync | 141 | .long sys_fsync |
142 | .long sys_sigreturn | 142 | .long sys_sigreturn |
143 | .long sys_clone /* 120 */ | 143 | .long __sys_clone /* 120 */ |
144 | .long sys_setdomainname | 144 | .long sys_setdomainname |
145 | .long sys_newuname | 145 | .long sys_newuname |
146 | .long sys_cacheflush /* modify_ldt for i386 */ | 146 | .long sys_cacheflush /* modify_ldt for i386 */ |
@@ -210,7 +210,7 @@ ENTRY(sys_call_table) | |||
210 | .long sys_sendfile | 210 | .long sys_sendfile |
211 | .long sys_ni_syscall /* streams1 */ | 211 | .long sys_ni_syscall /* streams1 */ |
212 | .long sys_ni_syscall /* streams2 */ | 212 | .long sys_ni_syscall /* streams2 */ |
213 | .long sys_vfork /* 190 */ | 213 | .long __sys_vfork /* 190 */ |
214 | .long sys_getrlimit | 214 | .long sys_getrlimit |
215 | .long sys_mmap2 | 215 | .long sys_mmap2 |
216 | .long sys_truncate64 | 216 | .long sys_truncate64 |