Commit 77245f1c authored by Borislav Petkov (AMD)'s avatar Borislav Petkov (AMD) Committed by Linus Torvalds

x86/CPU/AMD: Do not leak quotient data after a division by 0

Under certain circumstances, an integer division by 0 which faults, can
leave stale quotient data from a previous division operation on Zen1
microarchitectures.

Do a dummy division 0/1 before returning from the #DE exception handler
in order to avoid any leaks of potentially sensitive data.
Signed-off-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
Cc: <stable@kernel.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 13b93720
...@@ -495,4 +495,5 @@ ...@@ -495,4 +495,5 @@
/* BUG word 2 */ /* BUG word 2 */
#define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */ #define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */
#define X86_BUG_DIV0 X86_BUG(1*32 + 1) /* AMD DIV0 speculation bug */
#endif /* _ASM_X86_CPUFEATURES_H */ #endif /* _ASM_X86_CPUFEATURES_H */
...@@ -683,10 +683,12 @@ extern u16 get_llc_id(unsigned int cpu); ...@@ -683,10 +683,12 @@ extern u16 get_llc_id(unsigned int cpu);
extern u32 amd_get_nodes_per_socket(void); extern u32 amd_get_nodes_per_socket(void);
extern u32 amd_get_highest_perf(void); extern u32 amd_get_highest_perf(void);
extern bool cpu_has_ibpb_brtype_microcode(void); extern bool cpu_has_ibpb_brtype_microcode(void);
extern void amd_clear_divider(void);
#else #else
static inline u32 amd_get_nodes_per_socket(void) { return 0; } static inline u32 amd_get_nodes_per_socket(void) { return 0; }
static inline u32 amd_get_highest_perf(void) { return 0; } static inline u32 amd_get_highest_perf(void) { return 0; }
static inline bool cpu_has_ibpb_brtype_microcode(void) { return false; } static inline bool cpu_has_ibpb_brtype_microcode(void) { return false; }
static inline void amd_clear_divider(void) { }
#endif #endif
extern unsigned long arch_align_stack(unsigned long sp); extern unsigned long arch_align_stack(unsigned long sp);
......
...@@ -75,6 +75,10 @@ static const int amd_zenbleed[] = ...@@ -75,6 +75,10 @@ static const int amd_zenbleed[] =
AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf), AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf),
AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf)); AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf));
static const int amd_div0[] =
AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x00, 0x0, 0x2f, 0xf),
AMD_MODEL_RANGE(0x17, 0x50, 0x0, 0x5f, 0xf));
static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum) static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
{ {
int osvw_id = *erratum++; int osvw_id = *erratum++;
...@@ -1130,6 +1134,11 @@ static void init_amd(struct cpuinfo_x86 *c) ...@@ -1130,6 +1134,11 @@ static void init_amd(struct cpuinfo_x86 *c)
WARN_ON_ONCE(msr_set_bit(MSR_EFER, _EFER_AUTOIBRS)); WARN_ON_ONCE(msr_set_bit(MSR_EFER, _EFER_AUTOIBRS));
zenbleed_check(c); zenbleed_check(c);
if (cpu_has_amd_erratum(c, amd_div0)) {
pr_notice_once("AMD Zen1 DIV0 bug detected. Disable SMT for full protection.\n");
setup_force_cpu_bug(X86_BUG_DIV0);
}
} }
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
...@@ -1309,3 +1318,13 @@ bool cpu_has_ibpb_brtype_microcode(void) ...@@ -1309,3 +1318,13 @@ bool cpu_has_ibpb_brtype_microcode(void)
return false; return false;
} }
} }
/*
* Issue a DIV 0/1 insn to clear any division data from previous DIV
* operations.
*/
void noinstr amd_clear_divider(void)
{
asm volatile(ALTERNATIVE("", "div %2\n\t", X86_BUG_DIV0)
:: "a" (0), "d" (0), "r" (1));
}
...@@ -206,6 +206,8 @@ DEFINE_IDTENTRY(exc_divide_error) ...@@ -206,6 +206,8 @@ DEFINE_IDTENTRY(exc_divide_error)
{ {
do_error_trap(regs, 0, "divide error", X86_TRAP_DE, SIGFPE, do_error_trap(regs, 0, "divide error", X86_TRAP_DE, SIGFPE,
FPE_INTDIV, error_get_trap_addr(regs)); FPE_INTDIV, error_get_trap_addr(regs));
amd_clear_divider();
} }
DEFINE_IDTENTRY(exc_overflow) DEFINE_IDTENTRY(exc_overflow)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment