Add support for VMware port IO backdoor as secondary hypercall interface
- Dominant language
- Makefile
- Stars
- 814
- Forks
- 109
- PR merge metrics
- No merged PRs in 30d
Description
This ticket explores what's the status of implementing the Nyx hypercall API via the VMware port IO backdoor.
# kAFL agent
On the guest side, in [`libnyx_agent.c`](https://github.com/IntelLabs/kafl.targets/blob/master/linux-user/libnyx_agent/src/nyx_agent.c#L117), there is a dispatcher already implemented
~~~c
/**
* Execute hypercall depending on Nyx CPU type
*/
unsigned long hypercall(unsigned id, uintptr_t arg)
{
switch (nyx_cpu_type) {
case nyx_cpu_v1:
debug_printf("\t# vmcall(0x%x,0x%lx) ..\n", id, arg);
return kAFL_hypercall(id, arg);
case nyx_cpu_v2:
case nyx_cpu_none:
debug_printf("\t# vmcall(0x%x,0x%lx) skipped..\n", id, arg);
return 0;
case nyx_cpu_invalid:
default:
fprintf(stderr, "get_nyx_cpu_type() must be called first\n");
habort_msg("get_nyx_cpu_type() must be called first\n");
assert(false);
}
}
~~~
depending on the CPU type returned by CPUID.
~~~c
/**
* Get Nyx VMM type from CPUID
*/
static nyx_cpu_type_t _get_nyx_cpu_type(void)
{
uint32_t regs[4];
char str[17];
cpuid(KAFL_CPUID_IDENTIFIER, regs[0], regs[1], regs[2], regs[3]);
memcpy(str, regs, sizeof(regs));
str[16] = '\0';
//debug_printf("CPUID string: >>%s<<\n", str);
if (0 == strncmp(str, "NYX vCPU (PT)", sizeof(str))) {
return nyx_cpu_v1;
} else if (0 == strncmp(str, "NYX vCPU (NO-PT)", sizeof(str))) {
return nyx_cpu_v2;
} else {
return nyx_cpu_none;
}
}
~~~
# QEMU-Nyx
On the QEMU side, in [`kvm-all.c:kvm_cpu_exec()`](https://github.com/IntelLabs/kafl.qemu/blob/kafl_stable/accel/kvm/kvm-all.c#L2589), the handler for the VMware port forwarding the Nyx hypercalls seems to already be here
~~~c
switch (run->exit_reason) {
case KVM_EXIT_IO:
DPRINTF("handle_io\n");
#ifdef QEMU_NYX
// clang-format on
if (run->io.port == 0x5658 && run->io.size == 4 &&
*((uint32_t *)((uint8_t *)run + run->io.data_offset)) == 0x8080801f)
{
assert(kvm_state->nyx_no_pt_mode);
ret = handle_vmware_hypercall(run, cpu);
break;
}
// clang-format off
#endif
~~~
~~~c
static int handle_vmware_hypercall(struct kvm_run *run, CPUState *cpu)
{
kvm_arch_get_registers_fast(cpu);
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
return handle_kafl_hypercall(run, cpu, env->regs[R_EBX] + 100, env->regs[R_ECX]);
}
~~~
# Related
- on QEMU, the [`vmport`](https://www.qemu.org/docs/master/system/invocation.html?highlight=vmport) parameter toggles the emulation of the VMware backdoor. ([patch](https://listman.redhat.com/archives/libvir-list/2015-April/msg00000.html))

- on KVM, the vmware backdoor can be toggled with [`enable_vmware_backdoor=y`](https://patchwork.kernel.org/project/kvm/patch/1514134612-25857-2-git-send-email-liran.alon@oracle.com/) on the `kvm` module
@schumilo
- do you happen to have an existing implementation of the glude code necessary in the guest to issue hypercalls with the vmware backdoor ? Since the implementation exists in QEMU, I guest it was already working before ?
- can you detail a bit the existing code in QEMU ? I'm not clear on this line: `*((uint32_t *)((uint8_t *)run + run->io.data_offset)) == 0x8080801f)`. Also `handle_kafl_hypercall(run, cpu, env->regs[R_EBX] + 100, env->regs[R_ECX]);` why +100 ? 🤔
Thanks !
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.