Thread (178 messages) 178 messages, 11 authors, 2022-06-06

Re: [PATCH Part2 RFC v4 24/40] KVM: SVM: Add KVM_SEV_SNP_LAUNCH_UPDATE command

From: Sean Christopherson <seanjc@google.com>
Date: 2021-07-19 21:11:06
Also in: kvm, linux-coco, linux-efi, linux-mm, lkml, platform-driver-x86

On Fri, Jul 16, 2021, Brijesh Singh wrote:
On 7/16/21 3:01 PM, Sean Christopherson wrote:
quoted
I'm having a bit of deja vu...  This flow needs to hold kvm->srcu to do a memslot
lookup.

That said, IMO having KVM do the hva->gpa is not a great ABI.  The memslots are
completely arbitrary (from a certain point of view) and have no impact on the
validity of the memory pinning or PSP command.  E.g. a memslot update while this
code is in-flight would be all kinds of weird.

In other words, make userspace provide both the hva (because it's sadly needed
to pin memory) as well as the target gpa.  That prevents KVM from having to deal
with memslot lookups and also means that userspace can issue the command before
configuring the memslots (though I've no idea if that's actually feasible for
any userspace VMM).
The operation happen during the guest creation time so I was not sure if
memslot will be updated while we are executing this command. But I guess
its possible that a VMM may run different thread which may update
memslot while another thread calls the encryption. I'll let userspace
provide both the HVA and GPA as you recommended.
I'm not worried about a well-behaved userspace VMM, I'm worried about the code
KVM has to carry to guard against a misbehaving VMM.
 
quoted
quoted
+			ret = -EINVAL;
+			goto e_unpin;
+		}
+
+		psize = page_level_size(level);
+		pmask = page_level_mask(level);
Is there any hope of this path supporting 2mb/1gb pages in the not-too-distant
future?  If not, then I vote to do away with the indirection and just hardcode
4kg sizes in the flow.  I.e. if this works on 4kb chunks, make that obvious.
No plans to do 1g/2mb in this path. I will make that obvious by
hardcoding it.

quoted
quoted
+		gpa = gpa & pmask;
+
+		/* Transition the page state to pre-guest */
+		memset(&e, 0, sizeof(e));
+		e.assigned = 1;
+		e.gpa = gpa;
+		e.asid = sev_get_asid(kvm);
+		e.immutable = true;
+		e.pagesize = X86_TO_RMP_PG_LEVEL(level);
+		ret = rmpupdate(inpages[i], &e);
What happens if userspace pulls a stupid and assigns the same page to multiple
SNP guests?  Does RMPUPDATE fail?  Can one RMPUPDATE overwrite another?
The RMPUPDATE is available to the hv and it can call anytime with
whatever it want. The important thing is the RMPUPDATE + PVALIDATE
combination is what locks the page. In this case, PSP firmware updates
the RMP table and also validates the page.

If someone else attempts to issue another RMPUPDATE then Validated bit
will be cleared and page is no longer used as a private. Access to
unvalidated page will cause #VC.
Hmm, and there's no indication on success that the previous entry was assigned?
Adding a tracepoint in rmpupdate() to allow tracking transitions is probably a
good idea, otherwise debugging RMP violations and/or unexpected #VC is going to
be painful.

And/or if the kernel/KVM behavior is to never reassign directly and reading an RMP
entry isn't prohibitively expensive, then we could add a sanity check that the RMP
is unassigned and reject rmpupdate() if the page is already assigned.  Probably
not worth it if the overhead is noticeable, but it could be nice to have if things
go sideways.
quoted
quoted
+e_unpin:
+  /* Content of memory is updated, mark pages dirty */
+  memset(&e, 0, sizeof(e));
+  for (i = 0; i < npages; i++) {
+          set_page_dirty_lock(inpages[i]);
+          mark_page_accessed(inpages[i]);
+
+          /*
+           * If its an error, then update RMP entry to change page ownership
+           * to the hypervisor.
+           */
+          if (ret)
+                  rmpupdate(inpages[i], &e);
This feels wrong since it's purging _all_ RMP entries, not just those that were
successfully modified.  And maybe add a RMP "reset" helper, e.g. why is zeroing
the RMP entry the correct behavior?
By default all the pages are hypervior owned (i.e zero). If the
LAUNCH_UPDATE was successful then page should have transition from the
hypervisor owned to guest valid. By zero'ing it are reverting it back to
hypevisor owned.

I agree that I optimize it to clear the modified entries only and leave
everything else as a default.
To be clear, it's not just an optimization.  Pages that haven't yet been touched
may be already owned by a different VM (or even this VM).  I.e. "reverting" those
pages would actually result in a form of corruption.  It's somewhat of a moot point
because assigning a single page to multiple guests is going to be fatal anyways,
but potentially making a bug worse by introducing even more noise/confusion is not
good.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help