Michael Roth <[email protected]> writes:

> The GHCB specification[1] defines a VMGEXIT-based Guest Request
> hypercall to allow an SNP guest to issue encrypted requests directly to
> SNP firmware to do things like query the attestation report for the
> guest. These are generally handled purely in the kernel.
>
> In some cases, it's useful for the host to be able to additionally
> supply the certificate chain for the signing key that SNP firmware uses
> to sign these attestation reports. To allow for this, the GHCB
> specification defines an Extended Guest Request where this certificate
> data can be provided in a special format described in the GHCB spec.
> This certificate data may be global or guest-specific depending on how
> the guest was configured. Rather than providing interfaces to manage
> these within the kernel, KVM provides a new KVM_EXIT_SNP_REQ_CERTS exit
> to request the certificate contents from userspace. Implement support
> for that in QEMU.
>
> To synchronize delivery of the certificates to the guest in a way where
> they will not be rendered invalid by updates to SNP firmware or
> attestation singing/endorsement keys by management tools outside the
> purview of QEMU, it is expected by users of KVM_EXIT_SNP_REQ_CERTS to
> obtain a shared/read lock on the certificate file prior to delivering
> them back to KVM. Only after this will the attestation report be
> retrieved from firmware and bundled with the certificate data, so QEMU
> must continue to hold the file lock until KVM confirms that the
> attestation report has been retrieved/bundled.
>
> This confirmation is done by way of the kvm_immediate_exit callback
> infrastructure that was introduced in a prior commit. Once the callback
> is issued (after the next KVM_RUN), the attestation report will have
> been fetched, so the report and certificate data fetched by QEMU should
> be consistent with one another, and the certificate lock can then be
> released. The included documentation updates have more details on how
> this is handled.
>
> [1] "Guest Hypervisor Communication Block (GHCB) Standardization",
>     https://www.amd.com/en/developer/sev.html
>
> Co-developed-by: Melody Wang <[email protected]>
> Signed-off-by: Melody Wang <[email protected]>
> Signed-off-by: Michael Roth <[email protected]>
> ---
>  docs/system/i386/amd-memory-encryption.rst |  77 +++++
>  qapi/qom.json                              |  23 +-
>  target/i386/kvm/kvm.c                      |  10 +
>  target/i386/sev-system-stub.c              |   5 +
>  target/i386/sev.c                          | 338 +++++++++++++++++++++
>  target/i386/sev.h                          |   3 +-
>  6 files changed, 454 insertions(+), 2 deletions(-)
>
> diff --git a/docs/system/i386/amd-memory-encryption.rst 
> b/docs/system/i386/amd-memory-encryption.rst
> index 6c23f3535f..da6f1a3693 100644
> --- a/docs/system/i386/amd-memory-encryption.rst
> +++ b/docs/system/i386/amd-memory-encryption.rst
> @@ -228,6 +228,83 @@ schema for the 'sev-snp-guest' object)::
>      -machine ...,confidential-guest-support=sev0 \
>      -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1
>  
> +Certificate-fetching (SEV-SNP)
> +------------------------------
> +
> +When an SEV-SNP guest requests an attestation report from the host, it may
> +optionally request that the host also deliver the certificates (and
> +potentially other accompanying data) as part of the response.
> +
> +QEMU can be configured to provide this certificate data in the following
> +manner::
> +
> +  # ${QEMU} \
> +    -machine ...,confidential-guest-support=sev0 \
> +    -object 
> sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,certs-filename=<certs>
> +
> +where the format of the file is defined in the SEV-ES Guest-Hypervisor
> +Communication Block Standardization (GHCB) v2.04, section 4.1.8.1, as::
> +
> +  Returned certificates are identified in a table starting at offset 0x0 of
> +  [the file]. Each entry consists of a 16-byte GUID, a 4-byte offset from
> +  [the file] to where the certificate data starts and a 4-byte length
> +  representing the length of the certificate data. The table is terminated
> +  with an entry containing all zeroes for the GUID, offset and length.
> +
> +  struct cert_table {
> +      struct {
> +          unsigned char guid[16];
> +          uint32 offset;
> +          uint32 length;
> +      } cert_table_entry[];
> +  };
> +
> +Because QEMU supplies the certificate to the hypervisor prior to the
> +hypervisor actually issuing an attestation request, there is potential for
> +the certificate data to becoming stale due to a firmware upgrade or other
> +host management activities. The ioctl which enables certificate-fetching
> +support via the KVM hypervisor, KVM_SEV_SNP_ENABLE_REQ_CERTS, documents
> +the following suggested scheme as part of its linux documentation (v7.3
> +at the time of this writing), and it is highly recommended that all software
> +interacting with these certificates, or performing operations that may
> +affect their validity, adopt this same scheme for interoperability::
> +
> +  The recommended scheme to do this is to use file locking (e.g. via
> +  fcntl()'s F_OFD_SETLK) in the following manner:
> +
> +    - Prior to obtaining/providing certificate data as part of servicing an
> +      exit type of ``KVM_EXIT_SNP_REQ_CERTS``, the VMM should obtain a
> +      shared/read or exclusive/write lock on the certificate blob file before
> +      reading it and returning it to KVM, and continue to hold the lock until
> +      the attestation request is actually sent to firmware. To facilitate
> +      this, the VMM can set the ``immediate_exit`` flag of kvm_run just after
> +      supplying the certificate data, and just before resuming the vCPU.
> +      This will ensure the vCPU will exit again to userspace with ``-EINTR``
> +      after it finishes fetching the attestation request from firmware, at
> +      which point the VMM can safely drop the file lock.
> +
> +    - Tools/libraries that perform updates to SNP firmware TCB values or
> +      endorsement keys (e.g. via /dev/sev interfaces such as ``SNP_COMMIT``,
> +      ``SNP_SET_CONFIG``, or ``SNP_VLEK_LOAD``, see
> +      Documentation/virt/coco/sev-guest.rst for more details) in such a way
> +      that the certificate blob needs to be updated, should similarly take an
> +      exclusive lock on the certificate blob for the duration of any updates
> +      to endorsement keys or the certificate blob contents to ensure that
> +      VMMs using the above scheme will not return certificate blob data that
> +      is out of sync with the endorsement key used by firmware at the time
> +      the attestation request is actually issued.
> +
> +  This scheme is recommended so that tools can use a fairly generic/natural
> +  approach to synchronizing firmware/certificate updates via file-locking,
> +  which should make it easier to maintain interoperability across
> +  tools/VMMs/vendors.
> +
> +As such, QEMU implements this same scheme by waiting for a read-lock on the
> +file containing the certificate data before supplying any data it contains.
> +In order to ensure that the lock is not released until after the hypervisor
> +is finished fetching the attestation report for the guest, the lock is held
> +until a subsequent exit from the hypervisor that indicates the attestation
> +report has already been fetched, as which point QEMU will drop the lock.
>  
>  Debugging
>  ---------
> diff --git a/qapi/qom.json b/qapi/qom.json
> index 4810d53e58..8884a1eb66 100644
> --- a/qapi/qom.json
> +++ b/qapi/qom.json
> @@ -1104,6 +1104,25 @@
>  # @tsc-frequency: set secure TSC frequency.  Only valid if Secure TSC
>  #     is enabled (default: zero) (since 11.1)
>  #
> +# @certs-filename: Certificate data that can be passed to guests as
> +#     part of an attestion request.  See the
> +#     :doc:`/system/i386/amd-memory-encryption` documentation for more
> +#     details on the usage and file format.
> +#     (default: none) (since: 11.2)
> +#
> +# @certs-timeout: Maximum time in milliseconds to wait to obtain a
> +#     read lock on the certificate file specified by @certs-filename.
> +#     This is not a cumulative value and only affects how long QEMU
> +#     waits before returning execution to the vCPU and informing the
> +#     guest of the timeout, so the guest can still continue retrying
> +#     for as long as it likes, which for linux guests at the time of
> +#     this writing will be about 60 seconds before the guest gives
> +#     up and disables further requests.  If this guest-side timeout is
> +#     insufficient, set this higher to allow more time to fetch the
> +#     certificate.  If the guest-side timeout is sufficient,
> +#     set this lower to reduce the likelihood of soft lockups in the
> +#     guest.  (default: 100) (since: 11.2)
> +#
>  # Since: 9.1
>  ##
>  { 'struct': 'SevSnpGuestProperties',
> @@ -1117,7 +1136,9 @@
>              '*host-data': 'str',
>              '*vcek-disabled': 'bool',
>              '*secure-tsc': 'bool',
> -            '*tsc-frequency': 'uint32' } }
> +            '*tsc-frequency': 'uint32',
> +            '*certs-filename': 'str',
> +            '*certs-timeout': 'uint32' } }

