On Mon, May 17, 2021, Dave Hansen wrote: > On 5/17/21 10:39 AM, Sean Christopherson wrote: > > On Mon, May 17, 2021, Paolo Bonzini wrote: > >> On 14/05/21 07:11, Andy Lutomirski wrote: > >>> I don't even want to think about what happens if a perf NMI hits and > >>> accesses host user memory while the guest PKRU is live (on VMX -- I > >>> think this can't happen on SVM). > >> This is indeed a problem, which indeed cannot happen on SVM but is there on > >> VMX. Note that the function above is not handling all of the xstate, it's > >> handling the *XSAVE state*, that is XCR0, XSS and PKRU. Thus the window is > >> small, but it's there. > >> > >> Is it solvable at all, without having PKRU fields in the VMCS (and without > >> masking NMIs in the LAPIC which would be too expensive)? Dave, Sean, what > >> do you think? > > The least awful solution would be to have the NMI handler restore the host's > > PKRU. The NMI handler would need to save/restore the register, a la CR2, but the > > whole thing could be optimized to run if and only if the NMI lands in the window > > where the guest's PKRU is loaded. > > What were you thinking about? Something like: > > *this_cpu_ptr(&need_nmi_wpkru) = 1 > // Enter Guest > __write_pkru(vcpu->arch.pkru); > *this_cpu_ptr(&need_nmi_wpkru) = 0 > > And then in the NMI handler: > > u32 pkru; > > if (*this_cpu_ptr(&need_nmi_wpkru)) { > pkru = rdpku(); > __write_pkru(vcpu->arch.pkru); This isn't correct, vcpu->arch.pkru holds the guest value, the NMI handler needs to load the host value. I was thinking KVM would stash away the current host value, and the NMI handler would check the saved value against rdpkru(). > } > ... > copy_*_user_nmi(... whatever ...); > ... > if (*this_cpu_ptr(&need_nmi_wpkru)) > __write_pkru(pkru); > > ? > > I was thinking we could just blow away PKRU without saving/restoring it > in the NMI handler, but that might clobber PKRU in the window between > need_nmi_wpkru=1 and entering the guest. Yep. It would also blow away the guest's value if the guest did WRPKU while it was running since KVM would never get a chance to read/save the guest's new value. > But, the save/restore seems doable especially since we can do it in C > and don't have to mess with the NMI stack or anything.