lkml.org 
[lkml]   [2020]   [Nov]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.9 292/391] powerpc: Fix undetected data corruption with P9N DD2.1 VSX CI load emulation
    Date
    From: Michael Neuling <mikey@neuling.org>

    commit 1da4a0272c5469169f78cd76cf175ff984f52f06 upstream.

    __get_user_atomic_128_aligned() stores to kaddr using stvx which is a
    VMX store instruction, hence kaddr must be 16 byte aligned otherwise
    the store won't occur as expected.

    Unfortunately when we call __get_user_atomic_128_aligned() in
    p9_hmi_special_emu(), the buffer we pass as kaddr (ie. vbuf) isn't
    guaranteed to be 16B aligned. This means that the write to vbuf in
    __get_user_atomic_128_aligned() has the bottom bits of the address
    truncated. This results in other local variables being
    overwritten. Also vbuf will not contain the correct data which results
    in the userspace emulation being wrong and hence undetected user data
    corruption.

    In the past we've been mostly lucky as vbuf has ended up aligned but
    this is fragile and isn't always true. CONFIG_STACKPROTECTOR in
    particular can change the stack arrangement enough that our luck runs
    out.

    This issue only occurs on POWER9 Nimbus <= DD2.1 bare metal.

    The fix is to align vbuf to a 16 byte boundary.

    Fixes: 5080332c2c89 ("powerpc/64s: Add workaround for P9 vector CI load issue")
    Cc: stable@vger.kernel.org # v4.15+
    Signed-off-by: Michael Neuling <mikey@neuling.org>
    Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
    Link: https://lore.kernel.org/r/20201013043741.743413-1-mikey@neuling.org
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    arch/powerpc/kernel/traps.c | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)

    --- a/arch/powerpc/kernel/traps.c
    +++ b/arch/powerpc/kernel/traps.c
    @@ -889,7 +889,7 @@ static void p9_hmi_special_emu(struct pt
    {
    unsigned int ra, rb, t, i, sel, instr, rc;
    const void __user *addr;
    - u8 vbuf[16], *vdst;
    + u8 vbuf[16] __aligned(16), *vdst;
    unsigned long ea, msr, msr_mask;
    bool swap;


    \
     
     \ /
      Last update: 2020-11-03 22:51    [W:4.167 / U:0.096 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site