Skip to content

Commit

Permalink
x86/srso: Add a Speculative RAS Overflow mitigation
Browse files Browse the repository at this point in the history
Add a mitigation for the speculative return address stack overflow
vulnerability found on AMD processors.

The mitigation works by ensuring all RET instructions speculate to
a controlled location, similar to how speculation is controlled in the
retpoline sequence.  To accomplish this, the __x86_return_thunk forces
the CPU to mispredict every function return using a 'safe return'
sequence.

To ensure the safety of this mitigation, the kernel must ensure that the
safe return sequence is itself free from attacker interference.  In Zen3
and Zen4, this is accomplished by creating a BTB alias between the
untraining function srso_untrain_ret_alias() and the safe return
function srso_safe_ret_alias() which results in evicting a potentially
poisoned BTB entry and using that safe one for all function returns.

In older Zen1 and Zen2, this is accomplished using a reinterpretation
technique similar to Retbleed one: srso_untrain_ret() and
srso_safe_ret().

Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
  • Loading branch information
bp3tk0v committed Jul 27, 2023
1 parent 0e52740 commit fb3bd91
Show file tree
Hide file tree
Showing 16 changed files with 422 additions and 10 deletions.
1 change: 1 addition & 0 deletions Documentation/admin-guide/hw-vuln/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ are configurable at compile, boot or run time.
l1d_flush.rst
processor_mmio_stale_data.rst
cross-thread-rsb.rst
srso
133 changes: 133 additions & 0 deletions Documentation/admin-guide/hw-vuln/srso.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
.. SPDX-License-Identifier: GPL-2.0
Speculative Return Stack Overflow (SRSO)
========================================

This is a mitigation for the speculative return stack overflow (SRSO)
vulnerability found on AMD processors. The mechanism is by now the well
known scenario of poisoning CPU functional units - the Branch Target
Buffer (BTB) and Return Address Predictor (RAP) in this case - and then
tricking the elevated privilege domain (the kernel) into leaking
sensitive data.

AMD CPUs predict RET instructions using a Return Address Predictor (aka
Return Address Stack/Return Stack Buffer). In some cases, a non-architectural
CALL instruction (i.e., an instruction predicted to be a CALL but is
not actually a CALL) can create an entry in the RAP which may be used
to predict the target of a subsequent RET instruction.

The specific circumstances that lead to this varies by microarchitecture
but the concern is that an attacker can mis-train the CPU BTB to predict
non-architectural CALL instructions in kernel space and use this to
control the speculative target of a subsequent kernel RET, potentially
leading to information disclosure via a speculative side-channel.

The issue is tracked under CVE-2023-20569.

Affected processors
-------------------

AMD Zen, generations 1-4. That is, all families 0x17 and 0x19. Older
processors have not been investigated.

System information and options
------------------------------

First of all, it is required that the latest microcode be loaded for
mitigations to be effective.

The sysfs file showing SRSO mitigation status is:

/sys/devices/system/cpu/vulnerabilities/spec_rstack_overflow

The possible values in this file are:

- 'Not affected' The processor is not vulnerable

- 'Vulnerable: no microcode' The processor is vulnerable, no
microcode extending IBPB functionality
to address the vulnerability has been
applied.

- 'Mitigation: microcode' Extended IBPB functionality microcode
patch has been applied. It does not
address User->Kernel and Guest->Host
transitions protection but it does
address User->User and VM->VM attack
vectors.

(spec_rstack_overflow=microcode)

- 'Mitigation: safe RET' Software-only mitigation. It complements
the extended IBPB microcode patch
functionality by addressing User->Kernel
and Guest->Host transitions protection.

Selected by default or by
spec_rstack_overflow=safe-ret

- 'Mitigation: IBPB' Similar protection as "safe RET" above
but employs an IBPB barrier on privilege
domain crossings (User->Kernel,
Guest->Host).

(spec_rstack_overflow=ibpb)

- 'Mitigation: IBPB on VMEXIT' Mitigation addressing the cloud provider
scenario - the Guest->Host transitions
only.

