Linux Kernel: Bypassing Spectre-BTI User Space Mitigations
LowCVE-2023-0045 · Published Feb 3, 2023 · updated Feb 7, 2023
### 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...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| Kernel Product | < e8377f0456fb6738a4668d4df16c13d7599925fd | e8377f0456fb6738a4668d4df16c13d7599925fd |
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| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| Apr 122023 | Linux Kernel: Spectre v2 SMT mitigations problem | Medium | 6.3 |
| Feb 212023 | CISCO: ClamAV Heap Buffer Overflow | High | No fix yet |
| Jan 302023 | Amazon: RDS SQL Server | Medium | No fix yet |
| Jan 172023 | Unsandboxed Password Manager | High | No fix yet |
| Nov 292022 | Linux Kernel: Infoleak in Bluetooth L2CAP Handling | Medium | No fix yet |
| Nov 292022 | Linux Kernel: UAF in Bluetooth L2CAP Handshake | Medium | No fix yet |