Skip to content

Commit f2615bb

Browse files
bp3tk0vgregkh
authored andcommitted
x86/CPU/AMD: Do not leak quotient data after a division by 0
commit 77245f1 upstream. 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: Borislav Petkov (AMD) <bp@alien8.de> Cc: <stable@kernel.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 673cdde commit f2615bb

File tree

4 files changed

+24
-0
lines changed

4 files changed

+24
-0
lines changed

arch/x86/include/asm/cpufeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,4 +476,5 @@
476476

477477
/* BUG word 2 */
478478
#define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */
479+
#define X86_BUG_DIV0 X86_BUG(1*32 + 1) /* AMD DIV0 speculation bug */
479480
#endif /* _ASM_X86_CPUFEATURES_H */

arch/x86/include/asm/processor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,10 +801,12 @@ extern u16 get_llc_id(unsigned int cpu);
801801
extern u32 amd_get_nodes_per_socket(void);
802802
extern u32 amd_get_highest_perf(void);
803803
extern bool cpu_has_ibpb_brtype_microcode(void);
804+
extern void amd_clear_divider(void);
804805
#else
805806
static inline u32 amd_get_nodes_per_socket(void) { return 0; }
806807
static inline u32 amd_get_highest_perf(void) { return 0; }
807808
static inline bool cpu_has_ibpb_brtype_microcode(void) { return false; }
809+
static inline void amd_clear_divider(void) { }
808810
#endif
809811

810812
#define for_each_possible_hypervisor_cpuid_base(function) \

arch/x86/kernel/cpu/amd.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ static const int amd_zenbleed[] =
7575
AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf),
7676
AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf));
7777

78+
static const int amd_div0[] =
79+
AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x00, 0x0, 0x2f, 0xf),
80+
AMD_MODEL_RANGE(0x17, 0x50, 0x0, 0x5f, 0xf));
81+
7882
static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
7983
{
8084
int osvw_id = *erratum++;
@@ -1115,6 +1119,11 @@ static void init_amd(struct cpuinfo_x86 *c)
11151119
check_null_seg_clears_base(c);
11161120

11171121
zenbleed_check(c);
1122+
1123+
if (cpu_has_amd_erratum(c, amd_div0)) {
1124+
pr_notice_once("AMD Zen1 DIV0 bug detected. Disable SMT for full protection.\n");
1125+
setup_force_cpu_bug(X86_BUG_DIV0);
1126+
}
11181127
}
11191128

11201129
#ifdef CONFIG_X86_32
@@ -1275,3 +1284,13 @@ void amd_check_microcode(void)
12751284
{
12761285
on_each_cpu(zenbleed_check_cpu, NULL, 1);
12771286
}
1287+
1288+
/*
1289+
* Issue a DIV 0/1 insn to clear any division data from previous DIV
1290+
* operations.
1291+
*/
1292+
void noinstr amd_clear_divider(void)
1293+
{
1294+
asm volatile(ALTERNATIVE("", "div %2\n\t", X86_BUG_DIV0)
1295+
:: "a" (0), "d" (0), "r" (1));
1296+
}

arch/x86/kernel/traps.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ DEFINE_IDTENTRY(exc_divide_error)
206206
{
207207
do_error_trap(regs, 0, "divide error", X86_TRAP_DE, SIGFPE,
208208
FPE_INTDIV, error_get_trap_addr(regs));
209+
210+
amd_clear_divider();
209211
}
210212

211213
DEFINE_IDTENTRY(exc_overflow)

0 commit comments

Comments
 (0)