lkml.org 
[lkml]   [2015]   [Aug]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.12 45/82] sparc64: Fix userspace FPU register corruptions.
    Date
    From: "David S. Miller" <davem@davemloft.net>

    3.12-stable review patch. If anyone has any objections, please let me know.

    ===============

    [ Upstream commit 44922150d87cef616fd183220d43d8fde4d41390 ]

    If we have a series of events from userpsace, with %fprs=FPRS_FEF,
    like follows:

    ETRAP
    ETRAP
    VIS_ENTRY(fprs=0x4)
    VIS_EXIT
    RTRAP (kernel FPU restore with fpu_saved=0x4)
    RTRAP

    We will not restore the user registers that were clobbered by the FPU
    using kernel code in the inner-most trap.

    Traps allocate FPU save slots in the thread struct, and FPU using
    sequences save the "dirty" FPU registers only.

    This works at the initial trap level because all of the registers
    get recorded into the top-level FPU save area, and we'll return
    to userspace with the FPU disabled so that any FPU use by the user
    will take an FPU disabled trap wherein we'll load the registers
    back up properly.

    But this is not how trap returns from kernel to kernel operate.

    The simplest fix for this bug is to always save all FPU register state
    for anything other than the top-most FPU save area.

    Getting rid of the optimized inner-slot FPU saving code ends up
    making VISEntryHalf degenerate into plain VISEntry.

    Longer term we need to do something smarter to reinstate the partial
    save optimizations. Perhaps the fundament error is having trap entry
    and exit allocate FPU save slots and restore register state. Instead,
    the VISEntry et al. calls should be doing that work.

    This bug is about two decades old.

    Reported-by: James Y Knight <jyknight@google.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Jiri Slaby <jslaby@suse.cz>
    ---
    arch/sparc/include/asm/visasm.h | 16 +++-------
    arch/sparc/lib/NG4memcpy.S | 5 ++-
    arch/sparc/lib/VISsave.S | 67 ++---------------------------------------
    arch/sparc/lib/ksyms.c | 4 ---
    4 files changed, 11 insertions(+), 81 deletions(-)

    diff --git a/arch/sparc/include/asm/visasm.h b/arch/sparc/include/asm/visasm.h
    index 11fdf0ef50bb..50d6f16a1513 100644
    --- a/arch/sparc/include/asm/visasm.h
    +++ b/arch/sparc/include/asm/visasm.h
    @@ -28,16 +28,10 @@
    * Must preserve %o5 between VISEntryHalf and VISExitHalf */

    #define VISEntryHalf \
    - rd %fprs, %o5; \
    - andcc %o5, FPRS_FEF, %g0; \
    - be,pt %icc, 297f; \
    - sethi %hi(298f), %g7; \
    - sethi %hi(VISenterhalf), %g1; \
    - jmpl %g1 + %lo(VISenterhalf), %g0; \
    - or %g7, %lo(298f), %g7; \
    - clr %o5; \
    -297: wr %o5, FPRS_FEF, %fprs; \
    -298:
    + VISEntry
    +
    +#define VISExitHalf \
    + VISExit

    #define VISEntryHalfFast(fail_label) \
    rd %fprs, %o5; \
    @@ -47,7 +41,7 @@
    ba,a,pt %xcc, fail_label; \
    297: wr %o5, FPRS_FEF, %fprs;

    -#define VISExitHalf \
    +#define VISExitHalfFast \
    wr %o5, 0, %fprs;

    #ifndef __ASSEMBLY__
    diff --git a/arch/sparc/lib/NG4memcpy.S b/arch/sparc/lib/NG4memcpy.S
    index 140527a20e7d..83aeeb1dffdb 100644
    --- a/arch/sparc/lib/NG4memcpy.S
    +++ b/arch/sparc/lib/NG4memcpy.S
    @@ -240,8 +240,11 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
    add %o0, 0x40, %o0
    bne,pt %icc, 1b
    LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
    +#ifdef NON_USER_COPY
    + VISExitHalfFast
    +#else
    VISExitHalf
    -
    +#endif
    brz,pn %o2, .Lexit
    cmp %o2, 19
    ble,pn %icc, .Lsmall_unaligned
    diff --git a/arch/sparc/lib/VISsave.S b/arch/sparc/lib/VISsave.S
    index b320ae9e2e2e..a063d84336d6 100644
    --- a/arch/sparc/lib/VISsave.S
    +++ b/arch/sparc/lib/VISsave.S
    @@ -44,9 +44,8 @@ vis1: ldub [%g6 + TI_FPSAVED], %g3

    stx %g3, [%g6 + TI_GSR]
    2: add %g6, %g1, %g3
    - cmp %o5, FPRS_DU
    - be,pn %icc, 6f
    - sll %g1, 3, %g1
    + mov FPRS_DU | FPRS_DL | FPRS_FEF, %o5
    + sll %g1, 3, %g1
    stb %o5, [%g3 + TI_FPSAVED]
    rd %gsr, %g2
    add %g6, %g1, %g3
    @@ -80,65 +79,3 @@ vis1: ldub [%g6 + TI_FPSAVED], %g3
    .align 32
    80: jmpl %g7 + %g0, %g0
    nop
    -
    -6: ldub [%g3 + TI_FPSAVED], %o5
    - or %o5, FPRS_DU, %o5
    - add %g6, TI_FPREGS+0x80, %g2
    - stb %o5, [%g3 + TI_FPSAVED]
    -
    - sll %g1, 5, %g1
    - add %g6, TI_FPREGS+0xc0, %g3
    - wr %g0, FPRS_FEF, %fprs
    - membar #Sync
    - stda %f32, [%g2 + %g1] ASI_BLK_P
    - stda %f48, [%g3 + %g1] ASI_BLK_P
    - membar #Sync
    - ba,pt %xcc, 80f
    - nop
    -
    - .align 32
    -80: jmpl %g7 + %g0, %g0
    - nop
    -
    - .align 32
    -VISenterhalf:
    - ldub [%g6 + TI_FPDEPTH], %g1
    - brnz,a,pn %g1, 1f
    - cmp %g1, 1
    - stb %g0, [%g6 + TI_FPSAVED]
    - stx %fsr, [%g6 + TI_XFSR]
    - clr %o5
    - jmpl %g7 + %g0, %g0
    - wr %g0, FPRS_FEF, %fprs
    -
    -1: bne,pn %icc, 2f
    - srl %g1, 1, %g1
    - ba,pt %xcc, vis1
    - sub %g7, 8, %g7
    -2: addcc %g6, %g1, %g3
    - sll %g1, 3, %g1
    - andn %o5, FPRS_DU, %g2
    - stb %g2, [%g3 + TI_FPSAVED]
    -
    - rd %gsr, %g2
    - add %g6, %g1, %g3
    - stx %g2, [%g3 + TI_GSR]
    - add %g6, %g1, %g2
    - stx %fsr, [%g2 + TI_XFSR]
    - sll %g1, 5, %g1
    -3: andcc %o5, FPRS_DL, %g0
    - be,pn %icc, 4f
    - add %g6, TI_FPREGS, %g2
    -
    - add %g6, TI_FPREGS+0x40, %g3
    - membar #Sync
    - stda %f0, [%g2 + %g1] ASI_BLK_P
    - stda %f16, [%g3 + %g1] ASI_BLK_P
    - membar #Sync
    - ba,pt %xcc, 4f
    - nop
    -
    - .align 32
    -4: and %o5, FPRS_DU, %o5
    - jmpl %g7 + %g0, %g0
    - wr %o5, FPRS_FEF, %fprs
    diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c
    index 323335b9cd2b..ac094de28ccf 100644
    --- a/arch/sparc/lib/ksyms.c
    +++ b/arch/sparc/lib/ksyms.c
    @@ -126,10 +126,6 @@ EXPORT_SYMBOL(copy_user_page);
    void VISenter(void);
    EXPORT_SYMBOL(VISenter);

    -/* CRYPTO code needs this */
    -void VISenterhalf(void);
    -EXPORT_SYMBOL(VISenterhalf);
    -
    extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *);
    extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *,
    unsigned long *);
    --
    2.5.0


    \
     
     \ /
      Last update: 2015-08-24 11:21    [W:9.336 / U:0.064 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site