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/kernel | |
| 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/kernel')
| -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 |
3 files changed, 44 insertions, 71 deletions
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 45b2f293f8c..a78f5649e8d 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 c51bb172e14..aa9b1100027 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 4fc2e29b771..c30da5b3f2d 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 | |||
