Re: [PATCH 2.4.31 6/9] gcc4: fix x86_64 sys_iopl() bug

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, 12 Jun 2005 15:29:43 +0200, Andi Kleen wrote:
>> @@ -113,9 +113,18 @@ quiet_ni_syscall:
>>  	PTREGSCALL stub32_fork, sys32_fork
>>  	PTREGSCALL stub32_clone, sys32_clone
>>  	PTREGSCALL stub32_vfork, sys32_vfork
>> -	PTREGSCALL stub32_iopl, sys_iopl
>>  	PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend
>>  
>> +	.macro PTREGSCALL3 label, func, arg
>
>PTREGSCALL3? I'm sure that is not in 2.6. How about just changing
>PTREGSCALL globally? 
>
>iirc the other ptregs syscalls were safe, but I still changed them in 2.6
>to use a pointer argument.

This patch changes all PTREGSCALLs to follow the 2.6 convention.
Unfortunately this is a much larger patch than the one that just
fixes sys_iopl(). I've triple-checked the register numbers passed
to the PTREGSCALL macro, and things do seem to work correctly.

Signed-off-by: Mikael Pettersson <[email protected]>

 arch/x86_64/ia32/ia32_signal.c |   28 ++++++++++++++--------------
 arch/x86_64/ia32/ia32entry.S   |   23 ++++++++++++-----------
 arch/x86_64/ia32/sys_ia32.c    |   18 +++++++++---------
 arch/x86_64/kernel/entry.S     |   16 +++++++++-------
 arch/x86_64/kernel/ioport.c    |    6 +++---
 arch/x86_64/kernel/process.c   |   14 +++++++-------
 arch/x86_64/kernel/signal.c    |   24 ++++++++++++------------
 7 files changed, 66 insertions(+), 63 deletions(-)

diff -rupN linux-2.4.31/arch/x86_64/ia32/ia32_signal.c linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/ia32/ia32_signal.c
--- linux-2.4.31/arch/x86_64/ia32/ia32_signal.c	2003-11-29 00:28:11.000000000 +0100
+++ linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/ia32/ia32_signal.c	2005-06-12 17:55:52.000000000 +0200
@@ -89,7 +89,7 @@ static int ia32_copy_siginfo_to_user(sig
 }
 
 asmlinkage long
-sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs regs)
+sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs *regs)
 {
 	sigset_t saveset;
 
@@ -100,18 +100,18 @@ sys32_sigsuspend(int history0, int histo
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs.rax = -EINTR;
+	regs->rax = -EINTR;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(&regs, &saveset))
+		if (do_signal(regs, &saveset))
 			return -EINTR;
 	}
 }
 
 asmlinkage long
 sys32_sigaltstack(const stack_ia32_t *uss_ptr, stack_ia32_t *uoss_ptr, 
-				  struct pt_regs regs)
+				  struct pt_regs *regs)
 {
 	stack_t uss,uoss; 
 	int ret;
@@ -128,7 +128,7 @@ sys32_sigaltstack(const stack_ia32_t *us
 	}
 	seg = get_fs(); 
 	set_fs(KERNEL_DS); 
-	ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs.rsp);
+	ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->rsp);
 	set_fs(seg); 
 	if (ret >= 0 && uoss_ptr)  {
 		if (!access_ok(VERIFY_WRITE,uoss_ptr,sizeof(stack_ia32_t)) ||
@@ -241,9 +241,9 @@ ia32_restore_sigcontext(struct pt_regs *
 	return err;
 }
 
-asmlinkage long sys32_sigreturn(struct pt_regs regs)
+asmlinkage long sys32_sigreturn(struct pt_regs *regs)
 {
-	struct sigframe *frame = (struct sigframe *)(regs.rsp - 8);
+	struct sigframe *frame = (struct sigframe *)(regs->rsp - 8);
 	sigset_t set;
 	unsigned int eax;
 
@@ -261,18 +261,18 @@ asmlinkage long sys32_sigreturn(struct p
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 	
-	if (ia32_restore_sigcontext(&regs, &frame->sc, &eax))
+	if (ia32_restore_sigcontext(regs, &frame->sc, &eax))
 		goto badframe;
 	return eax;
 
 badframe:
-	signal_fault(&regs,frame,"32bit sigreturn");
+	signal_fault(regs,frame,"32bit sigreturn");
 	return 0;
 }	
 
-asmlinkage long sys32_rt_sigreturn(struct pt_regs regs)
+asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
 {
-	struct rt_sigframe *frame = (struct rt_sigframe *)(regs.rsp - 4);
+	struct rt_sigframe *frame = (struct rt_sigframe *)(regs->rsp - 4);
 	sigset_t set;
 	stack_t st;
 	unsigned int eax;
@@ -288,7 +288,7 @@ asmlinkage long sys32_rt_sigreturn(struc
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 	
-	if (ia32_restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax))
+	if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax))
 		goto badframe;
 
 	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
@@ -298,14 +298,14 @@ asmlinkage long sys32_rt_sigreturn(struc
 	{
 		mm_segment_t oldds = get_fs(); 
 		set_fs(KERNEL_DS); 
-		do_sigaltstack(&st, NULL, regs.rsp);
+		do_sigaltstack(&st, NULL, regs->rsp);
 		set_fs(oldds);  
 	}
 
 	return eax;
 
 badframe:
-	signal_fault(&regs,frame,"32bit rt sigreturn");
+	signal_fault(regs,frame,"32bit rt sigreturn");
 	return 0;
 }	
 
diff -rupN linux-2.4.31/arch/x86_64/ia32/ia32entry.S linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/ia32/ia32entry.S
--- linux-2.4.31/arch/x86_64/ia32/ia32entry.S	2005-01-19 18:00:53.000000000 +0100
+++ linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/ia32/ia32entry.S	2005-06-12 17:55:52.000000000 +0200
@@ -98,23 +98,24 @@ quiet_ni_syscall:
 	movl $-ENOSYS,%eax
 	ret	
 	
-	.macro PTREGSCALL label, func
+	.macro PTREGSCALL label, func, arg
 	.globl \label
 \label:
 	leaq \func(%rip),%rax
+	leaq -ARGOFFSET+8(%rsp),\arg	/* 8 for return address */
 	jmp  ia32_ptregs_common	
 	.endm
 
-	PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn
-	PTREGSCALL stub32_sigreturn, sys32_sigreturn
-	PTREGSCALL stub32_sigaltstack, sys32_sigaltstack
-	PTREGSCALL stub32_sigsuspend, sys32_sigsuspend
-	PTREGSCALL stub32_execve, sys32_execve
-	PTREGSCALL stub32_fork, sys32_fork
-	PTREGSCALL stub32_clone, sys32_clone
-	PTREGSCALL stub32_vfork, sys32_vfork
-	PTREGSCALL stub32_iopl, sys_iopl
-	PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend
+	PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi
+	PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi
+	PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx
+	PTREGSCALL stub32_sigsuspend, sys32_sigsuspend, %rcx
+	PTREGSCALL stub32_execve, sys32_execve, %rcx
+	PTREGSCALL stub32_fork, sys32_fork, %rdi
+	PTREGSCALL stub32_clone, sys32_clone, %rdx
+	PTREGSCALL stub32_vfork, sys32_vfork, %rdi
+	PTREGSCALL stub32_iopl, sys_iopl, %rsi
+	PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend, %rdx
 
 ENTRY(ia32_ptregs_common)
 	popq %r11
diff -rupN linux-2.4.31/arch/x86_64/ia32/sys_ia32.c linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/ia32/sys_ia32.c
--- linux-2.4.31/arch/x86_64/ia32/sys_ia32.c	2005-01-19 18:00:53.000000000 +0100
+++ linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/ia32/sys_ia32.c	2005-06-12 17:55:52.000000000 +0200
@@ -2222,7 +2222,7 @@ static int nargs(u32 src, char **dst) 
 	return cnt; 
 } 
 
-asmlinkage long sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
+asmlinkage long sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs *regs)
 { 
 	mm_segment_t oldseg; 
 	char **buf = NULL; 
@@ -2270,7 +2270,7 @@ asmlinkage long sys32_execve(char *name,
 
 	oldseg = get_fs(); 
 	set_fs(KERNEL_DS);
-	ret = do_execve(name, argv ? buf : NULL, envp ? buf+na : NULL, &regs);  
+	ret = do_execve(name, argv ? buf : NULL, envp ? buf+na : NULL, regs);  
 	set_fs(oldseg); 
 
 	if (ret == 0)
@@ -2288,16 +2288,16 @@ free:
 	return ret; 
 } 
 
-asmlinkage long sys32_fork(struct pt_regs regs)
+asmlinkage long sys32_fork(struct pt_regs *regs)
 {
-	return do_fork(SIGCHLD, regs.rsp, &regs, 0);
+	return do_fork(SIGCHLD, regs->rsp, regs, 0);
 }
 
-asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
+asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs *regs)
 {
 	if (!newsp)
-		newsp = regs.rsp;
-	return do_fork(clone_flags, newsp, &regs, 0);
+		newsp = regs->rsp;
+	return do_fork(clone_flags, newsp, regs, 0);
 }
 
 /*
@@ -2310,9 +2310,9 @@ asmlinkage long sys32_clone(unsigned int
  * do not have enough call-clobbered registers to hold all
  * the information you need.
  */
-asmlinkage long sys32_vfork(struct pt_regs regs)
+asmlinkage long sys32_vfork(struct pt_regs *regs)
 {
-	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0);
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->rsp, regs, 0);
 }
 
 /*
diff -rupN linux-2.4.31/arch/x86_64/kernel/entry.S linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/kernel/entry.S
--- linux-2.4.31/arch/x86_64/kernel/entry.S	2003-11-29 00:28:11.000000000 +0100
+++ linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/kernel/entry.S	2005-06-12 17:55:52.000000000 +0200
@@ -237,19 +237,20 @@ intret_signal_test:		
  * Certain special system calls that need to save a complete stack frame.
  */ 								
 	
-	.macro PTREGSCALL label,func
+	.macro PTREGSCALL label,func,arg
 	.globl \label
 \label:
 	leaq	\func(%rip),%rax
+	leaq    -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
 	jmp	ptregscall_common
 	.endm
 
-	PTREGSCALL stub_clone, sys_clone
-	PTREGSCALL stub_fork, sys_fork
-	PTREGSCALL stub_vfork, sys_vfork
-	PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend
-	PTREGSCALL stub_sigaltstack, sys_sigaltstack
-	PTREGSCALL stub_iopl, sys_iopl
+	PTREGSCALL stub_clone, sys_clone, %rdx /* not %r8 as it is in 2.6 */
+	PTREGSCALL stub_fork, sys_fork, %rdi
+	PTREGSCALL stub_vfork, sys_vfork, %rdi
+	PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
+	PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
+	PTREGSCALL stub_iopl, sys_iopl, %rsi
 
 ENTRY(ptregscall_common)
 	popq %r11
@@ -290,6 +291,7 @@ exec_32bit:
 ENTRY(stub_rt_sigreturn)
 	addq $8, %rsp		
 	SAVE_REST
+	movq %rsp,%rdi
 	FIXUP_TOP_OF_STACK %r11
 	call sys_rt_sigreturn
 	movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
diff -rupN linux-2.4.31/arch/x86_64/kernel/ioport.c linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/kernel/ioport.c
--- linux-2.4.31/arch/x86_64/kernel/ioport.c	2003-11-29 00:28:11.000000000 +0100
+++ linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/kernel/ioport.c	2005-06-12 17:55:52.000000000 +0200
@@ -81,9 +81,9 @@ asmlinkage long sys_ioperm(unsigned long
  * code.
  */
 
-asmlinkage long sys_iopl(unsigned int level, struct pt_regs regs)
+asmlinkage long sys_iopl(unsigned int level, struct pt_regs *regs)
 {
-	unsigned int old = (regs.eflags >> 12) & 3;
+	unsigned int old = (regs->eflags >> 12) & 3;
 
 	if (level > 3)
 		return -EINVAL;
@@ -92,6 +92,6 @@ asmlinkage long sys_iopl(unsigned int le
 		if (!capable(CAP_SYS_RAWIO))
 			return -EPERM;
 	}
-	regs.eflags = (regs.eflags & 0xffffffffffffcfff) | (level << 12);
+	regs->eflags = (regs->eflags &~ 0x3000UL) | (level << 12);
 	return 0;
 }
diff -rupN linux-2.4.31/arch/x86_64/kernel/process.c linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/kernel/process.c
--- linux-2.4.31/arch/x86_64/kernel/process.c	2005-06-01 18:02:21.000000000 +0200
+++ linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/kernel/process.c	2005-06-12 17:55:52.000000000 +0200
@@ -700,16 +700,16 @@ void set_personality_64bit(void)
 	current->thread.flags = 0;
 }
 
