Thread (239 messages) 239 messages, 19 authors, 2022-09-19

Re: [PATCH Part2 v5 00/45] Add AMD Secure Nested Paging (SEV-SNP) Hypervisor Support

From: Andy Lutomirski <luto@kernel.org>
Date: 2021-11-12 21:20:57
Also in: kvm, linux-crypto, linux-mm, lkml

On 11/12/21 13:12, Peter Gonda wrote:
On Fri, Nov 12, 2021 at 1:55 PM Borislav Petkov [off-list ref] wrote:
quoted
On Fri, Nov 12, 2021 at 08:37:59PM +0000, Sean Christopherson wrote:
quoted
Let userspace decide what is mapped shared and what is mapped private.
With "userspace", you mean the *host* userspace?
quoted
The kernel and KVM provide the APIs/infrastructure to do the actual
conversions in a thread-safe fashion and also to enforce the current
state, but userspace is the control plane.

It would require non-trivial changes in userspace if there are multiple processes
accessing guest memory, e.g. Peter's networking daemon example, but it _is_ fully
solvable.  The exit to userspace means all three components (guest, kernel,
and userspace) have full knowledge of what is shared and what is private.  There
is zero ambiguity:

   - if userspace accesses guest private memory, it gets SIGSEGV or whatever.
That SIGSEGV is generated by the host kernel, I presume, after it checks
whether the memory belongs to the guest?
quoted
   - if kernel accesses guest private memory, it does BUG/panic/oops[*]
If *it* is the host kernel, then you probably shouldn't do that -
otherwise you just killed the host kernel on which all those guests are
running.
I agree, it seems better to terminate the single guest with an issue.
Rather than killing the host (and therefore all guests). So I'd
suggest even in this case we do the 'convert to shared' approach or
just outright terminate the guest.

Are there already examples in KVM of a KVM bug in servicing a VM's
request results in a BUG/panic/oops? That seems not ideal ever.
quoted
quoted
   - if guest accesses memory with the incorrect C/SHARED-bit, it gets killed.
Yah, that's the easy one.
quoted
This is the direction KVM TDX support is headed, though it's obviously still a WIP.

And ideally, to avoid implicit conversions at any level, hardware vendors' ABIs
define that:

   a) All convertible memory, i.e. RAM, starts as private.
   b) Conversions between private and shared must be done via explicit hypercall.
I like the explicit nature of this but devil's in the detail and I'm no
virt guy...
This seems like a reasonable approach that can help with the issue of
terminating the entity behaving poorly. Could this feature be an
improvement that comes later? This improvement could be gated behind a
per VM KVM CAP, a kvm module param, or insert other solution here, to
not blind side userspace with this change?
quoted
quoted
Without (b), userspace and thus KVM have to treat guest accesses to the incorrect
type as implicit conversions.

[*] Sadly, fully preventing kernel access to guest private is not possible with
     TDX, especially if the direct map is left intact.  But maybe in the future
     TDX will signal a fault instead of poisoning memory and leaving a #MC mine.
Yah, the #MC thing sounds like someone didn't think things through. ;-\
Yes #MC in TDX seems much harder to deal with than the #PF for SNP.
I'd propose TDX keeps the host kernel safe bug not have that solution
block SNP. As suggested above I like the idea but it seems like it can
come as a future improvement to SNP support.
Can you clarify what type of host bug you're talking about here?  We're 
talking about the host kernel reading or writing guest private memory 
through the direct map or kmap, right?  It seems to me that the way this 
happens is:

struct page *guest_page = (get and refcount a guest page);

...

guest switches the page to private;

...

read or write the page via direct map or kmap.


This naively *looks* like something a malicious or buggy guest could 
induce the host kernel to do.  But I think that, if this actually 
occurs, it's an example of a much more severe host bug.  In particular, 
there is nothing special about the guest switching a page to private -- 
the guest or QEMU could just as easily have freed (hotunplugged) a 
shared guest page or ballooned it or swapped it or otherwise deallocated 
it.  And, if the host touches a page/pfn that the guest has freed, this 
is UAF, is a huge security hole if the guest has any degree of control, 
and needs to kill the host kernel if detected.

Now we can kind of sweep it under the rug by saying that changing a page 
from shared to private isn't really freeing the page -- it's just 
modifying the usage of the page.  But to me that sounds like saying 
"reusing a former user memory page as a pagetable isn't *really* freeing 
it if the kernel kept a pointer around the whole time and the page 
allocator wasn't involved".

So let's please just consider these mode transitions to be equivalent to 
actually freeing the page at least from a locking perspective, and then 
the way to prevent these bugs and the correct action to take if they 
occur is clear.

(On TDX, changing a page shared/private state is very much like freeing 
and reallocating -- they're in different page tables and, in principle 
anyway, there is no actual relationship between a shared page and a 
supposedly matching private page except that some bits of the GPA happen 
to match.  The hardware the TD module fully support both being mapped at 
once at the same "address", at least according to the specs I've read.)

--Andy
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help