Here's a revised diff to correct the handling on amd64 and i386 of the 
MXCSR register in frames that could be altered by users, so that a user 
can't trick the kernel into faulting by trying to load an invalid MXCSR 
value during the return to userspace.

Originally worked out by joshe@; this corrects the timing of the call to 
fpuinit() for the primary CPU on amd64 so that the saved mask value is 
initialized correctly.  It also uniformly uses 
__attribute__((aligned(16))) do get a buffer of the correct alignment.

I've been using this on amd64 for a while and have confirmed that a test 
program which previous crashed the box now continues just fine.  I'm away 
from my i386 test box so we could use confirmation from someone running an 
i386 that shows FXSR in the cpu0 flags list.

ok?


Philip Guenther

Index: sys/arch/amd64/amd64/cpu.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/cpu.c,v
retrieving revision 1.40
diff -u -p -r1.40 cpu.c
--- sys/arch/amd64/amd64/cpu.c  27 Nov 2010 13:03:04 -0000      1.40
+++ sys/arch/amd64/amd64/cpu.c  25 Dec 2010 19:38:48 -0000
@@ -365,6 +365,8 @@ cpu_attach(struct device *parent, struct
 void
 cpu_init(struct cpu_info *ci)
 {
+       fpuinit(ci);
+
        /* configure the CPU if needed */
        if (ci->cpu_setup != NULL)
                (*ci->cpu_setup)(ci);
@@ -509,7 +511,6 @@ cpu_hatch(void *v)
        cpu_init_idt();
        lapic_set_lvt();
        gdt_init_cpu(ci);
-       fpuinit(ci);
 
        lldt(0);
 
Index: sys/arch/amd64/amd64/fpu.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/fpu.c,v
retrieving revision 1.21
diff -u -p -r1.21 fpu.c
--- sys/arch/amd64/amd64/fpu.c  29 Sep 2010 15:11:31 -0000      1.21
+++ sys/arch/amd64/amd64/fpu.c  25 Dec 2010 19:38:48 -0000
@@ -95,6 +95,8 @@
 void fpudna(struct cpu_info *);
 static int x86fpflags_to_siginfo(u_int32_t);
 
+uint32_t       fpu_mxcsr_mask;
+
 /*
  * Init the FPU.
  */
@@ -103,6 +105,16 @@ fpuinit(struct cpu_info *ci)
 {
        lcr0(rcr0() & ~(CR0_EM|CR0_TS));
        fninit();
+       if (CPU_IS_PRIMARY(ci)) {
+               struct fxsave64 fx __attribute__((aligned(16)));
+
+               bzero(&fx, sizeof(fx));
+               fxsave(&fx);
+               if (fx.fx_mxcsr_mask)
+                       fpu_mxcsr_mask = fx.fx_mxcsr_mask;
+               else
+                       fpu_mxcsr_mask = __INITIAL_MXCSR_MASK__;
+       }
        lcr0(rcr0() | (CR0_TS));
 }
 
Index: sys/arch/amd64/amd64/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/machdep.c,v
retrieving revision 1.129
diff -u -p -r1.129 machdep.c
--- sys/arch/amd64/amd64/machdep.c      22 Nov 2010 21:07:16 -0000      1.129
+++ sys/arch/amd64/amd64/machdep.c      25 Dec 2010 19:38:49 -0000
@@ -658,9 +658,11 @@ sys_sigreturn(struct proc *p, void *v, r
                fpusave_proc(p, 0);
 
        if (ksc.sc_fpstate) {
-               if ((error = copyin(ksc.sc_fpstate,
-                   &p->p_addr->u_pcb.pcb_savefpu.fp_fxsave, sizeof (struct 
fxsave64))))
+               struct fxsave64 *fx = &p->p_addr->u_pcb.pcb_savefpu.fp_fxsave;
+
+               if ((error = copyin(ksc.sc_fpstate, fx, sizeof(*fx))))
                        return (error);
+               fx->fx_mxcsr &= fpu_mxcsr_mask;
                p->p_md.md_flags |= MDP_USEDFPU;
        }
 
Index: sys/arch/amd64/amd64/process_machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/process_machdep.c,v
retrieving revision 1.9
diff -u -p -r1.9 process_machdep.c
--- sys/arch/amd64/amd64/process_machdep.c      29 Sep 2010 15:11:31 -0000      
1.9
+++ sys/arch/amd64/amd64/process_machdep.c      25 Dec 2010 19:38:50 -0000
@@ -137,7 +137,7 @@ process_read_fpregs(struct proc *p, stru
                frame->fx_fsw = 0x0000;
                frame->fx_ftw = 0xff;
                frame->fx_mxcsr = __INITIAL_MXCSR__;
-               frame->fx_mxcsr_mask = __INITIAL_MXCSR_MASK__;
+               frame->fx_mxcsr_mask = fpu_mxcsr_mask;
                p->p_md.md_flags |= MDP_USEDFPU;
        }
 
@@ -198,6 +198,7 @@ process_write_fpregs(struct proc *p, str
        }
 
        memcpy(frame, &regs->fxstate, sizeof(*regs));
+       frame->fx_mxcsr &= fpu_mxcsr_mask;
        return (0);
 }
 
Index: sys/arch/amd64/include/fpu.h
===================================================================
RCS file: /cvs/src/sys/arch/amd64/include/fpu.h,v
retrieving revision 1.7
diff -u -p -r1.7 fpu.h
--- sys/arch/amd64/include/fpu.h        20 Nov 2010 20:11:17 -0000      1.7
+++ sys/arch/amd64/include/fpu.h        25 Dec 2010 19:38:50 -0000
@@ -49,6 +49,8 @@ struct savefpu {
 struct trapframe;
 struct cpu_info;
 
+extern uint32_t        fpu_mxcsr_mask;
+
 void fpuinit(struct cpu_info *);
 void fpudrop(void);
 void fpudiscard(struct proc *);
Index: sys/arch/i386/i386/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/machdep.c,v
retrieving revision 1.485
diff -u -p -r1.485 machdep.c
--- sys/arch/i386/i386/machdep.c        2 Oct 2010 23:31:34 -0000       1.485
+++ sys/arch/i386/i386/machdep.c        25 Dec 2010 19:38:52 -0000
@@ -2362,9 +2362,11 @@ sys_sigreturn(struct proc *p, void *v, r
                npxsave_proc(p, 0);
 
        if (context.sc_fpstate) {
-               if ((error = copyin(context.sc_fpstate,
-                   &p->p_addr->u_pcb.pcb_savefpu, sizeof (union savefpu))))
+               union savefpu *sfp = &p->p_addr->u_pcb.pcb_savefpu;
+               if ((error = copyin(context.sc_fpstate, sfp, sizeof(*sfp))))
                        return (error);
+               if (i386_use_fxsave)
+                       sfp->sv_xmm.sv_env.en_mxcsr &= fpu_mxcsr_mask;
                p->p_md.md_flags |= MDP_USEDFPU;
        }
 
Index: sys/arch/i386/i386/process_machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/process_machdep.c,v
retrieving revision 1.25
diff -u -p -r1.25 process_machdep.c
--- sys/arch/i386/i386/process_machdep.c        29 Sep 2010 15:11:31 -0000      
1.25
+++ sys/arch/i386/i386/process_machdep.c        25 Dec 2010 19:38:52 -0000
@@ -137,6 +137,7 @@ process_fninit_xmm(struct savexmm *sxmm)
        memset(sxmm, 0, sizeof(*sxmm));
        sxmm->sv_env.en_cw = __OpenBSD_NPXCW__;
        sxmm->sv_env.en_mxcsr = __INITIAL_MXCSR__;
+       sxmm->sv_env.en_mxcsr_mask = fpu_mxcsr_mask;
        sxmm->sv_env.en_sw = 0x0000;
        sxmm->sv_env.en_tw = 0x00;
 }
@@ -308,6 +309,7 @@ process_write_fpregs(struct proc *p, str
                /* XXX Yuck. */
                memcpy(&s87, regs, sizeof(*regs));
                process_s87_to_xmm(&s87, &frame->sv_xmm);
+               frame->sv_xmm.sv_env.en_mxcsr &= fpu_mxcsr_mask;
        } else
                memcpy(&frame->sv_87, regs, sizeof(*regs));
 
Index: sys/arch/i386/include/npx.h
===================================================================
RCS file: /cvs/src/sys/arch/i386/include/npx.h,v
retrieving revision 1.15
diff -u -p -r1.15 npx.h
--- sys/arch/i386/include/npx.h 29 Sep 2010 15:11:31 -0000      1.15
+++ sys/arch/i386/include/npx.h 25 Dec 2010 19:38:52 -0000
@@ -96,7 +96,7 @@ struct envxmm {
        uint16_t en_fos;        /* FPU Data pointer selector */
        uint16_t en_rsvd2;
        uint32_t en_mxcsr;      /* MXCSR Register State */
-       uint32_t en_rsvd3;
+       uint32_t en_mxcsr_mask; /* Mask for valid MXCSR bits (may be 0) */
 };
 
 /* FPU regsters in the extended save format. */
@@ -142,6 +142,7 @@ struct      emcsts {
  * Set Reference, pg. 3-369.
  */
 #define __INITIAL_MXCSR__       0x1f80
+#define __INITIAL_MXCSR_MASK__ 0xffbf
 
 /*
  * The standard control word from finit is 0x37F, giving:
@@ -157,6 +158,8 @@ void    process_s87_to_xmm(const struct 
 
 struct cpu_info;
 struct trapframe;
+
+extern unsigned int fpu_mxcsr_mask;
 
 void   npxinit(struct cpu_info *);
 void   npxtrap(struct trapframe *);
Index: sys/arch/i386/isa/npx.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/isa/npx.c,v
retrieving revision 1.53
diff -u -p -r1.53 npx.c
--- sys/arch/i386/isa/npx.c     29 Sep 2010 15:11:31 -0000      1.53
+++ sys/arch/i386/isa/npx.c     25 Dec 2010 19:38:52 -0000
@@ -54,6 +54,7 @@
 
 #include <machine/cpu.h>
 #include <machine/intr.h>
+#include <machine/lock.h>
 #include <machine/npx.h>
 #include <machine/pio.h>
 #include <machine/cpufunc.h>
@@ -97,6 +98,11 @@
 #define        clts()                  __asm("clts")
 #define        stts()                  lcr0(rcr0() | CR0_TS)
 
+/*
+ * The mxcsr_mask for this host, taken from fxsave() on the primary CPU
+ */
+unsigned int   fpu_mxcsr_mask;
+
 int npxintr(void *);
 static int npxprobe1(struct isa_attach_args *);
 static int x86fpflags_to_siginfo(u_int32_t);
@@ -350,6 +356,16 @@ npxinit(struct cpu_info *ci)
                i386_fpu_fdivbug = 1;
                printf("%s: WARNING: Pentium FDIV bug detected!\n",
                    ci->ci_dev.dv_xname);
+       }
+       if (CPU_IS_PRIMARY(ci) && i386_use_fxsave) {
+               struct savexmm xm __attribute__((aligned(16)));
+
+               bzero(&xm, sizeof(xm));
+               fxsave(&xm);
+               if (xm.sv_env.en_mxcsr_mask)
+                       fpu_mxcsr_mask = xm.sv_env.en_mxcsr_mask;
+               else
+                       fpu_mxcsr_mask = __INITIAL_MXCSR_MASK__;
        }
        lcr0(rcr0() | (CR0_TS));
 }

Reply via email to