-asmlinkage long sys_fork(struct pt_regs regs)
+asmlinkage long sys_fork(struct pt_regs *regs)
 {
-	return do_fork(SIGCHLD, regs.rsp, &regs, 0);
+	return do_fork(SIGCHLD, regs->rsp, regs, 0);
 }
 
-asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs regs)
+asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs)
 {
 	if (!newsp)
-		newsp = regs.rsp;
-	return do_fork(clone_flags, newsp, &regs, 0);
+		newsp = regs->rsp;
+	return do_fork(clone_flags, newsp, regs, 0);
 }
 
 /*
@@ -722,9 +722,9 @@ asmlinkage long sys_clone(unsigned long 
  * do not have enough call-clobbered registers to hold all
  * the information you need.
  */
-asmlinkage long sys_vfork(struct pt_regs regs)
+asmlinkage long sys_vfork(struct pt_regs *regs)
 {
-	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0);
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->rsp, regs, 0);
 }
 
 /*
diff -rupN linux-2.4.31/arch/x86_64/kernel/signal.c linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/kernel/signal.c
--- linux-2.4.31/arch/x86_64/kernel/signal.c	2005-01-19 18:00:53.000000000 +0100
+++ linux-2.4.31.gcc4-ptregscall-changes/arch/x86_64/kernel/signal.c	2005-06-12 17:55:52.000000000 +0200
@@ -82,7 +82,7 @@ int copy_siginfo_to_user(siginfo_t *to, 
 }
 
 asmlinkage long
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs regs)
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs)
 {
 	sigset_t saveset, newset;
 
@@ -101,21 +101,21 @@ sys_rt_sigsuspend(sigset_t *unewset, siz
 	spin_unlock_irq(&current->sigmask_lock);
 #if DEBUG_SIG
 	printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n",
-		saveset, newset, &regs, regs.rip);
+		saveset, newset, regs, regs->rip);
 #endif 
-	regs.rax = -EINTR;
+	regs->rax = -EINTR;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(&regs, &saveset))
+		if (do_signal(regs, &saveset))
 			return -EINTR;
 	}
 }
 
 asmlinkage long
-sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs regs)
+sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs)
 {
-	return do_sigaltstack(uss, uoss, regs.rsp);
+	return do_sigaltstack(uss, uoss, regs->rsp);
 }
 
 
@@ -180,9 +180,9 @@ restore_sigcontext(struct pt_regs *regs,
 }
 #undef COPY
 
-asmlinkage long sys_rt_sigreturn(struct pt_regs regs)
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
 {
-	struct rt_sigframe *frame = (struct rt_sigframe *)(regs.rsp - 8);
+	struct rt_sigframe *frame = (struct rt_sigframe *)(regs->rsp - 8);
 	sigset_t set;
 	stack_t st;
 	long eax;
@@ -198,23 +198,23 @@ asmlinkage long sys_rt_sigreturn(struct 
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 	
-	if (restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax))
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax))
 		goto badframe;
 
 #if DEBUG_SIG
-	printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs.rip,regs.rsp,frame,eax);
+	printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs->rip,regs->rsp,frame,eax);
 #endif
 
 	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
 		goto badframe;
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
-	do_sigaltstack(&st, NULL, regs.rsp);
+	do_sigaltstack(&st, NULL, regs->rsp);
 
 	return eax;
 
 badframe:
-	signal_fault(&regs, frame, "rt_sigreturn"); 
+	signal_fault(regs, frame, "rt_sigreturn"); 
 	return 0;
 }	
 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux