Commit 35053cd
KVM: x86: Defer non-architectural deliver of exception payload to userspace read
commit d0ad1b0 upstream.
When attempting to play nice with userspace that hasn't enabled
KVM_CAP_EXCEPTION_PAYLOAD, defer KVM's non-architectural delivery of the
payload until userspace actually reads relevant vCPU state, and more
importantly, force delivery of the payload in *all* paths where userspace
saves relevant vCPU state, not just KVM_GET_VCPU_EVENTS.
Ignoring userspace save/restore for the moment, delivering the payload
before the exception is injected is wrong regardless of whether L1 or L2
is running. To make matters even more confusing, the flaw *currently*
being papered over by the !is_guest_mode() check isn't even the same bug
that commit da998b4 ("kvm: x86: Defer setting of CR2 until #PF
delivery") was trying to avoid.
At the time of commit da998b4, KVM didn't correctly handle exception
intercepts, as KVM would wait until VM-Entry into L2 was imminent to check
if the queued exception should morph to a nested VM-Exit. I.e. KVM would
deliver the payload to L2 and then synthesize a VM-Exit into L1. But the
payload was only the most blatant issue, e.g. waiting to check exception
intercepts would also lead to KVM incorrectly escalating a
should-be-intercepted #PF into a #DF.
That underlying bug was eventually fixed by commit 7709aba ("KVM: x86:
Morph pending exceptions to pending VM-Exits at queue time"), but in the
interim, commit a06230b ("KVM: x86: Deliver exception payload on
KVM_GET_VCPU_EVENTS") came along and subtly added another dependency on
the !is_guest_mode() check.
While not recorded in the changelog, the motivation for deferring the
!exception_payload_enabled delivery was to fix a flaw where a synthesized
MTF (Monitor Trap Flag) VM-Exit would drop a pending #DB and clobber DR6.
On a VM-Exit, VMX CPUs save pending #DB information into the VMCS, which
is emulated by KVM in nested_vmx_update_pending_dbg() by grabbing the
payload from the queue/pending exception. I.e. prematurely delivering the
payload would cause the pending #DB to not be recorded in the VMCS, and of
course, clobber L2's DR6 as seen by L1.
Jumping back to save+restore, the quirked behavior of forcing delivery of
the payload only works if userspace does KVM_GET_VCPU_EVENTS *before*
CR2 or DR6 is saved, i.e. before KVM_GET_SREGS{,2} and KVM_GET_DEBUGREGS.
E.g. if userspace does KVM_GET_SREGS before KVM_GET_VCPU_EVENTS, then the
CR2 saved by userspace won't contain the payload for the exception save by
KVM_GET_VCPU_EVENTS.
Deliberately deliver the payload in the store_regs() path, as it's the
least awful option even though userspace may not be doing save+restore.
Because if userspace _is_ doing save restore, it could elide KVM_GET_SREGS
knowing that SREGS were already saved when the vCPU exited.
Link: https://lore.kernel.org/all/20200207103608.110305-1-oupton@google.com
Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
Cc: stable@vger.kernel.org
Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev>
Tested-by: Yosry Ahmed <yosry.ahmed@linux.dev>
Link: https://patch.msgid.link/20260218005438.2619063-1-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>1 parent f3deabe commit 35053cd
1 file changed
Lines changed: 39 additions & 23 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
695 | 695 | | |
696 | 696 | | |
697 | 697 | | |
698 | | - | |
699 | | - | |
700 | | - | |
701 | 698 | | |
702 | 699 | | |
703 | 700 | | |
| |||
5147 | 5144 | | |
5148 | 5145 | | |
5149 | 5146 | | |
5150 | | - | |
5151 | | - | |
| 5147 | + | |
5152 | 5148 | | |
5153 | | - | |
5154 | | - | |
5155 | | - | |
5156 | | - | |
5157 | | - | |
5158 | | - | |
5159 | | - | |
5160 | | - | |
5161 | | - | |
5162 | 5149 | | |
5163 | 5150 | | |
5164 | 5151 | | |
| |||
5169 | 5156 | | |
5170 | 5157 | | |
5171 | 5158 | | |
5172 | | - | |
5173 | | - | |
5174 | | - | |
| 5159 | + | |
| 5160 | + | |
| 5161 | + | |
| 5162 | + | |
| 5163 | + | |
| 5164 | + | |
| 5165 | + | |
| 5166 | + | |
5175 | 5167 | | |
5176 | 5168 | | |
5177 | | - | |
5178 | | - | |
5179 | | - | |
5180 | | - | |
5181 | | - | |
5182 | | - | |
| 5169 | + | |
| 5170 | + | |
| 5171 | + | |
| 5172 | + | |
| 5173 | + | |
| 5174 | + | |
| 5175 | + | |
| 5176 | + | |
| 5177 | + | |
| 5178 | + | |
| 5179 | + | |
5183 | 5180 | | |
5184 | 5181 | | |
5185 | 5182 | | |
5186 | 5183 | | |
| 5184 | + | |
| 5185 | + | |
| 5186 | + | |
| 5187 | + | |
| 5188 | + | |
| 5189 | + | |
| 5190 | + | |
| 5191 | + | |
| 5192 | + | |
| 5193 | + | |
| 5194 | + | |
| 5195 | + | |
| 5196 | + | |
| 5197 | + | |
| 5198 | + | |
5187 | 5199 | | |
5188 | 5200 | | |
5189 | 5201 | | |
| |||
5364 | 5376 | | |
5365 | 5377 | | |
5366 | 5378 | | |
| 5379 | + | |
| 5380 | + | |
5367 | 5381 | | |
5368 | 5382 | | |
5369 | 5383 | | |
| |||
11396 | 11410 | | |
11397 | 11411 | | |
11398 | 11412 | | |
| 11413 | + | |
| 11414 | + | |
11399 | 11415 | | |
11400 | 11416 | | |
11401 | 11417 | | |
| |||
0 commit comments