Skip to contentSkip to conversation

x86/signal: Remove pax argument from restore_sigcontext

PATCH In review Brian Gerst 3 participants 9 messages Apr 4, 2015 – Apr 7, 2015 x86

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 x86/signal: Remove pax argument from restore_sigcontext

The pax argument is unnecesary. Instead, store the RAX value directly in regs.

Cc Ingo Molnar <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Borislav Petkov <[email protected]>
---
 arch/x86/ia32/ia32_signal.c        | 17 ++++++-----------
 arch/x86/include/asm/sighandling.h |  4 +---
 arch/x86/kernel/signal.c           | 22 ++++++++--------------
 3 files changed, 15 insertions(+), 28 deletions(-)
arch/x86/ia32/ia32_signal.c +6 -11
index 1f5e2b0..c81d35e6 100644
@@ -161,8 +161,7 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 }
 
 static int ia32_restore_sigcontext(struct pt_regs *regs,
-				   struct sigcontext_ia32 __user *sc,
-				   unsigned int *pax)
+				   struct sigcontext_ia32 __user *sc)
 {
 	unsigned int tmpflags, err = 0;
 	void __user *buf;
@@ -184,7 +183,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
 		RELOAD_SEG(es);
 
 		COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
-		COPY(dx); COPY(cx); COPY(ip);
+		COPY(dx); COPY(cx); COPY(ip); COPY(ax);
 		/* Don't touch extended registers */
 
 		COPY_SEG_CPL3(cs);
@@ -197,8 +196,6 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
 
 		get_user_ex(tmp, &sc->fpstate);
 		buf = compat_ptr(tmp);
-
-		get_user_ex(*pax, &sc->ax);
 	} get_user_catch(err);
 
 	err |= restore_xstate_sig(buf, 1);
@@ -213,7 +210,6 @@ asmlinkage long sys32_sigreturn(void)
 	struct pt_regs *regs = current_pt_regs();
 	struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
 	sigset_t set;
-	unsigned int ax;
 
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
@@ -226,9 +222,9 @@ asmlinkage long sys32_sigreturn(void)
 
 	set_current_blocked(&set);
 
-	if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
+	if (ia32_restore_sigcontext(regs, &frame->sc))
 		goto badframe;
-	return ax;
+	return regs->ax;
 
 badframe:
 	signal_fault(regs, frame, "32bit sigreturn");
@@ -240,7 +236,6 @@ asmlinkage long sys32_rt_sigreturn(void)
 	struct pt_regs *regs = current_pt_regs();
 	struct rt_sigframe_ia32 __user *frame;
 	sigset_t set;
-	unsigned int ax;
 
 	frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
 
@@ -251,13 +246,13 @@ asmlinkage long sys32_rt_sigreturn(void)
 
 	set_current_blocked(&set);
 
-	if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
+	if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
 
 	if (compat_restore_altstack(&frame->uc.uc_stack))
 		goto badframe;
 
-	return ax;
+	return regs->ax;
 
 badframe:
 	signal_fault(regs, frame, "32bit rt sigreturn");
arch/x86/include/asm/sighandling.h +1 -3
index 7a95816..89db467 100644
@@ -13,9 +13,7 @@
 			 X86_EFLAGS_CF | X86_EFLAGS_RF)
 
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
-
-int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
-		       unsigned long *pax);
+int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc);
 int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
 		     struct pt_regs *regs, unsigned long mask);
 
arch/x86/kernel/signal.c +8 -14
index eaa2c5e..53cc408 100644
@@ -61,8 +61,7 @@
 	regs->seg = GET_SEG(seg) | 3;			\
 } while (0)
 
