[3.16.y-ckt stable] Patch "x86/fpu: Fix 32-bit signal frame handling" has been added to staging queue

Luis Henriques luis.henriques at canonical.com
Mon Jan 4 17:29:49 UTC 2016


This is a note to let you know that I have just added a patch titled

    x86/fpu: Fix 32-bit signal frame handling

to the linux-3.16.y-queue branch of the 3.16.y-ckt extended stable tree 
which can be found at:

    http://kernel.ubuntu.com/git/ubuntu/linux.git/log/?h=linux-3.16.y-queue

This patch is scheduled to be released in version 3.16.7-ckt22.

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.16.y-ckt tree, see
https://wiki.ubuntu.com/Kernel/Dev/ExtendedStable

Thanks.
-Luis

------

>From 09a752053647474c90b9c0b1472030cd87c13ced Mon Sep 17 00:00:00 2001
From: Dave Hansen <dave.hansen at linux.intel.com>
Date: Tue, 10 Nov 2015 16:23:54 -0800
Subject: x86/fpu: Fix 32-bit signal frame handling

commit ab6b52947545a5355154f64f449f97af9d05845f upstream.

(This should have gone to LKML originally. Sorry for the extra
 noise, folks on the cc.)

Background:

Signal frames on x86 have two formats:

  1. For 32-bit executables (whether on a real 32-bit kernel or
     under 32-bit emulation on a 64-bit kernel) we have a
    'fpregset_t' that includes the "FSAVE" registers.

  2. For 64-bit executables (on 64-bit kernels obviously), the
     'fpregset_t' is smaller and does not contain the "FSAVE"
     state.

When creating the signal frame, we have to be aware of whether
we are running a 32 or 64-bit executable so we create the
correct format signal frame.

Problem:

save_xstate_epilog() uses 'fx_sw_reserved_ia32' whenever it is
called for a 32-bit executable.  This is for real 32-bit and
ia32 emulation.

But, fpu__init_prepare_fx_sw_frame() only initializes
'fx_sw_reserved_ia32' when emulation is enabled, *NOT* for real
32-bit kernels.

This leads to really wierd situations where 32-bit programs
lose their extended state when returning from a signal handler.
The kernel copies the uninitialized (zero) 'fx_sw_reserved_ia32'
out to userspace in save_xstate_epilog().  But when returning
from the signal, the kernel errors out in check_for_xstate()
when it does not see FP_XSTATE_MAGIC1 present (because it was
zeroed).  This leads to the FPU/XSAVE state being initialized.

For MPX, this leads to the most permissive state and means we
silently lose bounds violations.  I think this would also mean
that we could lose *ANY* FPU/SSE/AVX state.  I'm not sure why
no one has spotted this bug.

I believe this was broken by:

	72a671ced66d ("x86, fpu: Unify signal handling code paths for x86 and x86_64 kernels")

way back in 2012.

Signed-off-by: Dave Hansen <dave.hansen at linux.intel.com>
Cc: Andy Lutomirski <luto at amacapital.net>
Cc: Borislav Petkov <bp at alien8.de>
Cc: Brian Gerst <brgerst at gmail.com>
Cc: Denys Vlasenko <dvlasenk at redhat.com>
Cc: H. Peter Anvin <hpa at zytor.com>
Cc: Linus Torvalds <torvalds at linux-foundation.org>
Cc: Peter Zijlstra <peterz at infradead.org>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: dave at sr71.net
Cc: fenghua.yu at intel.com
Cc: yu-cheng.yu at intel.com
Link: http://lkml.kernel.org/r/20151111002354.A0799571@viggo.jf.intel.com
Signed-off-by: Ingo Molnar <mingo at kernel.org>
[ luis: backported to 3.16:
  - file and function rename:
    * arch/x86/kernel/fpu/signal.c -> arch/x86/kernel/xsave.c
    * fpu__init_prepare_fx_sw_frame() -> prepare_fx_sw_frame()
  - use 'i387_fsave_struct' instead of 'fregs_state'
  - adjusted context ]
Signed-off-by: Luis Henriques <luis.henriques at canonical.com>
---
 arch/x86/kernel/xsave.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index 7a09aca4b33a..beddb0344d52 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -429,20 +429,19 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
  */
 static void prepare_fx_sw_frame(void)
 {
-	int fsave_header_size = sizeof(struct i387_fsave_struct);
 	int size = xstate_size + FP_XSTATE_MAGIC2_SIZE;

-	if (config_enabled(CONFIG_X86_32))
-		size += fsave_header_size;
-
 	fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
 	fx_sw_reserved.extended_size = size;
 	fx_sw_reserved.xstate_bv = pcntxt_mask;
 	fx_sw_reserved.xstate_size = xstate_size;

-	if (config_enabled(CONFIG_IA32_EMULATION)) {
+	if (config_enabled(CONFIG_IA32_EMULATION) ||
+	    config_enabled(CONFIG_X86_32)) {
+		int fsave_header_size = sizeof(struct i387_fsave_struct);
+
 		fx_sw_reserved_ia32 = fx_sw_reserved;
-		fx_sw_reserved_ia32.extended_size += fsave_header_size;
+		fx_sw_reserved_ia32.extended_size = size + fsave_header_size;
 	}
 }





More information about the kernel-team mailing list