AI and data stack advisories

Severe, 6 weeks1496Projects326

1496 severe, 6 weeks · 326 projects

GoogleGHSA-9x5g-vmxf-4qj8

Linux Kernel: Bypassing Spectre-BTI User Space Mitigations

Google

CVE-2023-0045 · Published Feb 3, 2023 · updated Feb 7, 2023

Low
Fix: upgrade to e8377f0456fb6738a4668d4df16c13d7599925fd or later
GitHub advisory

Summary

When testing the success rate of Spectre-BTI attacks, we detected a strange pattern when using the kernel API as mitigation [[1](https://docs.kernel.org/userspace-api/spec_ctrl.html)]. Our tests revealed that the Linux kernel fails to correctly mitigate the attack leaving the process exposed for a short period of time after the syscall.

Further investigation showed that the kernel does not issue an IBPB immediately during the syscall. The ``ib_prctl_set` [[2](https://elixir.bootlin.com/linux/v5.15.56/source/arch/x86/kernel/cpu/bugs.c#L1467)] function updates the Thread Information Flags (TIFs) for the task and updates the SPEC_CTRL MSR on the function `__speculation_ctrl_update`` [[3]([https://elixir.bootlin.com/linux/v5.15.56/source/arch/x86/kernel/cpu/bugs.c#L1467])], but the IBPB is only issued on the next schedule, when the TIF bits are checked. This leaves the victim vulnerable to values already injected on the BTB, prior to the prctl syscall. The behavior is only corrected after a reschedule of the taks happens. Furthermore, the kernel entrance (due to the syscall itself), does not issue an IBPB in the default scenarios (i.e., when the kernel protects itself via retpoline or eIBRS).

Executing a prctl to mitigate spectre-BTI attacks using: `` prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_FORCE_DISABLE, 0, 0);` leads to the``...

Affected versions

PackageAffectedFixed in
Kernel
Product
< e8377f0456fb6738a4668d4df16c13d7599925fde8377f0456fb6738a4668d4df16c13d7599925fd
Details and references

### Summary When testing the success rate of Spectre-BTI attacks, we detected a strange pattern when using the kernel API as mitigation [[1](https://docs.kernel.org/userspace-api/spec_ctrl.html)]. Our tests revealed that the Linux kernel fails to correctly mitigate the attack leaving the process exposed for a short period of time after the syscall. Further investigation showed that the kernel does not issue an IBPB immediately during the syscall. The ```ib_prctl_set``` [[2](https://elixir.bootlin.com/linux/v5.15.56/source/arch/x86/kernel/cpu/bugs.c#L1467)] function updates the Thread Information Flags (TIFs) for the task and updates the SPEC_CTRL MSR on the function ```__speculation_ctrl_update``` [[3]([https://elixir.bootlin.com/linux/v5.15.56/source/arch/x86/kernel/cpu/bugs.c#L1467])], but the IBPB is only issued on the next schedule, when the TIF bits are checked. This leaves the victim vulnerable to values already injected on the BTB, prior to the prctl syscall. The behavior is only corrected after a reschedule of the taks happens. Furthermore, the kernel entrance (due to the syscall itself), does not issue an IBPB in the default scenarios (i.e., when the kernel protects itself via retpoline or eIBRS). Executing a prctl to mitigate spectre-BTI attacks using: ``` prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_FORCE_DISABLE, 0, 0);``` leads to the``` ib_prctl_set``` [[2](https://elixir.bootlin.com/linux/v5.15.56/source/arch/x86/kernel/cpu/bugs.c#L1467)] function on kernel 5.15. When the option SPEC_DISABLE is used the TIF bit for ```task_set_spec_ib_disable``` is set and ```task_update_spec_tif``` is called: ``` static int ib_prctl_set(struct task_struct *task, unsigned long ctrl) [...] case PR_SPEC_FORCE_DISABLE: /* * Indirect branch speculation is always allowed when * mitigation is force disabled. */ if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE && spectre_v2_user_stibp == SPECTRE_V2_USER_NONE) return -EPERM; if (!is_spec_ib_user_controlled()) return 0; task_set_spec_ib_disable(task); if (ctrl == PR_SPEC_FORCE_DISABLE) task_set_spec_ib_force_disable(task); task_update_spec_tif(task); break; ``` ``` ```task_set_spec_ib_disable``` calls ```set_tsk_thread_flag(tsk, TIF_SPEC_FORCE_UPDATE);``` and if the target task is the current process it calls ``` speculation_ctrl_update_current(); ``` ``` static void task_update_spec_tif(struct task_struct *tsk) { /* Force the update of the real TIF bits */ set_tsk_thread_flag(tsk, TIF_SPEC_FORCE_UPDATE); /* * Immediately update the speculation control MSRs for the current * task, but for a non-current task delay setting the CPU * mitigation until it is scheduled next. * * This can only happen for SECCOMP mitigation. For PRCTL it's * always the current task. */ if (tsk == current) speculation_ctrl_update_current(); } ``` The ``` speculation_ctrl_update_current``` after the ```speculation_ctrl_update``` wrapper executes ```__speculation_ctrl_update``` with ```tifp = ~tifp``` , here the update of the wrmsr for setting STIBP is executed but no IBPB is issued : ``` static __always_inline void __speculation_ctrl_update(unsigned long tifp, unsigned long tifn) { unsigned long tif_diff = tifp ^ tifn; u64 msr = x86_spec_ctrl_base; bool updmsr = false; lockdep_assert_irqs_disabled(); /* Handle change of TIF_SSBD depending on the mitigation method. */ if (static_cpu_has(X86_FEATURE_VIRT_SSBD)) { if (tif_diff & _TIF_SSBD) amd_set_ssb_virt_state(tifn); } else if (static_cpu_has(X86_FEATURE_LS_CFG_SSBD)) { if (tif_diff & _TIF_SSBD) amd_set_core_ssb_state(tifn); } else if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) || static_cpu_has(X86_FEATURE_AMD_SSBD)) { updmsr |= !!(tif_diff & _TIF_SSBD); msr |= ssbd_tif_to_spec_ctrl(tifn); } /* Only evaluate TIF_SPEC_IB if conditional STIBP is enabled. */ if (IS_ENABLED(CONFIG_SMP) && static_branch_unlikely(&switch_to_cond_stibp)) {

Severity from
GitHub (reviewed advisory)

More Google advisories

All Google