-int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
-		       unsigned long *pax)
+int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
 {
 	void __user *buf;
 	unsigned int tmpflags;
@@ -81,7 +80,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
 #endif /* CONFIG_X86_32 */
 
 		COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
-		COPY(dx); COPY(cx); COPY(ip);
+		COPY(dx); COPY(cx); COPY(ip); COPY(ax);
 
 #ifdef CONFIG_X86_64
 		COPY(r8);
@@ -102,8 +101,6 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
 		regs->orig_ax = -1;		/* disable syscall checks */
 
 		get_user_ex(buf, &sc->fpstate);
-
-		get_user_ex(*pax, &sc->ax);
 	} get_user_catch(err);
 
 	err |= restore_xstate_sig(buf, config_enabled(CONFIG_X86_32));
@@ -545,7 +542,6 @@ asmlinkage unsigned long sys_sigreturn(void)
 {
 	struct pt_regs *regs = current_pt_regs();
 	struct sigframe __user *frame;
-	unsigned long ax;
 	sigset_t set;
 
 	frame = (struct sigframe __user *)(regs->sp - 8);
@@ -559,9 +555,9 @@ asmlinkage unsigned long sys_sigreturn(void)
 
 	set_current_blocked(&set);
 
-	if (restore_sigcontext(regs, &frame->sc, &ax))
+	if (restore_sigcontext(regs, &frame->sc))
 		goto badframe;
-	return ax;
+	return regs->ax;
 
 badframe:
 	signal_fault(regs, frame, "sigreturn");
@@ -574,7 +570,6 @@ asmlinkage long sys_rt_sigreturn(void)
 {
 	struct pt_regs *regs = current_pt_regs();
 	struct rt_sigframe __user *frame;
-	unsigned long ax;
 	sigset_t set;
 
 	frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
@@ -585,13 +580,13 @@ asmlinkage long sys_rt_sigreturn(void)
 
 	set_current_blocked(&set);
 
-	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
 
 	if (restore_altstack(&frame->uc.uc_stack))
 		goto badframe;
 
-	return ax;
+	return regs->ax;
 
 badframe:
 	signal_fault(regs, frame, "rt_sigreturn");
@@ -786,7 +781,6 @@ asmlinkage long sys32_x32_rt_sigreturn(void)
 	struct pt_regs *regs = current_pt_regs();
 	struct rt_sigframe_x32 __user *frame;
 	sigset_t set;
-	unsigned long ax;
 
 	frame = (struct rt_sigframe_x32 __user *)(regs->sp - 8);
 
@@ -797,13 +791,13 @@ asmlinkage long sys32_x32_rt_sigreturn(void)
 
 	set_current_blocked(&set);
 
-	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
 
 	if (compat_restore_altstack(&frame->uc.uc_stack))
 		goto badframe;
 
-	return ax;
+	return regs->ax;
 
 badframe:
 	signal_fault(regs, frame, "x32 rt_sigreturn");
Signature · 1 line
2.1.0
#1 lore raw
Quoted 42 lines · Brian Gerst

The pax argument is unnecesary. Instead, store the RAX value directly in regs.

Cc Ingo Molnar <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Borislav Petkov <[email protected]>
---
 arch/x86/ia32/ia32_signal.c        | 17 ++++++-----------
 arch/x86/include/asm/sighandling.h |  4 +---
 arch/x86/kernel/signal.c           | 22 ++++++++--------------
 3 files changed, 15 insertions(+), 28 deletions(-)
arch/x86/ia32/ia32_signal.c +2 -3
index 1f5e2b0..c81d35e6 100644
@@ -161,8 +161,7 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 }
 
 static int ia32_restore_sigcontext(struct pt_regs *regs,
-				   struct sigcontext_ia32 __user *sc,
-				   unsigned int *pax)
+				   struct sigcontext_ia32 __user *sc)
 {
 	unsigned int tmpflags, err = 0;
 	void __user *buf;
@@ -184,7 +183,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
 		RELOAD_SEG(es);
 
 		COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
-		COPY(dx); COPY(cx); COPY(ip);
+		COPY(dx); COPY(cx); COPY(ip); COPY(ax);
 		/* Don't touch extended registers */
 
 		COPY_SEG_CPL3(cs);

arch/x86/ia32/ia32_signal.c static int ia32_restore_sigcontext(struct pt_regs *regs, · line 199

Quoted 6 lines
arch/x86/ia32/ia32_signal.c +0 -2
@@ -197,8 +196,6 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
 
 		get_user_ex(tmp, &sc->fpstate);
 		buf = compat_ptr(tmp);
-
-		get_user_ex(*pax, &sc->ax);
 	} get_user_catch(err);

Note that arch/x86/kernel/signal.c appears to have a similar pattern - and there it could be removed as well?

I'm wondering what the original reason for adding the extra handling of regs->ax was. Maybe something changed regs->ax - but I cannot find such code path anymore.

It would be nice to try to do a bit of Git archeology to figure out the origins of this complication - maybe it's something subtle - or it's something that has changed meanwhile.

Thanks,

Ingo

#2 lore raw
Quoted 46 lines · Ingo Molnar
Quoted 43 lines · Brian Gerst

The pax argument is unnecesary. Instead, store the RAX value directly in regs.

Cc Ingo Molnar <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Borislav Petkov <[email protected]>
---
 arch/x86/ia32/ia32_signal.c        | 17 ++++++-----------
 arch/x86/include/asm/sighandling.h |  4 +---
 arch/x86/kernel/signal.c           | 22 ++++++++--------------
 3 files changed, 15 insertions(+), 28 deletions(-)
arch/x86/ia32/ia32_signal.c +2 -3
index 1f5e2b0..c81d35e6 100644
@@ -161,8 +161,7 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 }
 
 static int ia32_restore_sigcontext(struct pt_regs *regs,
-                                struct sigcontext_ia32 __user *sc,
-                                unsigned int *pax)
+                                struct sigcontext_ia32 __user *sc)
 {
      unsigned int tmpflags, err = 0;
      void __user *buf;
@@ -184,7 +183,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
              RELOAD_SEG(es);
 
              COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
-             COPY(dx); COPY(cx); COPY(ip);
+             COPY(dx); COPY(cx); COPY(ip); COPY(ax);
              /* Don't touch extended registers */
 
              COPY_SEG_CPL3(cs);
@@ -197,8 +196,6 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
 
Quoted 8 lines

arch/x86/ia32/ia32_signal.c static int ia32_restore_sigcontext(struct pt_regs *regs, · line 199

Quoted 5 lines
arch/x86/ia32/ia32_signal.c +0 -2
              get_user_ex(tmp, &sc->fpstate);
              buf = compat_ptr(tmp);
-
-             get_user_ex(*pax, &sc->ax);
      } get_user_catch(err);

Note that arch/x86/kernel/signal.c appears to have a similar pattern - and there it could be removed as well?

I'm guessing you didn't read the whole patch, because I did change it.

Quoted 7 lines

I'm wondering what the original reason for adding the extra handling of regs->ax was. Maybe something changed regs->ax - but I cannot find such code path anymore.

It would be nice to try to do a bit of Git archeology to figure out the origins of this complication - maybe it's something subtle - or it's something that has changed meanwhile.

#3 lore raw
Quoted 56 lines · Brian Gerst
Quoted 46 lines · Ingo Molnar
Quoted 43 lines · Brian Gerst

The pax argument is unnecesary. Instead, store the RAX value directly in regs.

Cc Ingo Molnar <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Borislav Petkov <[email protected]>
---
 arch/x86/ia32/ia32_signal.c        | 17 ++++++-----------
 arch/x86/include/asm/sighandling.h |  4 +---
 arch/x86/kernel/signal.c           | 22 ++++++++--------------
 3 files changed, 15 insertions(+), 28 deletions(-)
arch/x86/ia32/ia32_signal.c +2 -3
index 1f5e2b0..c81d35e6 100644
@@ -161,8 +161,7 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 }
 
 static int ia32_restore_sigcontext(struct pt_regs *regs,
-                                struct sigcontext_ia32 __user *sc,
-                                unsigned int *pax)
+                                struct sigcontext_ia32 __user *sc)
 {
      unsigned int tmpflags, err = 0;
      void __user *buf;
@@ -184,7 +183,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
              RELOAD_SEG(es);
 
              COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
-             COPY(dx); COPY(cx); COPY(ip);
+             COPY(dx); COPY(cx); COPY(ip); COPY(ax);
              /* Don't touch extended registers */
 
              COPY_SEG_CPL3(cs);
@@ -197,8 +196,6 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
 
Quoted 8 lines

arch/x86/ia32/ia32_signal.c static int ia32_restore_sigcontext(struct pt_regs *regs, · line 199

Quoted 5 lines
arch/x86/ia32/ia32_signal.c +0 -2
              get_user_ex(tmp, &sc->fpstate);
              buf = compat_ptr(tmp);
-
-             get_user_ex(*pax, &sc->ax);
      } get_user_catch(err);

Note that arch/x86/kernel/signal.c appears to have a similar pattern - and there it could be removed as well?

Quoted 1 line

I'm guessing you didn't read the whole patch, because I did change it.

Yes :-/

Ingo

#4 lore raw
In reply to Ingo Molnar
Quoted 55 lines · Ingo Molnar
Quoted 42 lines · Brian Gerst

The pax argument is unnecesary. Instead, store the RAX value directly in regs.

Cc Ingo Molnar <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Borislav Petkov <[email protected]>
---
 arch/x86/ia32/ia32_signal.c        | 17 ++++++-----------
 arch/x86/include/asm/sighandling.h |  4 +---
 arch/x86/kernel/signal.c           | 22 ++++++++--------------
 3 files changed, 15 insertions(+), 28 deletions(-)
arch/x86/ia32/ia32_signal.c +2 -3
index 1f5e2b0..c81d35e6 100644
@@ -161,8 +161,7 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 }
 
 static int ia32_restore_sigcontext(struct pt_regs *regs,
-                                struct sigcontext_ia32 __user *sc,
-                                unsigned int *pax)
+                                struct sigcontext_ia32 __user *sc)
 {
      unsigned int tmpflags, err = 0;
      void __user *buf;
@@ -184,7 +183,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
              RELOAD_SEG(es);
 
              COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
-             COPY(dx); COPY(cx); COPY(ip);
+             COPY(dx); COPY(cx); COPY(ip); COPY(ax);
              /* Don't touch extended registers */
 
              COPY_SEG_CPL3(cs);

arch/x86/ia32/ia32_signal.c static int ia32_restore_sigcontext(struct pt_regs *regs, · line 199

Quoted 6 lines
arch/x86/ia32/ia32_signal.c +0 -2
@@ -197,8 +196,6 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
 
              get_user_ex(tmp, &sc->fpstate);
              buf = compat_ptr(tmp);
-
-             get_user_ex(*pax, &sc->ax);
      } get_user_catch(err);

Note that arch/x86/kernel/signal.c appears to have a similar pattern - and there it could be removed as well?

Quoted 7 lines

I'm wondering what the original reason for adding the extra handling of regs->ax was. Maybe something changed regs->ax - but I cannot find such code path anymore.

It would be nice to try to do a bit of Git archeology to figure out the origins of this complication - maybe it's something subtle - or it's something that has changed meanwhile.

It goes all the way back to 2.1.106pre1, when restore_sigcontext() was changed to return an error code instead of EAX directly.

https://git.kernel.org/cgit/linux/kernel/git/history/history.git/diff/arch/i386/kernel/signal.c?id=9a8f8b7ca3f319bd668298d447bdf32730e51174

--
Brian Gerst

#5 lore raw
Quoted 4 lines · Brian Gerst
Quoted 4 lines

I'm wondering what the original reason for adding the extra handling of regs->ax was. Maybe something changed regs->ax - but I cannot find such code path anymore.

Quoted 8 lines
Quoted 3 lines

It would be nice to try to do a bit of Git archeology to figure out the origins of this complication - maybe it's something subtle
- or it's something that has changed meanwhile.

It goes all the way back to 2.1.106pre1, when restore_sigcontext() was changed to return an error code instead of EAX directly.

https://git.kernel.org/cgit/linux/kernel/git/history/history.git/diff/arch/i386/kernel/signal.c?id=9a8f8b7ca3f319bd668298d447bdf32730e51174

Indeed: restore_sigcontext() used to return eax as a return value, without copying it into regs->ax.

Then in 2007 sigaltstack syscall support was added, where the return value of restore_sigcontext() was changed to carry the memory-copying failure code. But instead of putting 'ax' into regs->ax, it was carried in via a pointer and then returned, where the generic syscall return code copied it to regs->ax.

So there was never any deeper reason for this suboptimal pattern, it was simply never noticed after being introduced.

(Btw., the regs->ax we return will be copied back to regs->ax after the syscall straight away once again - but I guess this cannot be helped.)

I've added this information to the changelog.

Thanks,

Ingo

#6 lore raw
Quoted 14 lines · Ingo Molnar
Quoted 11 lines · Brian Gerst
Quoted 7 lines

I'm wondering what the original reason for adding the extra handling of regs->ax was. Maybe something changed regs->ax - but I cannot find such code path anymore.

It would be nice to try to do a bit of Git archeology to figure out the origins of this complication - maybe it's something subtle
- or it's something that has changed meanwhile.

It goes all the way back to 2.1.106pre1, when restore_sigcontext() was changed to return an error code instead of EAX directly.

Quoted 6 lines
Quoted 1 line

https://git.kernel.org/cgit/linux/kernel/git/history/history.git/diff/arch/i386/kernel/signal.c?id=9a8f8b7ca3f319bd668298d447bdf32730e51174

Indeed: restore_sigcontext() used to return eax as a return value, without copying it into regs->ax.

Then in 2007

Version 2.1.106 was released on Jun 13, 1998.

Quoted 6 lines

sigaltstack syscall support was added, where the return value of restore_sigcontext() was changed to carry the memory-copying failure code. But instead of putting 'ax' into regs->ax, it was carried in via a pointer and then returned, where the generic syscall return code copied it to regs->ax.

Quoted 6 lines

So there was never any deeper reason for this suboptimal pattern, it was simply never noticed after being introduced.

(Btw., the regs->ax we return will be copied back to regs->ax after the syscall straight away once again - but I guess this cannot be helped.)

The 64-bit stub could skip saving it back to regs. However 32-bit does not have a special stub so sys_rt_sigreturn() still needs to return regs->ax.

--
Brian Gerst

#7 lore raw
Quoted 15 lines · Brian Gerst
Quoted 14 lines · Ingo Molnar
Quoted 11 lines · Brian Gerst
Quoted 7 lines

I'm wondering what the original reason for adding the extra handling of regs->ax was. Maybe something changed regs->ax - but I cannot find such code path anymore.

It would be nice to try to do a bit of Git archeology to figure out the origins of this complication - maybe it's something subtle
- or it's something that has changed meanwhile.

It goes all the way back to 2.1.106pre1, when restore_sigcontext() was changed to return an error code instead of EAX directly.

Quoted 8 lines
Quoted 6 lines
Quoted 1 line

https://git.kernel.org/cgit/linux/kernel/git/history/history.git/diff/arch/i386/kernel/signal.c?id=9a8f8b7ca3f319bd668298d447bdf32730e51174

Indeed: restore_sigcontext() used to return eax as a return value, without copying it into regs->ax.

Then in 2007

Version 2.1.106 was released on Jun 13, 1998.

Sigh, the Git timestamp of the historic tree threw me off :-)

