Re: [PATCH v10 016/108] KVM: TDX: create/destroy VM structure

Ackerley Tng
2023-01-03T18:17:26Z

Happy to help!

Nope it wasn't any special technique, I was working on the selftests and
made a mistake configuring the TD while initializing it.

While setting up struct kvm_tdx_init_vm, I did not copy the entire
struct kvm_cpuid2.

This reliably reproduces the crash:

--------

// SPDX-License-Identifier: GPL-2.0-only

#include "kvm_util_base.h"
#include <processor.h>

static int tdx_ioctl(int fd, int ioctl_no, uint32_t flags, void *data)
{
struct kvm_tdx_cmd tdx_cmd;

memset(&tdx_cmd, 0x0, sizeof(tdx_cmd));
tdx_cmd.id = ioctl_no;
tdx_cmd.flags = flags;
tdx_cmd.data = (uint64_t)data;
return ioctl(fd, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd);
}

#define XFEATURE_LBR 15
#define XFEATURE_XTILECFG 17
#define XFEATURE_XTILEDATA 18
#define XFEATURE_CET_U 11
#define XFEATURE_CET_S 12

#define XFEATURE_MASK_LBR (1 << XFEATURE_LBR)
#define XFEATURE_MASK_CET_U (1 << XFEATURE_CET_U)
#define XFEATURE_MASK_CET_S (1 << XFEATURE_CET_S)
#define XFEATURE_MASK_CET (XFEATURE_MASK_CET_U | XFEATURE_MASK_CET_S)
#define XFEATURE_MASK_XTILECFG (1 << XFEATURE_XTILECFG)
#define XFEATURE_MASK_XTILEDATA (1 << XFEATURE_XTILEDATA)
#define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILECFG |
XFEATURE_MASK_XTILEDATA)

static void apply_tdx_restrictions(struct kvm_cpuid2 *cpuid_data)
{
for (int i = 0; i < 100; i++) {
struct kvm_cpuid_entry2 *e = &cpuid_data->entries[i];

if (e->function == 0xd && e->index == 0) {
/*
* TDX module requires both XTILE_{CFG, DATA} to be set.
* Both bits are required for AMX to be functional.
*/
if ((e->eax & XFEATURE_MASK_XTILE) != XFEATURE_MASK_XTILE) {
e->eax &= ~XFEATURE_MASK_XTILE;
}
}

if (e->function == 0xd && e->index == 1) {
/*
* TDX doesn't support LBR yet.
* Disable bits from the XCR0 register.
*/
e->ecx &= ~XFEATURE_MASK_LBR;

/*
* TDX modules requires both CET_{U, S} to be set even
* if only one is supported.
*/
if (e->ecx & XFEATURE_MASK_CET)
e->ecx |= XFEATURE_MASK_CET;
}
}
}

void initialize_td_bad(struct kvm_vm *vm)
{
const struct kvm_cpuid2 *cpuid;
int rc;

/* No guest VMM controlled cpuid information yet. */
struct kvm_tdx_init_vm init_vm;

rc = kvm_check_cap(KVM_CAP_X2APIC_API);
TEST_ASSERT(rc, "TDX: KVM_CAP_X2APIC_API is not supported!");
rc = kvm_check_cap(KVM_CAP_SPLIT_IRQCHIP);
TEST_ASSERT(rc, "TDX: KVM_CAP_SPLIT_IRQCHIP is not supported!");

vm_enable_cap(vm, KVM_CAP_X2APIC_API,
KVM_X2APIC_API_USE_32BIT_IDS |
KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK);
vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);

/* Allocate and setup memory for the td guest. */
vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0, 0, 1, 0);

cpuid = kvm_get_supported_cpuid();
apply_tdx_restrictions((struct kvm_cpuid2 *) cpuid);

memset(&init_vm, 0, sizeof(init_vm));
init_vm.attributes = 0;

/*
* Should have been kvm_cpuid2_size(cpuid->nent) instead of
* sizeof(*cpuid)
*/
memcpy(&init_vm.cpuid, cpuid, sizeof(*cpuid));

rc = tdx_ioctl(vm->fd, KVM_TDX_INIT_VM, 0, &init_vm);
TEST_ASSERT(rc == 0, "KVM_TDX_INIT_VM failed: %d %d", rc, errno);
}

static int crash(void)
{
struct kvm_vm *vm;

/* Create a TD VM with no memory.*/
vm = ____vm_create(VM_MODE_DEFAULT, 0, KVM_X86_TDX_VM);

/* Allocate TD guest memory and initialize the TD.*/
initialize_td_bad(vm);

return 0;
}

int main(int argc, char **argv)
{
/* Disable stdout buffering */
setbuf(stdout, NULL);

return crash();
}