mbox series

[RFC,v1,00/10] Enable encrypted guest memory access in QEMU

Message ID 20210506014037.11982-1-yuan.yao@linux.intel.com
Headers show
Series Enable encrypted guest memory access in QEMU | expand

Message

Yuan Yao May 6, 2021, 1:40 a.m. UTC
From: Yuan Yao <yuan.yao@intel.com>

This RFC series introduces the basic framework and a common
implementation on x86 to handle encrypted guest memory
reading/writing, to support QEMU's built-in guest debugging
features, like the monitor command xp and gdbstub.

The encrypted guest which its memory and/or register context
is encrypted by vendor specific technology(AMD SEV/INTEL TDX),
is able to resist the attack from malicious VMM or other
privileged components in host side, however, this ability also
breaks down the QEMU's built-in guest debugging features,
because it prohibits the direct guest memory accessing
(memcpy() with HVA) from QEMU which is the base of these
debugging features.

The framework part based on the previous patche set from
AMD[1] and some discussion result in community[2]. The main
idea is, introduce some new debug interfaces to handle the
encrypted guest physical memory accessing, also introduce
new interfaces in MemoryRegion to handle the actual accessing
there with KVM, don't bother the exist memory access logic or
callbacks as far as possible. 

[1] https://lore.kernel.org/qemu-devel/
    cover.1605316268.git.ashish.kalra@amd.com/
[2] https://lore.kernel.org/qemu-devel/
    20200922201124.GA6606@ashkalra_ubuntu_server/

 - The difference part in this patch series:
   - We introduce another new vm level ioctl focus on the encrypted
     guest memory accessing:

     KVM_MEMORY_ENCRYPT_{READ,WRITE}_MEMORY

     struct kvm_rw_memory rw;
     rw.addr = gpa_OR_hva;
     rw.buf = (__u64)src;
     rw.len = len;
     kvm_vm_ioctl(kvm_state,
                  KVM_MEMORY_ENCRYPT_{READ,WRITE}_MEMORY,
                  &rw);

     This new ioctl has more neutral and general name for its
     purpose, the debugging support of AMD SEV and INTEL TDX
     can be covered by a unify QEMU implementation on x86 with this
     ioctl. Although only INTEL TD guest is supported in this series,
     AMD SEV could be also supported with implementation of this
     ioctl in KVM, plus small modifications in QEMU to enable the
     unify part.

   - The MemoryRegion interface introduced by AMD before now has
     addtional GPA parameter(only HVA before).
     This is for INTEL TDX which uses GPA to do guest memory
     accessing. This change won't impact AMD SEV which is using
     HVA to access the guest memory.

 - New APIs in QEMU:
   - Physical memory accessing:
     - cpu_physical_memory_rw_debug().
     - cpu_physical_memory_read_debug().
     - cpu_physical_memory_write_debug().
     - x86_ldl_phys_debug().
     - x86_ldq_phys_debug().
   - Access from address_space:
     - address_space_read_debug().
     - address_space_write_rom_debug().
   - Virtual memory accessing and page table walking:
     - cpu_memory_rw_debug().
     - x86_cpu_get_phys_page_attrs_encrypted_debug().

 - New intrfaces in QEMU:
   - MemoryDebugOps *physical_memory_debug_op
     - For normal guest:
       Just call the old exist memory RW functions.
     - For encrypted guest:
       Forward the request to MemoryRegion->ram_debug_ops

   - MemoryRegionRAMReadWriteOps MemoryRegion::*ram_debug_ops
     - For normal guest:
       NULL and nobody use it.
     - For encrypted guest:
       Forward the request to common/vendor specific implementation.

 - The relationship diagram of the APIs and interfaces:

                 +---------------------------------------------+
                 |x86_cpu_get_phys_page_attrs_encrypted_debug()|
                 +----------------------------------+----------+
                                                    |
          +---------------------------------+       |
          |cpu_physical_memory_rw_debug()   |       |
          |cpu_physical_memory_read_debug() |       |
          |cpu_physical_memory_write_debug()|       |
          +----------------------+----------+       |
                                 |                  |
   +---------------------+       |        +---------v----------+
   |cpu_memory_rw_debug()|       |        |x86_ldl_phys_debug()|
   +-------------------+-+       |        |x86_ldq_phys_debug()|
                       |         |        +-------+------------+
                       |         |                |
                       |         |                |
  +--------------------v---------v----------------v------------+
  |         MemoryDebugOps *physical_memory_debug_op           |
  +----------------------+--------------------------+----------+
                         |                          |
                         |Encrypted guest           |Normal guest
                         |                          |
    +--------------------v-----------------------+  |
    |address_space_encrypted_memory_read_debug() |  |
    |address_space_encrypted_rom_write_debug()   |  |
    +--------------------+-----------------------+  |
                         |                          | 
                         |          +---------------v----------+
                         |          |address_space_read()      |
                         |          |address_space_write_rom() |
                         |          +--------------------------+
                         |
        +----------------v----------------+
        | address_space_read_debug()      |
        | address_space_write_rom_debug() |
        +----------------+----------------+
                         |
                         |
                         |
        +----------------v----------------+
        |  MemoryRegionRAMReadWriteOps    |
        |  MemoryRegion::*ram_debug_ops   |
        +--------+--------------+---------+
                 |              |
                 |              |Normal guest
                 |              |
  Encrypted guest|          +---v-------------------+
                 |          | NULL(nobody using it) |
                 |          +-----------------------+
                 |
       +---------v----------------------------+
       |  kvm_encrypted_guest_read_memory()   |
       |  kvm_encrypted_guest_write_memory()  |
       +--------------------------------------+

