lkml.org 
[lkml]   [2020]   [May]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 11/86] x86/apm: Dont access __preempt_count with zeroed fs
    Date
    From: Ville Syrjälä <ville.syrjala@linux.intel.com>

    commit 6f6060a5c9cc76fdbc22748264e6aa3779ec2427 upstream.

    APM_DO_POP_SEGS does not restore fs/gs which were zeroed by
    APM_DO_ZERO_SEGS. Trying to access __preempt_count with
    zeroed fs doesn't really work.

    Move the ibrs call outside the APM_DO_SAVE_SEGS/APM_DO_RESTORE_SEGS
    invocations so that fs is actually restored before calling
    preempt_enable().

    Fixes the following sort of oopses:
    [ 0.313581] general protection fault: 0000 [#1] PREEMPT SMP
    [ 0.313803] Modules linked in:
    [ 0.314040] CPU: 0 PID: 268 Comm: kapmd Not tainted 4.16.0-rc1-triton-bisect-00090-gdd84441a7971 #19
    [ 0.316161] EIP: __apm_bios_call_simple+0xc8/0x170
    [ 0.316161] EFLAGS: 00210016 CPU: 0
    [ 0.316161] EAX: 00000102 EBX: 00000000 ECX: 00000102 EDX: 00000000
    [ 0.316161] ESI: 0000530e EDI: dea95f64 EBP: dea95f18 ESP: dea95ef0
    [ 0.316161] DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068
    [ 0.316161] CR0: 80050033 CR2: 00000000 CR3: 015d3000 CR4: 000006d0
    [ 0.316161] Call Trace:
    [ 0.316161] ? cpumask_weight.constprop.15+0x20/0x20
    [ 0.316161] on_cpu0+0x44/0x70
    [ 0.316161] apm+0x54e/0x720
    [ 0.316161] ? __switch_to_asm+0x26/0x40
    [ 0.316161] ? __schedule+0x17d/0x590
    [ 0.316161] kthread+0xc0/0xf0
    [ 0.316161] ? proc_apm_show+0x150/0x150
    [ 0.316161] ? kthread_create_worker_on_cpu+0x20/0x20
    [ 0.316161] ret_from_fork+0x2e/0x38
    [ 0.316161] Code: da 8e c2 8e e2 8e ea 57 55 2e ff 1d e0 bb 5d b1 0f 92 c3 5d 5f 07 1f 89 47 0c 90 8d b4 26 00 00 00 00 90 8d b4 26 00 00 00 00 90 <64> ff 0d 84 16 5c b1 74 7f 8b 45 dc 8e e0 8b 45 d8 8e e8 8b 45
    [ 0.316161] EIP: __apm_bios_call_simple+0xc8/0x170 SS:ESP: 0068:dea95ef0
    [ 0.316161] ---[ end trace 656253db2deaa12c ]---

    Fixes: dd84441a7971 ("x86/speculation: Use IBRS if available before calling into firmware")
    Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Cc: stable@vger.kernel.org
    Cc: David Woodhouse <dwmw@amazon.co.uk>
    Cc: "H. Peter Anvin" <hpa@zytor.com>
    Cc: x86@kernel.org
    Cc: David Woodhouse <dwmw@amazon.co.uk>
    Cc: "H. Peter Anvin" <hpa@zytor.com>
    Link: https://lkml.kernel.org/r/20180709133534.5963-1-ville.syrjala@linux.intel.com
    Cc: Guenter Roeck <linux@roeck-us.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    arch/x86/include/asm/apm.h | 6 ------
    arch/x86/kernel/apm_32.c | 5 +++++
    2 files changed, 5 insertions(+), 6 deletions(-)

    --- a/arch/x86/include/asm/apm.h
    +++ b/arch/x86/include/asm/apm.h
    @@ -6,8 +6,6 @@
    #ifndef _ASM_X86_MACH_DEFAULT_APM_H
    #define _ASM_X86_MACH_DEFAULT_APM_H

    -#include <asm/nospec-branch.h>
    -
    #ifdef APM_ZERO_SEGS
    # define APM_DO_ZERO_SEGS \
    "pushl %%ds\n\t" \
    @@ -33,7 +31,6 @@ static inline void apm_bios_call_asm(u32
    * N.B. We do NOT need a cld after the BIOS call
    * because we always save and restore the flags.
    */
    - firmware_restrict_branch_speculation_start();
    __asm__ __volatile__(APM_DO_ZERO_SEGS
    "pushl %%edi\n\t"
    "pushl %%ebp\n\t"
    @@ -46,7 +43,6 @@ static inline void apm_bios_call_asm(u32
    "=S" (*esi)
    : "a" (func), "b" (ebx_in), "c" (ecx_in)
    : "memory", "cc");
    - firmware_restrict_branch_speculation_end();
    }

    static inline u8 apm_bios_call_simple_asm(u32 func, u32 ebx_in,
    @@ -59,7 +55,6 @@ static inline u8 apm_bios_call_simple_as
    * N.B. We do NOT need a cld after the BIOS call
    * because we always save and restore the flags.
    */
    - firmware_restrict_branch_speculation_start();
    __asm__ __volatile__(APM_DO_ZERO_SEGS
    "pushl %%edi\n\t"
    "pushl %%ebp\n\t"
    @@ -72,7 +67,6 @@ static inline u8 apm_bios_call_simple_as
    "=S" (si)
    : "a" (func), "b" (ebx_in), "c" (ecx_in)
    : "memory", "cc");
    - firmware_restrict_branch_speculation_end();
    return error;
    }

    --- a/arch/x86/kernel/apm_32.c
    +++ b/arch/x86/kernel/apm_32.c
    @@ -239,6 +239,7 @@
    #include <asm/olpc.h>
    #include <asm/paravirt.h>
    #include <asm/reboot.h>
    +#include <asm/nospec-branch.h>

    #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
    extern int (*console_blank_hook)(int);
    @@ -613,11 +614,13 @@ static long __apm_bios_call(void *_call)
    gdt[0x40 / 8] = bad_bios_desc;

    apm_irq_save(flags);
    + firmware_restrict_branch_speculation_start();
    APM_DO_SAVE_SEGS;
    apm_bios_call_asm(call->func, call->ebx, call->ecx,
    &call->eax, &call->ebx, &call->ecx, &call->edx,
    &call->esi);
    APM_DO_RESTORE_SEGS;
    + firmware_restrict_branch_speculation_end();
    apm_irq_restore(flags);
    gdt[0x40 / 8] = save_desc_40;
    put_cpu();
    @@ -689,10 +692,12 @@ static long __apm_bios_call_simple(void
    gdt[0x40 / 8] = bad_bios_desc;

    apm_irq_save(flags);
    + firmware_restrict_branch_speculation_start();
    APM_DO_SAVE_SEGS;
    error = apm_bios_call_simple_asm(call->func, call->ebx, call->ecx,
    &call->eax);
    APM_DO_RESTORE_SEGS;
    + firmware_restrict_branch_speculation_end();
    apm_irq_restore(flags);
    gdt[0x40 / 8] = save_desc_40;
    put_cpu();

    \
     
     \ /
      Last update: 2020-05-18 20:32    [W:2.348 / U:0.052 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site