Quoted 6 lines
Quoted 6 lines

sigaltstack syscall support was added, where the return value of restore_sigcontext() was changed to carry the memory-copying failure code. But instead of putting 'ax' into regs->ax, it was carried in via a pointer and then returned, where the generic syscall return code copied it to regs->ax.

Quoted 8 lines
Quoted 6 lines

So there was never any deeper reason for this suboptimal pattern, it was simply never noticed after being introduced.

(Btw., the regs->ax we return will be copied back to regs->ax after the syscall straight away once again - but I guess this cannot be helped.)

The 64-bit stub could skip saving it back to regs.

Yeah, but at the cost of having a duplicated entry stub, right?

Thanks,

Ingo

#8 lore raw
In reply to Brian Gerst
x86/signal: Remove pax argument from restore_sigcontext
Commit-ID:  6a3713f001b3b53587e411ab0d3036ae9b0fb93b
Gitweb:     http://git.kernel.org/tip/6a3713f001b3b53587e411ab0d3036ae9b0fb93b
Author:     Brian Gerst <[email protected]>
AuthorDate: Sat, 4 Apr 2015 08:58:23 -0400
Committer:  Ingo Molnar <[email protected]>
CommitDate: Mon, 6 Apr 2015 09:06:39 +0200

x86/signal: Remove pax argument from restore_sigcontext