Ashish Kalra (2):
  Introduce new MemoryDebugOps which hook into guest virtual and
    physical memory debug interfaces such as cpu_memory_rw_debug, to
    allow vendor specific assist/hooks for debugging and delegating
    accessing the guest memory. This is required for example in case of
    AMD SEV platform where the guest memory is encrypted and a SEV
    specific debug assist/hook will be required to access the guest
    memory.
  Add new address_space_read and address_space_write debug helper
    interfaces which can be invoked by vendor specific guest memory
    debug assist/hooks to do guest RAM memory accesses using the added
    MemoryRegion callbacks.

Brijesh Singh (2):
  Extend the MemTxAttrs to include a 'debug' flag. The flag can be used
    as general indicator that operation was triggered by the debugger.
  Currently, guest memory access for debugging purposes is performed
    using memcpy(). Extend the 'struct MemoryRegion' to include new
    callbacks that can be used to override the use of memcpy() with
    something else.

Yuan Yao (6):
  Introduce new interface KVMState::set_mr_debug_ops and its wrapper
  Implements the common MemoryRegion::ram_debug_ops for encrypted guests
  Set the RAM's MemoryRegion::debug_ops for INTEL TD guests
  Introduce debug version of physical memory read/write API
  Change the monitor and other commands and gdbstub to use the debug API
  Introduce new CPUClass::get_phys_page_attrs_debug implementation for
    encrypted guests

 accel/kvm/kvm-all.c       |  17 +++++
 accel/stubs/kvm-stub.c    |  11 +++
 dump/dump.c               |   2 +-
 gdbstub.c                 |   4 +-
 hw/i386/pc.c              |   4 +
 include/exec/cpu-common.h |  14 ++++
 include/exec/memattrs.h   |   4 +
 include/exec/memory.h     |  54 +++++++++++++
 include/sysemu/kvm.h      |   5 ++
 include/sysemu/tdx.h      |   3 +
 monitor/misc.c            |  12 ++-
 softmmu/cpus.c            |   2 +-
 softmmu/physmem.c         | 154 +++++++++++++++++++++++++++++++++++++-
 target/i386/cpu.h         |   4 +
 target/i386/helper.c      |  64 +++++++++++++---
 target/i386/kvm/kvm.c     |  68 +++++++++++++++++
 target/i386/kvm/tdx.c     |  21 ++++++
 target/i386/monitor.c     |  52 ++++++-------
 18 files changed, 447 insertions(+), 48 deletions(-)

Comments

Ashish Kalra Sept. 2, 2021, 2:04 p.m. UTC | #1
> - We introduce another new vm level ioctl focus on the encrypted
>     guest memory accessing:
>
>     KVM_MEMORY_ENCRYPT_{READ,WRITE}_MEMORY
>
>     struct kvm_rw_memory rw;
>     rw.addr = gpa_OR_hva;
>     rw.buf = (__u64)src;
>     rw.len = len;
>     kvm_vm_ioctl(kvm_state,
>                  KVM_MEMORY_ENCRYPT_{READ,WRITE}_MEMORY,
>                  &rw);
>
>     This new ioctl has more neutral and general name for its
>     purpose, the debugging support of AMD SEV and INTEL TDX
>     can be covered by a unify QEMU implementation on x86 with this
>     ioctl. Although only INTEL TD guest is supported in this series,
>     AMD SEV could be also supported with implementation of this
>     ioctl in KVM, plus small modifications in QEMU to enable the
>     unify part.

A general comment, we have sev_ioctl() interface for SEV guests and
probably this new vm level ioctl will not work for us.

It probably makes more sense to do this TDX/SEV level abstraction 
using the Memory Region's ram_debug_ops, which can point these to 
TDX specific vm level ioctl and SEV specific ioctl at the lowest
level of this interface.

Thanks,
Ashish
Yuan Yao Sept. 2, 2021, 11:23 p.m. UTC | #2
>-----Original Message-----
>From: Ashish Kalra <Ashish.Kalra@amd.com>
>Sent: Thursday, September 02, 2021 22:05
>To: yuan.yao@linux.intel.com
>Cc: Thomas.Lendacky@amd.com; armbru@redhat.com; ashish.kalra@amd.com; brijesh.singh@amd.com;
>dgilbert@redhat.com; ehabkost@redhat.com; Yamahata, Isaku <isaku.yamahata@intel.com>; kvm@vger.kernel.org;
>mst@redhat.com; mtosatti@redhat.com; pbonzini@redhat.com; qemu-devel@nongnu.org; Yao, Yuan
><yuan.yao@intel.com>
>Subject: [RFC][PATCH v1 00/10] Enable encrypted guest memory access in QEMU
>
>> - We introduce another new vm level ioctl focus on the encrypted
>>     guest memory accessing:
>>
>>     KVM_MEMORY_ENCRYPT_{READ,WRITE}_MEMORY
>>
>>     struct kvm_rw_memory rw;
>>     rw.addr = gpa_OR_hva;
>>     rw.buf = (__u64)src;
>>     rw.len = len;
>>     kvm_vm_ioctl(kvm_state,
>>                  KVM_MEMORY_ENCRYPT_{READ,WRITE}_MEMORY,
>>                  &rw);
>>
>>     This new ioctl has more neutral and general name for its
>>     purpose, the debugging support of AMD SEV and INTEL TDX
>>     can be covered by a unify QEMU implementation on x86 with this
>>     ioctl. Although only INTEL TD guest is supported in this series,
>>     AMD SEV could be also supported with implementation of this
>>     ioctl in KVM, plus small modifications in QEMU to enable the
>>     unify part.
>
>A general comment, we have sev_ioctl() interface for SEV guests and
>probably this new vm level ioctl will not work for us.
>
>It probably makes more sense to do this TDX/SEV level abstraction
>using the Memory Region's ram_debug_ops, which can point these to
>TDX specific vm level ioctl and SEV specific ioctl at the lowest
>level of this interface.
>
Hi Ashish,

Yes, this new ioctl is now working as the low-level interface for 
Memory Region's ram_debug_ops. SEV can use 
kvm_setup_set_memory_region_debug_ops() to install a new
callback to KVM for installing SEV only low-level implementation,
then call kvm_set_memory_region_debug_ops() to do Memory
Region's ram_debug_ops installation later.


>Thanks,
>Ashish
Ashish Kalra Sept. 7, 2021, 10:51 a.m. UTC | #3
Hello Yuan,

On Thu, Sep 02, 2021 at 11:23:50PM +0000, Yao, Yuan wrote:
> >-----Original Message-----
> >From: Ashish Kalra <Ashish.Kalra@amd.com>
> >Sent: Thursday, September 02, 2021 22:05
> >To: yuan.yao@linux.intel.com
> >Cc: Thomas.Lendacky@amd.com; armbru@redhat.com; ashish.kalra@amd.com; brijesh.singh@amd.com;
> >dgilbert@redhat.com; ehabkost@redhat.com; Yamahata, Isaku <isaku.yamahata@intel.com>; kvm@vger.kernel.org;
> >mst@redhat.com; mtosatti@redhat.com; pbonzini@redhat.com; qemu-devel@nongnu.org; Yao, Yuan
> ><yuan.yao@intel.com>
> >Subject: [RFC][PATCH v1 00/10] Enable encrypted guest memory access in QEMU
> >
> >> - We introduce another new vm level ioctl focus on the encrypted
> >>     guest memory accessing:
> >>
> >>     KVM_MEMORY_ENCRYPT_{READ,WRITE}_MEMORY
> >>
> >>     struct kvm_rw_memory rw;
> >>     rw.addr = gpa_OR_hva;
> >>     rw.buf = (__u64)src;
> >>     rw.len = len;
> >>     kvm_vm_ioctl(kvm_state,
> >>                  KVM_MEMORY_ENCRYPT_{READ,WRITE}_MEMORY,
> >>                  &rw);
> >>
> >>     This new ioctl has more neutral and general name for its
> >>     purpose, the debugging support of AMD SEV and INTEL TDX
> >>     can be covered by a unify QEMU implementation on x86 with this
> >>     ioctl. Although only INTEL TD guest is supported in this series,
> >>     AMD SEV could be also supported with implementation of this
> >>     ioctl in KVM, plus small modifications in QEMU to enable the
> >>     unify part.
> >
> >A general comment, we have sev_ioctl() interface for SEV guests and
> >probably this new vm level ioctl will not work for us.
> >
> >It probably makes more sense to do this TDX/SEV level abstraction
> >using the Memory Region's ram_debug_ops, which can point these to
> >TDX specific vm level ioctl and SEV specific ioctl at the lowest
> >level of this interface.
> >
> Hi Ashish,
> 
> Yes, this new ioctl is now working as the low-level interface for 
> Memory Region's ram_debug_ops. SEV can use 
> kvm_setup_set_memory_region_debug_ops() to install a new
> callback to KVM for installing SEV only low-level implementation,
> then call kvm_set_memory_region_debug_ops() to do Memory
> Region's ram_debug_ops installation later.
> 
> 

Ok. Yes i think that should work. 

Thanks,
Ashish