Fixing a public but almost undocumented speculative execution vulnerability that is specific to aarch64. Even though ERET always causes a jump to another address, aarch64 CPUs speculatively execute following instructions as if the ERET instruction was not a jump instruction. The speculative execution does not cross privilege-levels (to the jump target as one would expect), but it continues on the kernel privilege level as if the ERET instruction did not change the control flow - thus execution anything that is accidentally linked after the ERET instruction. Later, the results of this speculative execution are always architecturally discarded, however they can leak data using microarchitectural side channels. This speculative execution is very reliable (seems to be unconditional) and it manages to complete even relatively performance-heavy operations (e.g. multiple dependent fetches from uncached memory). It was quietly fixed in Linux by this patch: https://github.com/torvalds/linux/commit/679db70801da9fda91d26caf13bf5b5ccc74e8e8 And the misbehavior is demonstrated by this implementation: https://github.com/google/safeside/blob/master/demos/eret_hvc_smc_wrapper.cc https://github.com/google/safeside/blob/master/kernel_modules/kmod_eret_hvc_smc/eret_hvc_smc_module.c This is the patch - the attachments probably do not work properly: diff -u -r -N freebsdold/sys/arm64/arm64/exception.S freebsdnew/sys/arm64/arm64/exception.S --- freebsdold/sys/arm64/arm64/exception.S 2019-12-16 15:25:23.876924499 -0800 +++ freebsdnew/sys/arm64/arm64/exception.S 2019-12-16 15:22:21.811969062 -0800 @@ -176,6 +176,8 @@ bl do_el1h_sync restore_registers 1 eret + dsb sy + isb END(handle_el1h_sync) ENTRY(handle_el1h_irq) @@ -184,6 +186,8 @@ bl intr_irq_handler restore_registers 1 eret + dsb sy + isb END(handle_el1h_irq) ENTRY(handle_el0_sync) @@ -195,6 +199,8 @@ do_ast restore_registers 0 eret + dsb sy + isb END(handle_el0_sync) ENTRY(handle_el0_irq) @@ -204,6 +210,8 @@ do_ast restore_registers 0 eret + dsb sy + isb END(handle_el0_irq) ENTRY(handle_serror) diff -u -r -N freebsdold/sys/arm64/arm64/swtch.S freebsdnew/sys/arm64/arm64/swtch.S --- freebsdold/sys/arm64/arm64/swtch.S 2019-12-16 15:25:24.332926892 -0800 +++ freebsdnew/sys/arm64/arm64/swtch.S 2019-12-16 15:22:38.732057855 -0800 @@ -254,6 +254,8 @@ * will be set to the desired value anyway. */ eret + dsb sy + isb END(fork_trampoline)
*** Bug 242675 has been marked as a duplicate of this bug. ***
*** Bug 242674 has been marked as a duplicate of this bug. ***
Thank you for the report and patch PoC Anthony
Do you know which CPUs this affects?
It probably affects all aarch64 CPUs that support speculative execution. I concretely tested that on Cavium ThunderX2 T99 and on Cortex A-72 in Raspberry Pi 4.
Created attachment 210049 [details] Full report about the vulnerability.
A commit references this bug: Author: andrew Date: Thu Dec 19 08:52:17 UTC 2019 New revision: 355907 URL: https://svnweb.freebsd.org/changeset/base/355907 Log: Stop speculation past an eret instruction On arm64 the eret instruction is used to return from an exception handler. Some implementations may speculate past this instruction into the next function. As the user may control many registers in these functions add a synchronisation barrier sequence after the eret instruction to stop these CPUs from speculating out of the exception handler. PR: 242676 Submitted by: Anthony Steinhauser <asteinhauser@google.com> (previous version) MFC after: 1 week Changes: head/sys/arm64/arm64/exception.S head/sys/arm64/arm64/swtch.S head/sys/arm64/include/asm.h
Taking a stab at opening this up to the public now that a fix has been committed and the issue has been somewhat described anyways in the commit message, and the rest of the materials referenced by Anthony are already public. Re-assigned to andrew@ because secteam@ has no further action to take here while we don't do SA for arm64. Marking it as 'in progress' for andrew@ to close when he feels it's completed.
^Triage: Keep secteam CC'd for comms/coordination if and where required