(spec_rstack_overflow=ibpb-vmexit)

In order to exploit vulnerability, an attacker needs to:

- gain local access on the machine

- break kASLR

- find gadgets in the running kernel in order to use them in the exploit

- potentially create and pin an additional workload on the sibling
thread, depending on the microarchitecture (not necessary on fam 0x19)

- run the exploit

Considering the performance implications of each mitigation type, the
default one is 'Mitigation: safe RET' which should take care of most
attack vectors, including the local User->Kernel one.

As always, the user is advised to keep her/his system up-to-date by
applying software updates regularly.

The default setting will be reevaluated when needed and especially when
new attack vectors appear.

As one can surmise, 'Mitigation: safe RET' does come at the cost of some
performance depending on the workload. If one trusts her/his userspace
and does not want to suffer the performance impact, one can always
disable the mitigation with spec_rstack_overflow=off.

Similarly, 'Mitigation: IBPB' is another full mitigation type employing
an indrect branch prediction barrier after having applied the required
microcode patch for one's system. This mitigation comes also at
a performance cost.

Mitigation: safe RET
--------------------

The mitigation works by ensuring all RET instructions speculate to
a controlled location, similar to how speculation is controlled in the
retpoline sequence. To accomplish this, the __x86_return_thunk forces
the CPU to mispredict every function return using a 'safe return'
sequence.

To ensure the safety of this mitigation, the kernel must ensure that the
safe return sequence is itself free from attacker interference. In Zen3
and Zen4, this is accomplished by creating a BTB alias between the
untraining function srso_untrain_ret_alias() and the safe return
function srso_safe_ret_alias() which results in evicting a potentially
poisoned BTB entry and using that safe one for all function returns.

In older Zen1 and Zen2, this is accomplished using a reinterpretation
technique similar to Retbleed one: srso_untrain_ret() and
srso_safe_ret().
11 changes: 11 additions & 0 deletions Documentation/admin-guide/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5875,6 +5875,17 @@
Not specifying this option is equivalent to
spectre_v2_user=auto.

spec_rstack_overflow=
[X86] Control RAS overflow mitigation on AMD Zen CPUs

off - Disable mitigation
microcode - Enable microcode mitigation only
safe-ret - Enable sw-only safe RET mitigation (default)
ibpb - Enable mitigation by issuing IBPB on
kernel entry
ibpb-vmexit - Issue IBPB only on VMEXIT
(cloud-specific mitigation)

spec_store_bypass_disable=
[HW] Control Speculative Store Bypass (SSB) Disable mitigation
(Speculative Store Bypass vulnerability)
Expand Down
7 changes: 7 additions & 0 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2593,6 +2593,13 @@ config CPU_IBRS_ENTRY
This mitigates both spectre_v2 and retbleed at great cost to
performance.

config CPU_SRSO
bool "Mitigate speculative RAS overflow on AMD"
depends on CPU_SUP_AMD && X86_64 && RETHUNK
default y
help
Enable the SRSO mitigation needed on AMD Zen1-4 machines.

config SLS
bool "Mitigate Straight-Line-Speculation"
depends on CC_HAS_SLS && X86_64
Expand Down
5 changes: 5 additions & 0 deletions arch/x86/include/asm/cpufeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,9 @@
#define X86_FEATURE_SMBA (11*32+21) /* "" Slow Memory Bandwidth Allocation */
#define X86_FEATURE_BMEC (11*32+22) /* "" Bandwidth Monitoring Event Configuration */

#define X86_FEATURE_SRSO (11*32+24) /* "" AMD BTB untrain RETs */
#define X86_FEATURE_SRSO_ALIAS (11*32+25) /* "" AMD BTB untrain RETs through aliasing */

/* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
#define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */
#define X86_FEATURE_AVX512_BF16 (12*32+ 5) /* AVX512 BFLOAT16 instructions */
Expand Down Expand Up @@ -484,4 +487,6 @@
#define X86_BUG_EIBRS_PBRSB X86_BUG(28) /* EIBRS is vulnerable to Post Barrier RSB Predictions */
#define X86_BUG_SMT_RSB X86_BUG(29) /* CPU is vulnerable to Cross-Thread Return Address Predictions */

