diff options
Diffstat (limited to 'arch/x86/kernel/process_32.c')
-rw-r--r-- | arch/x86/kernel/process_32.c | 53 |
1 files changed, 32 insertions, 21 deletions
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 1a1ae8edc40c..fec79ad85dc6 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <stdarg.h> | 12 | #include <stdarg.h> |
13 | 13 | ||
14 | #include <linux/stackprotector.h> | ||
14 | #include <linux/cpu.h> | 15 | #include <linux/cpu.h> |
15 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
16 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
@@ -91,6 +92,15 @@ void cpu_idle(void) | |||
91 | { | 92 | { |
92 | int cpu = smp_processor_id(); | 93 | int cpu = smp_processor_id(); |
93 | 94 | ||
95 | /* | ||
96 | * If we're the non-boot CPU, nothing set the stack canary up | ||
97 | * for us. CPU0 already has it initialized but no harm in | ||
98 | * doing it again. This is a good place for updating it, as | ||
99 | * we wont ever return from this function (so the invalid | ||
100 | * canaries already on the stack wont ever trigger). | ||
101 | */ | ||
102 | boot_init_stack_canary(); | ||
103 | |||
94 | current_thread_info()->status |= TS_POLLING; | 104 | current_thread_info()->status |= TS_POLLING; |
95 | 105 | ||
96 | /* endless idle loop with no priority at all */ | 106 | /* endless idle loop with no priority at all */ |
@@ -131,7 +141,7 @@ void __show_regs(struct pt_regs *regs, int all) | |||
131 | if (user_mode_vm(regs)) { | 141 | if (user_mode_vm(regs)) { |
132 | sp = regs->sp; | 142 | sp = regs->sp; |
133 | ss = regs->ss & 0xffff; | 143 | ss = regs->ss & 0xffff; |
134 | savesegment(gs, gs); | 144 | gs = get_user_gs(regs); |
135 | } else { | 145 | } else { |
136 | sp = (unsigned long) (®s->sp); | 146 | sp = (unsigned long) (®s->sp); |
137 | savesegment(ss, ss); | 147 | savesegment(ss, ss); |
@@ -212,6 +222,7 @@ int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | |||
212 | regs.ds = __USER_DS; | 222 | regs.ds = __USER_DS; |
213 | regs.es = __USER_DS; | 223 | regs.es = __USER_DS; |
214 | regs.fs = __KERNEL_PERCPU; | 224 | regs.fs = __KERNEL_PERCPU; |
225 | regs.gs = __KERNEL_STACK_CANARY; | ||
215 | regs.orig_ax = -1; | 226 | regs.orig_ax = -1; |
216 | regs.ip = (unsigned long) kernel_thread_helper; | 227 | regs.ip = (unsigned long) kernel_thread_helper; |
217 | regs.cs = __KERNEL_CS | get_kernel_rpl(); | 228 | regs.cs = __KERNEL_CS | get_kernel_rpl(); |
@@ -304,7 +315,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, | |||
304 | 315 | ||
305 | p->thread.ip = (unsigned long) ret_from_fork; | 316 | p->thread.ip = (unsigned long) ret_from_fork; |
306 | 317 | ||
307 | savesegment(gs, p->thread.gs); | 318 | task_user_gs(p) = get_user_gs(regs); |
308 | 319 | ||
309 | tsk = current; | 320 | tsk = current; |
310 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { | 321 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { |
@@ -342,7 +353,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, | |||
342 | void | 353 | void |
343 | start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) | 354 | start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) |
344 | { | 355 | { |
345 | __asm__("movl %0, %%gs" : : "r"(0)); | 356 | set_user_gs(regs, 0); |
346 | regs->fs = 0; | 357 | regs->fs = 0; |
347 | set_fs(USER_DS); | 358 | set_fs(USER_DS); |
348 | regs->ds = __USER_DS; | 359 | regs->ds = __USER_DS; |
@@ -539,7 +550,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | |||
539 | * used %fs or %gs (it does not today), or if the kernel is | 550 | * used %fs or %gs (it does not today), or if the kernel is |
540 | * running inside of a hypervisor layer. | 551 | * running inside of a hypervisor layer. |
541 | */ | 552 | */ |
542 | savesegment(gs, prev->gs); | 553 | lazy_save_gs(prev->gs); |
543 | 554 | ||
544 | /* | 555 | /* |
545 | * Load the per-thread Thread-Local Storage descriptor. | 556 | * Load the per-thread Thread-Local Storage descriptor. |
@@ -585,31 +596,31 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | |||
585 | * Restore %gs if needed (which is common) | 596 | * Restore %gs if needed (which is common) |
586 | */ | 597 | */ |
587 | if (prev->gs | next->gs) | 598 | if (prev->gs | next->gs) |
588 | loadsegment(gs, next->gs); | 599 | lazy_load_gs(next->gs); |
589 | 600 | ||
590 | percpu_write(current_task, next_p); | 601 | percpu_write(current_task, next_p); |
591 | 602 | ||
592 | return prev_p; | 603 | return prev_p; |
593 | } | 604 | } |
594 | 605 | ||
595 | asmlinkage int sys_fork(struct pt_regs regs) | 606 | int sys_fork(struct pt_regs *regs) |
596 | { | 607 | { |
597 | return do_fork(SIGCHLD, regs.sp, ®s, 0, NULL, NULL); | 608 | return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); |
598 | } | 609 | } |
599 | 610 | ||
600 | asmlinkage int sys_clone(struct pt_regs regs) | 611 | int sys_clone(struct pt_regs *regs) |
601 | { | 612 | { |
602 | unsigned long clone_flags; | 613 | unsigned long clone_flags; |
603 | unsigned long newsp; | 614 | unsigned long newsp; |
604 | int __user *parent_tidptr, *child_tidptr; | 615 | int __user *parent_tidptr, *child_tidptr; |
605 | 616 | ||
606 | clone_flags = regs.bx; | 617 | clone_flags = regs->bx; |
607 | newsp = regs.cx; | 618 | newsp = regs->cx; |
608 | parent_tidptr = (int __user *)regs.dx; | 619 | parent_tidptr = (int __user *)regs->dx; |
609 | child_tidptr = (int __user *)regs.di; | 620 | child_tidptr = (int __user *)regs->di; |
610 | if (!newsp) | 621 | if (!newsp) |
611 | newsp = regs.sp; | 622 | newsp = regs->sp; |
612 | return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); | 623 | return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); |
613 | } | 624 | } |
614 | 625 | ||
615 | /* | 626 | /* |
@@ -622,27 +633,27 @@ asmlinkage int sys_clone(struct pt_regs regs) | |||
622 | * do not have enough call-clobbered registers to hold all | 633 | * do not have enough call-clobbered registers to hold all |
623 | * the information you need. | 634 | * the information you need. |
624 | */ | 635 | */ |
625 | asmlinkage int sys_vfork(struct pt_regs regs) | 636 | int sys_vfork(struct pt_regs *regs) |
626 | { | 637 | { |
627 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.sp, ®s, 0, NULL, NULL); | 638 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, NULL, NULL); |
628 | } | 639 | } |
629 | 640 | ||
630 | /* | 641 | /* |
631 | * sys_execve() executes a new program. | 642 | * sys_execve() executes a new program. |
632 | */ | 643 | */ |
633 | asmlinkage int sys_execve(struct pt_regs regs) | 644 | int sys_execve(struct pt_regs *regs) |
634 | { | 645 | { |
635 | int error; | 646 | int error; |
636 | char *filename; | 647 | char *filename; |
637 | 648 | ||
638 | filename = getname((char __user *) regs.bx); | 649 | filename = getname((char __user *) regs->bx); |
639 | error = PTR_ERR(filename); | 650 | error = PTR_ERR(filename); |
640 | if (IS_ERR(filename)) | 651 | if (IS_ERR(filename)) |
641 | goto out; | 652 | goto out; |
642 | error = do_execve(filename, | 653 | error = do_execve(filename, |
643 | (char __user * __user *) regs.cx, | 654 | (char __user * __user *) regs->cx, |
644 | (char __user * __user *) regs.dx, | 655 | (char __user * __user *) regs->dx, |
645 | ®s); | 656 | regs); |
646 | if (error == 0) { | 657 | if (error == 0) { |
647 | /* Make sure we don't return using sysenter.. */ | 658 | /* Make sure we don't return using sysenter.. */ |
648 | set_thread_flag(TIF_IRET); | 659 | set_thread_flag(TIF_IRET); |