The 'pax' argument is unnecesary. Instead, store the RAX value directly in regs.

This pattern goes all the way back to 2.1.106pre1, when restore_sigcontext() was changed to return an error code instead of EAX directly:

https://git.kernel.org/cgit/linux/kernel/git/history/history.git/diff/arch/i386/kernel/signal.c?id=9a8f8b7ca3f319bd668298d447bdf32730e51174

In 2007 sigaltstack syscall support was added, where the return value of restore_sigcontext() was changed to carry the memory-copying failure code.

But instead of putting 'ax' into regs->ax directly, it was carried in via a pointer and then returned, where the generic syscall return code copied it to regs->ax.

So there was never any deeper reason for this suboptimal pattern, it was simply never noticed after being introduced.

Cc Andy Lutomirski <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Denys Vlasenko <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Thomas Gleixner <[email protected]>
---
 arch/x86/ia32/ia32_signal.c        | 17 ++++++-----------
 arch/x86/include/asm/sighandling.h |  4 +---
 arch/x86/kernel/signal.c           | 22 ++++++++--------------
 3 files changed, 15 insertions(+), 28 deletions(-)
arch/x86/ia32/ia32_signal.c +6 -11
index 1f5e2b0..c81d35e6 100644
@@ -161,8 +161,7 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 }
 
 static int ia32_restore_sigcontext(struct pt_regs *regs,
-				   struct sigcontext_ia32 __user *sc,
-				   unsigned int *pax)
+				   struct sigcontext_ia32 __user *sc)
 {
 	unsigned int tmpflags, err = 0;
 	void __user *buf;
@@ -184,7 +183,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
 		RELOAD_SEG(es);
 
 		COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
-		COPY(dx); COPY(cx); COPY(ip);
+		COPY(dx); COPY(cx); COPY(ip); COPY(ax);
 		/* Don't touch extended registers */
 
 		COPY_SEG_CPL3(cs);
@@ -197,8 +196,6 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
 
 		get_user_ex(tmp, &sc->fpstate);
 		buf = compat_ptr(tmp);
-
-		get_user_ex(*pax, &sc->ax);
 	} get_user_catch(err);
 
 	err |= restore_xstate_sig(buf, 1);