/* BUG word 2 */
#define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */
#endif /* _ASM_X86_CPUFEATURES_H */
15 changes: 14 additions & 1 deletion arch/x86/include/asm/nospec-branch.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@
* eventually turn into it's own annotation.
*/
.macro VALIDATE_UNRET_END
#if defined(CONFIG_NOINSTR_VALIDATION) && defined(CONFIG_CPU_UNRET_ENTRY)
#if defined(CONFIG_NOINSTR_VALIDATION) && \
(defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_SRSO))
ANNOTATE_RETPOLINE_SAFE
nop
#endif
Expand Down Expand Up @@ -296,6 +297,11 @@
"call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \
__stringify(RESET_CALL_DEPTH), X86_FEATURE_CALL_DEPTH
#endif

#ifdef CONFIG_CPU_SRSO
ALTERNATIVE_2 "", "call srso_untrain_ret", X86_FEATURE_SRSO, \
"call srso_untrain_ret_alias", X86_FEATURE_SRSO_ALIAS
#endif
.endm

.macro UNTRAIN_RET_FROM_CALL
Expand All @@ -307,6 +313,11 @@
"call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \
__stringify(RESET_CALL_DEPTH_FROM_CALL), X86_FEATURE_CALL_DEPTH
#endif

#ifdef CONFIG_CPU_SRSO
ALTERNATIVE_2 "", "call srso_untrain_ret", X86_FEATURE_SRSO, \
"call srso_untrain_ret_alias", X86_FEATURE_SRSO_ALIAS
#endif
.endm


Expand All @@ -332,6 +343,8 @@ extern retpoline_thunk_t __x86_indirect_jump_thunk_array[];

extern void __x86_return_thunk(void);
extern void zen_untrain_ret(void);
extern void srso_untrain_ret(void);
extern void srso_untrain_ret_alias(void);
extern void entry_ibpb(void);

#ifdef CONFIG_CALL_THUNKS
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -682,9 +682,11 @@ extern u16 get_llc_id(unsigned int cpu);
#ifdef CONFIG_CPU_SUP_AMD
extern u32 amd_get_nodes_per_socket(void);
extern u32 amd_get_highest_perf(void);
extern bool cpu_has_ibpb_brtype_microcode(void);
#else
static inline u32 amd_get_nodes_per_socket(void) { return 0; }
static inline u32 amd_get_highest_perf(void) { return 0; }
static inline bool cpu_has_ibpb_brtype_microcode(void) { return false; }
#endif

extern unsigned long arch_align_stack(unsigned long sp);
Expand Down
4 changes: 3 additions & 1 deletion arch/x86/kernel/alternative.c
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,9 @@ static int patch_return(void *addr, struct insn *insn, u8 *bytes)
int i = 0;

/* Patch the custom return thunks... */
if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) {
if (cpu_feature_enabled(X86_FEATURE_RETHUNK) ||
cpu_feature_enabled(X86_FEATURE_SRSO) ||
cpu_feature_enabled(X86_FEATURE_SRSO_ALIAS)) {
i = JMP32_INSN_SIZE;
__text_gen_insn(bytes, JMP32_INSN_OPCODE, addr, x86_return_thunk, i);
} else {
Expand Down
14 changes: 14 additions & 0 deletions arch/x86/kernel/cpu/amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1235,3 +1235,17 @@ u32 amd_get_highest_perf(void)
return 255;
}
EXPORT_SYMBOL_GPL(amd_get_highest_perf);

bool cpu_has_ibpb_brtype_microcode(void)
{
u8 fam = boot_cpu_data.x86;

if (fam == 0x17) {
/* Zen1/2 IBPB flushes branch type predictions too. */
return boot_cpu_has(X86_FEATURE_AMD_IBPB);
} else if (fam == 0x19) {
return false;
}

return false;
}
Loading

0 comments on commit fb3bd91

Please sign in to comment.