Why uint32 for time?  We commonly use 'int'.

Hmm, see [*] below.

>  
>  ##
>  # @TdxGuestProperties:
> diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
> index da922f72d7..9f7bdf9618 100644
> --- a/target/i386/kvm/kvm.c
> +++ b/target/i386/kvm/kvm.c
> @@ -6651,6 +6651,16 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run 
> *run)
>              break;
>          }
>          ret = 0;
> +        break;
> +    case KVM_EXIT_SNP_REQ_CERTS:
> +        if (!sev_snp_enabled()) {
> +            error_report("KVM: Encountered a certificate request exit for a "
> +                         "non-SEV-SNP guest.");
> +            ret = -1;
> +        } else {
> +            ret = kvm_handle_snp_req_certs(cs, run);
> +        }
> +
>          break;
>      default:
>          fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
> diff --git a/target/i386/sev-system-stub.c b/target/i386/sev-system-stub.c
> index d97536cca1..e53f1bbefc 100644
> --- a/target/i386/sev-system-stub.c
> +++ b/target/i386/sev-system-stub.c
> @@ -34,3 +34,8 @@ int sev_es_save_reset_vector(void *flash_ptr, uint64_t 
> flash_size)
>  void pc_system_parse_sev_metadata(uint8_t *flash_ptr, size_t flash_size)
>  {
>  }
> +
> +int kvm_handle_snp_req_certs(CPUState *cpu, struct kvm_run *run)
> +{
> +    g_assert_not_reached();
> +}
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 11072b00dc..3cb2e9cd0c 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -186,6 +186,8 @@ struct SevSnpGuestState {
>      uint8_t *id_auth;
>      char *host_data;
>      uint32_t tsc_khz;
> +    char *certs_filename;
> +    uint32_t certs_timeout;
>  
>      struct kvm_sev_snp_launch_start kvm_start_conf;
>      struct kvm_sev_snp_launch_finish kvm_finish_conf;
> @@ -1701,6 +1703,278 @@ sev_snp_launch_finish(SevCommonState *sev_common)
>      sev_set_guest_state(sev_common, SEV_STATE_RUNNING);
>  }
>  
> +/*
> + * Cases where -EAGAIN is returned on an error path are expected to terminate
> + * after the next call (e.g. via a qemu_open() error) if they are not 
> transient
> + * issues. These potentially-transient issues are still logged however, since
> + * they are not expected on a well-behaved system.
> + */
> +static int open_certs_locked(SevSnpGuestState *sev_snp_guest)
> +{
> +    struct stat locked_file, current_file;
> +    int fd, ret;
> +
> +    fd = qemu_open(sev_snp_guest->certs_filename, O_RDONLY, NULL);
> +    if (fd == -1) {
> +        error_report_once("Unable to open certificate file: %s",
> +                          strerror(errno));
> +        return -errno;
> +    }
> +
> +    if (fstat(fd, &locked_file) == -1) {
> +        error_report_once("Unable to check status of certificate file: %s",
> +                          strerror(errno));
> +        ret = -errno;
> +        goto out_close;
> +    }
> +
> +    ret = qemu_lock_fd(fd, 0, 0, false);
> +    if (ret == -EACCES) {
> +        /*
> +         * F_SETLK is documented to potentially return either EACCES or 
> EAGAIN
> +         * for contended file locks.
> +         */
> +        ret = -EAGAIN;
> +    } else if (ret == -EDEADLK) {
> +        error_report_once("Potential deadlock encountered while trying "
> +                          "to lock the certificate file");
> +        ret = -EAGAIN;
> +    }
> +
> +    if (ret) {
> +        if (ret != -EAGAIN) {
> +            error_report_once("Error while trying to lock certificate file: 
> %s",
> +                              strerror(-ret));
> +        }
> +        goto out_close;
> +    }
> +
> +    if (stat(sev_snp_guest->certs_filename, &current_file) == -1) {
> +        error_report_once("Certificate file no longer present: %s",
> +                          strerror(errno));
> +        ret = -EAGAIN;
> +        goto out_close;
> +    }
> +
> +    /*
> +     * Locked files should not be changing; this violates the locking
> +     * protocol assumed by this implementation. Indicate the need to
> +     * retry to the caller, but make sure to log it first.
> +     */
> +    if (locked_file.st_ino != current_file.st_ino ||
> +        locked_file.st_dev != current_file.st_dev) {
> +        error_report_once("Locked certificate file was recreated");
> +        ret = -EAGAIN;
> +        goto out_close;
> +    }
> +
> +    /*
> +     * The locked file is intact and as-expected, and it has not been 
> replaced
> +     * since then, so the fd should be okay to use.
> +     */
> +    return fd;
> +
> +out_close:
> +    close(fd);
> +    return ret;
> +}
> +
> +static void close_certs(int fd)
> +{
> +    qemu_unlock_fd(fd, 0, 0);
> +    close(fd);
> +}
> +
> +static ssize_t get_certs_size(int fd)
> +{
> +    ssize_t size;
> +
> +    size = lseek(fd, 0, SEEK_END);
> +    if (size == -1) {
> +        error_report_once("Error while determining the size of the 
> certificate file: %s",
> +                          strerror(errno));
> +        return -errno;
> +    }
> +
> +    return size;
> +}
> +
> +static int read_certs(int fd, void *buf, size_t buf_len)
> +{
> +    ssize_t n;
> +
> +    n = lseek(fd, 0, SEEK_SET);
> +    if (n == -1) {
> +        error_report_once("Error while setting certificate file position: 
> %s",
> +                          strerror(errno));
> +        return -errno;
> +    }
> +
> +    while ((n = read(fd, buf, buf_len)) != 0) {
> +        if (n == -1) {
> +            if (errno == EINTR) {
> +                continue;
> +            }
> +
> +            error_report_once("Error reading the certificate file: %s",
> +                              strerror(errno));
> +            return -errno;
> +        }
> +        buf += n;
> +        buf_len -= n;
> +    }
> +
> +    return 0;
> +}
> +
> +static void snp_release_certs_lock(CPUState *cpu, run_on_cpu_data data)
> +{
> +    close_certs(data.host_int);
> +}
> +
> +/*
> + * NOTE: It is not expected that the guest will call this in a tight loop
> + * where error reporting would flood logs. A failed certificate fetch results
> + * in a failed attestation request, which results in a disabled attestation
> + * driver in the guest usually.
> + *
> + * However, one instance of such an error is usually enough of a clue to
> + * to identify the component of the system that should be investigated.
> + *
> + * So, to guard against a malicious guest trying to flood host logs, while
> + * still providing reasonable debug/error information to the user, use
> + * error_report_once() throughout this function and its supporting helpers.
> + */
> +int kvm_handle_snp_req_certs(CPUState *cpu, struct kvm_run *run)
> +{
> +    struct kvm_exit_snp_req_certs *req_certs = &run->snp_req_certs;
> +    SevSnpGuestState *sev_snp_guest;
> +    ssize_t certs_size;
> +    uint32_t npages;
> +    void *guest_buf;
> +    int64_t t0_ms;
> +    hwaddr buf_sz;
> +    int ret, fd;
> +    hwaddr gpa;
> +
> +    gpa = req_certs->gpa;
> +    npages = req_certs->npages;
> +
> +    sev_snp_guest = SEV_SNP_GUEST(MACHINE(qdev_get_machine())->cgs);
> +    if (!sev_snp_guest->certs_filename) {
> +        req_certs->ret = 0;
> +        return 0;
> +    }
> +
> +    /*
> +     * By default, any errors encountered below will be forwarded to the 
> guest
> +     * as an EIO. This will likely result in the guest disabling its driver, 
> but
> +     * it's better than crashing QEMU.
> +     *
> +     * Leave the special cases, SUCCESS/ENOSPC/EAGAIN, to re-set the guest
> +     * return code as-needed.
> +     *
> +     * Errors that are useful for debugging QEMU will still be logged, with 
> care
> +     * to avoid busy/EAGAIN paths/etc.
> +     */
> +    req_certs->ret = EIO;
> +
> +    /*
> +     * -EAGAIN from open_certs_locked() indicates that a lock could not be
> +     * obtained on the certificate file. It would be possible to set
> +     * req_certs->ret = EAGAIN to immediately inform the requesting vCPU of
> +     * this condition so that it can retry again later, however, linux guests
> +     * are currently hard-limited to a 60 second timeout, at which point they
> +     * will assume misbehavior and refuse to continue issuing attestation
> +     * requests from that point forward.
> +     *
> +     * Avoid risking triggering this by instead busy-waiting on the QEMU 
> side,
> +     * which allows more time for QEMU to wait on potentially long-running
> +     * tasks like SNP firmware updates/etc. which may be holding an exclusive
> +     * lock on the certificate file.
> +     *
> +     * The down-side to doing things this way is that too long of a busy-wait
> +     * will result in soft-lockups in the guest, but the guest will otherwise
> +     * continue normally afterward.
> +     *
> +     * If the QEMU-side timeout is reached, then just go ahead and indicate
> +     * EAGAIN to the guest, at which point the above-mentioned guest-side
> +     * timeout will trigger if QEMU's timeout exceeds that of the guest. But
> +     * that's better than killing the vCPU, which is the only viable
> +     * alternative at that point.
> +     */
> +    t0_ms = g_get_monotonic_time() / 1000;
> +
> +    do {
> +        fd = open_certs_locked(sev_snp_guest);
> +
> +        if (fd == -EAGAIN) {
> +            int64_t t1_ms = g_get_monotonic_time() / 1000;
> +
> +            if (t1_ms - t0_ms > sev_snp_guest->certs_timeout) {

[*] Left operand is int64_t, and the right operand is uint32_t.  The
right operand is converted to int64_t, which is safe, but to see that,
you need to know the "usual arithmetic conversions (C99 ยง 6.3.1.8)
intimately.  Suggest to make the right operand int64_t to avoid such
brain burn.

> +                req_certs->ret = EAGAIN;
> +                return 0;
> +            }
> +
> +            /*
> +             * If some other process (QEMU only ever takes a read lock) has 
> an
> +             * exclusive lock on the certificate file, then it is likely 
> because
> +             * a firmware update or other long-running operation is taking 
> place;
> +             * it's a waste to re-try at a high rate.
> +             */
> +            g_usleep(1000);
> +        } else if (fd < 0) {
> +            return 0;
> +        }
> +    } while (fd == -EAGAIN);
> +
> +    certs_size = get_certs_size(fd);
> +    if (certs_size < 0) {
> +        goto err_close;
> +    }
> +
> +    buf_sz = (hwaddr)npages * TARGET_PAGE_SIZE;
> +    if (buf_sz < certs_size) {
> +        /* Communicate to guest that more pages are needed. */
> +        req_certs->ret = ENOSPC;
> +        req_certs->npages = DIV_ROUND_UP(certs_size, TARGET_PAGE_SIZE);
> +        goto err_close;
> +    }
> +
> +    guest_buf = address_space_map(&address_space_memory, gpa, &buf_sz, true,
> +                                  MEMTXATTRS_UNSPECIFIED);
> +    if (!guest_buf) {
> +        error_report_once("Unable to map guest buffer to provide "
> +                          "certificate data.");
> +        goto err_close;
> +    }
> +
> +    if (buf_sz < (hwaddr)npages * TARGET_PAGE_SIZE) {
> +        error_report_once("Unable to map the full guest buffer to provide "
> +                          "certificate data.");
> +        address_space_unmap(&address_space_memory, guest_buf, buf_sz, true, 
> 0);
> +        goto err_close;
> +    }
> +
> +    ret = read_certs(fd, guest_buf, buf_sz);
> +    address_space_unmap(&address_space_memory, guest_buf, buf_sz, true, 
> buf_sz);
> +
> +    if (!ret) {
> +        /*
> +         * Looks good, return the certificate to the guest and prepare to
> +         * release the file lock once KVM signals completion.
> +         */
> +        kvm_add_immediate_exit_callback(cpu, snp_release_certs_lock,
> +                                        RUN_ON_CPU_HOST_INT(fd));
> +
> +        req_certs->ret = 0;
> +        return 0;
> +    }
> +
> +err_close:
> +    close_certs(fd);
> +    return 0;
> +}
>  
>  static void
>  sev_vm_state_change(void *opaque, bool running, RunState state)
> @@ -2051,6 +2325,41 @@ static int sev_snp_kvm_init(ConfidentialGuestSupport 
> *cgs, Error **errp)
>      g_free(sev_snp_guest->kernel_hashes_data);
>      sev_snp_guest->kernel_hashes_data = NULL;
>  
> +    if (sev_snp_guest->certs_filename) {
> +        unsigned long certs_attr;
> +        struct kvm_device_attr attr = {
> +            .group = KVM_X86_GRP_SEV,
> +            .attr = KVM_X86_SEV_SNP_REQ_CERTS,
> +            .addr = (unsigned long) &certs_attr
> +        };
> +        int ret;
> +
> +        if (!kvm_check_extension(kvm_state, KVM_CAP_SYS_ATTRIBUTES) ||
> +            !kvm_check_extension(kvm_state, KVM_CAP_IMMEDIATE_EXIT)) {
> +            return -EINVAL;
> +        }
> +
> +        ret = kvm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
> +        if (ret < 0) {
> +            error_setg(errp, "Certificate-fetching attribute not present.");
> +            return ret;
> +        }
> +
> +        if (!certs_attr) {
> +            error_setg(errp, "Certificate-fetching attribute not set.");
> +            return -EINVAL;
> +        }
> +
> +        ret = sev_ioctl(SEV_COMMON(sev_snp_guest)->sev_fd,
> +                        KVM_SEV_SNP_ENABLE_REQ_CERTS,
> +                        NULL, NULL);
> +        if (ret) {
> +            error_setg(errp, "Failed to enable support for SEV-SNP "
> +                             "certificate-fetching requests.");
> +            return ret;
> +        }
> +    }
> +
>      return 0;
>  }
>  
> @@ -3320,6 +3629,26 @@ sev_snp_guest_set_tsc_frequency(Object *obj, Visitor 
> *v, const char *name,
>      SEV_SNP_GUEST(obj)->tsc_khz = value / 1000;
>  }
>  
> +static char *
> +sev_snp_guest_get_certs_filename(Object *obj, Error **errp)
> +{
> +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> +
> +    return g_strdup(sev_snp_guest->certs_filename);
> +}
> +
> +static void
> +sev_snp_guest_set_certs_filename(Object *obj, const char *value, Error 
> **errp)
> +{
> +    SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
> +
> +    if (sev_snp_guest->certs_filename) {
> +        g_free(sev_snp_guest->certs_filename);
> +    }
> +
> +    sev_snp_guest->certs_filename = value ? g_strdup(value) : NULL;
> +}
> +
>  static void
>  sev_snp_guest_class_init(ObjectClass *oc, const void *data)
>  {
> @@ -3361,6 +3690,12 @@ sev_snp_guest_class_init(ObjectClass *oc, const void 
> *data)
>      object_class_property_add(oc, "tsc-frequency", "uint32",
>                                sev_snp_guest_get_tsc_frequency,
>                                sev_snp_guest_set_tsc_frequency, NULL, NULL);
> +    object_class_property_add_str(oc, "certs-filename",
> +                                  sev_snp_guest_get_certs_filename,
> +                                  sev_snp_guest_set_certs_filename);
> +    object_class_property_add_uint32_ptr(oc, "certs-timeout",
> +                                   offsetof(SevSnpGuestState, certs_timeout),
> +                                   OBJ_PROP_FLAG_READWRITE);
>  }
>  
>  static void
> @@ -3374,6 +3709,8 @@ sev_snp_guest_instance_init(Object *obj)
>      /* default init/start/finish params for kvm */
>      sev_snp_guest->kvm_start_conf.policy = DEFAULT_SEV_SNP_POLICY;
>      sev_set_feature(SEV_COMMON(sev_snp_guest), SVM_SEV_FEAT_SNP_ACTIVE, 
> true);
> +
> +    sev_snp_guest->certs_timeout = 100;
>  }
>  
>  static void
> @@ -3387,6 +3724,7 @@ sev_snp_guest_finalize(Object *obj)
>      g_free(sev_snp_guest->id_auth_base64);
>      g_free(sev_snp_guest->id_auth);
>      g_free(sev_snp_guest->host_data);
> +    g_free(sev_snp_guest->certs_filename);
>  }
>  
>  /* guest info specific to sev-snp */
> diff --git a/target/i386/sev.h b/target/i386/sev.h
> index 7725f92e19..4d9e9b44b4 100644
> --- a/target/i386/sev.h
> +++ b/target/i386/sev.h
> @@ -15,6 +15,7 @@
>  #define I386_SEV_H
>  
>  #include "target/i386/svm.h"
> +#include "system/kvm.h"
>  
>  #ifndef CONFIG_USER_ONLY
>  #include CONFIG_DEVICES /* CONFIG_SEV */
> @@ -198,5 +199,5 @@ void pc_system_parse_sev_metadata(uint8_t *flash_ptr, 
> size_t flash_size);
>  
>  uint32_t sev_get_cbit_position(void);
>  uint32_t sev_get_reduced_phys_bits(void);
> -
> +int kvm_handle_snp_req_certs(CPUState *cpu, struct kvm_run *run);
>  #endif


Reply via email to