@@ -213,7 +210,6 @@ asmlinkage long sys32_sigreturn(void)
 	struct pt_regs *regs = current_pt_regs();
 	struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
 	sigset_t set;
-	unsigned int ax;
 
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
@@ -226,9 +222,9 @@ asmlinkage long sys32_sigreturn(void)
 
 	set_current_blocked(&set);
 
-	if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
+	if (ia32_restore_sigcontext(regs, &frame->sc))
 		goto badframe;
-	return ax;
+	return regs->ax;
 
 badframe:
 	signal_fault(regs, frame, "32bit sigreturn");
@@ -240,7 +236,6 @@ asmlinkage long sys32_rt_sigreturn(void)
 	struct pt_regs *regs = current_pt_regs();
 	struct rt_sigframe_ia32 __user *frame;
 	sigset_t set;
-	unsigned int ax;
 
 	frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
 
@@ -251,13 +246,13 @@ asmlinkage long sys32_rt_sigreturn(void)
 
 	set_current_blocked(&set);
 
-	if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
+	if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
 
 	if (compat_restore_altstack(&frame->uc.uc_stack))
 		goto badframe;
 
-	return ax;
+	return regs->ax;
 
 badframe:
 	signal_fault(regs, frame, "32bit rt sigreturn");
arch/x86/include/asm/sighandling.h +1 -3
index 7a95816..89db467 100644
@@ -13,9 +13,7 @@
 			 X86_EFLAGS_CF | X86_EFLAGS_RF)
 
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
-
-int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
-		       unsigned long *pax);
+int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc);
 int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
 		     struct pt_regs *regs, unsigned long mask);
 
