x86: fix execve with -fstack-protect
Ingo Molnar [Tue, 26 Feb 2008 11:55:57 +0000 (12:55 +0100)]
pointed out by pageexec@freemail.hu:

> what happens here is that gcc treats the argument area as owned by the
> callee, not the caller and is allowed to do certain tricks. for ssp it
> will make a copy of the struct passed by value into the local variable
> area and pass *its* address down, and it won't copy it back into the
> original instance stored in the argument area.
>
> so once sys_execve returns, the pt_regs passed by value hasn't at all
> changed and its default content will cause a nice double fault (FWIW,
> this part took me the longest to debug, being down with cold didn't
> help it either ;).

To fix this we pass in pt_regs by pointer.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

arch/x86/kernel/entry_64.S
arch/x86/kernel/process_64.c

index 2ad9a1b..c20c9e7 100644 (file)
@@ -453,6 +453,7 @@ ENTRY(stub_execve)
        CFI_REGISTER rip, r11
        SAVE_REST
        FIXUP_TOP_OF_STACK %r11
+       movq %rsp, %rcx
        call sys_execve
        RESTORE_TOP_OF_STACK %r11
        movq %rax,RAX(%rsp)
@@ -1036,15 +1037,16 @@ ENDPROC(child_rip)
  *     rdi: name, rsi: argv, rdx: envp
  *
  * We want to fallback into:
- *     extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
+ *     extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs *regs)
  *
  * do_sys_execve asm fallback arguments:
- *     rdi: name, rsi: argv, rdx: envp, fake frame on the stack
+ *     rdi: name, rsi: argv, rdx: envp, rcx: fake frame on the stack
  */
 ENTRY(kernel_execve)
        CFI_STARTPROC
        FAKE_STACK_FRAME $0
        SAVE_ALL        
+       movq %rsp,%rcx
        call sys_execve
        movq %rax, RAX(%rsp)    
        RESTORE_REST
index b0cc8f0..43f2877 100644 (file)
@@ -730,16 +730,16 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
  */
 asmlinkage
 long sys_execve(char __user *name, char __user * __user *argv,
-               char __user * __user *envp, struct pt_regs regs)
+               char __user * __user *envp, struct pt_regs *regs)
 {
        long error;
        char * filename;
 
        filename = getname(name);
        error = PTR_ERR(filename);
-       if (IS_ERR(filename)) 
+       if (IS_ERR(filename))
                return error;
-       error = do_execve(filename, argv, envp, &regs); 
+       error = do_execve(filename, argv, envp, regs);
        putname(filename);
        return error;
 }