arch/x86/kernel/signal.c +8 -14
index eaa2c5e..53cc408 100644
@@ -61,8 +61,7 @@
 	regs->seg = GET_SEG(seg) | 3;			\
 } while (0)
 
-int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
-		       unsigned long *pax)
+int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
 {
 	void __user *buf;
 	unsigned int tmpflags;
@@ -81,7 +80,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
 #endif /* CONFIG_X86_32 */
 
 		COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
-		COPY(dx); COPY(cx); COPY(ip);
+		COPY(dx); COPY(cx); COPY(ip); COPY(ax);
 
 #ifdef CONFIG_X86_64
 		COPY(r8);
@@ -102,8 +101,6 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
 		regs->orig_ax = -1;		/* disable syscall checks */
 
 		get_user_ex(buf, &sc->fpstate);
-
-		get_user_ex(*pax, &sc->ax);
 	} get_user_catch(err);
 
 	err |= restore_xstate_sig(buf, config_enabled(CONFIG_X86_32));
@@ -545,7 +542,6 @@ asmlinkage unsigned long sys_sigreturn(void)
 {
 	struct pt_regs *regs = current_pt_regs();
 	struct sigframe __user *frame;
-	unsigned long ax;
 	sigset_t set;
 
 	frame = (struct sigframe __user *)(regs->sp - 8);
@@ -559,9 +555,9 @@ asmlinkage unsigned long sys_sigreturn(void)
 
 	set_current_blocked(&set);
 
-	if (restore_sigcontext(regs, &frame->sc, &ax))
+	if (restore_sigcontext(regs, &frame->sc))
 		goto badframe;
-	return ax;
+	return regs->ax;
 
 badframe:
 	signal_fault(regs, frame, "sigreturn");
@@ -574,7 +570,6 @@ asmlinkage long sys_rt_sigreturn(void)
 {
 	struct pt_regs *regs = current_pt_regs();
 	struct rt_sigframe __user *frame;
-	unsigned long ax;
 	sigset_t set;
 
 	frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
@@ -585,13 +580,13 @@ asmlinkage long sys_rt_sigreturn(void)
 
 	set_current_blocked(&set);
 
-	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
 
 	if (restore_altstack(&frame->uc.uc_stack))
 		goto badframe;
 
-	return ax;
+	return regs->ax;
 
 badframe:
 	signal_fault(regs, frame, "rt_sigreturn");
@@ -786,7 +781,6 @@ asmlinkage long sys32_x32_rt_sigreturn(void)
 	struct pt_regs *regs = current_pt_regs();
 	struct rt_sigframe_x32 __user *frame;
 	sigset_t set;
-	unsigned long ax;
 
 	frame = (struct rt_sigframe_x32 __user *)(regs->sp - 8);
 
@@ -797,13 +791,13 @@ asmlinkage long sys32_x32_rt_sigreturn(void)
 
 	set_current_blocked(&set);
 
-	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
 
 	if (compat_restore_altstack(&frame->uc.uc_stack))
 		goto badframe;
 
-	return ax;
+	return regs->ax;
 
 badframe:
 	signal_fault(regs, frame, "x32 rt_sigreturn");