From patchwork Sun Dec 24 10:08:01 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arbel Moshe X-Patchwork-Id: 10131921 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id BC6596019C for ; Sun, 24 Dec 2017 10:09:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A620328C4D for ; Sun, 24 Dec 2017 10:09:21 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9AF4028C6A; Sun, 24 Dec 2017 10:09:21 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DC0AB28C4D for ; Sun, 24 Dec 2017 10:09:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752071AbdLXKJS (ORCPT ); Sun, 24 Dec 2017 05:09:18 -0500 Received: from userp2120.oracle.com ([156.151.31.85]:33198 "EHLO userp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751941AbdLXKJQ (ORCPT ); Sun, 24 Dec 2017 05:09:16 -0500 Received: from pps.filterd (userp2120.oracle.com [127.0.0.1]) by userp2120.oracle.com (8.16.0.21/8.16.0.21) with SMTP id vBOA9EW7001903; Sun, 24 Dec 2017 10:09:14 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2017-10-26; bh=Vcn/VFkWZZLFGDkX7UclTlqIOki6PA/UlnRxcunwbWA=; b=qaPfWyr5bovmzfAhY9n/an6u8D4lLjP7aaMSpCcNSspHPRWDj1OA3xeZAUQJIQaAVkHW DYHu0TQwnzlTzvmzWrIfDIIUThTD74x1vZqqBicX2lQSjNI0KtqZ3MmxJ6qjAtVIRxsd /ZO+cqLWPwPYONVaremZf5YgJJLGOOQbFUSGBsbb6pLJE/CzviJm0FJanDWH8nO+4cfW Nn19qadJNWpxrb22jBxHuTclI488F5lhpR+2z83s9xt/NDV/FXUBLvZPHlPUG11slkh/ I5/RxqiMBcXBksww2eIPd/jVwWPmzknFBDTNzp0UBJiwDLT01oa/zrjCyt8alR1tnnqZ lQ== Received: from userv0022.oracle.com (userv0022.oracle.com [156.151.31.74]) by userp2120.oracle.com with ESMTP id 2f2a66g056-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sun, 24 Dec 2017 10:09:14 +0000 Received: from userv0121.oracle.com (userv0121.oracle.com [156.151.31.72]) by userv0022.oracle.com (8.14.4/8.14.4) with ESMTP id vBOA9Dl2032250 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Sun, 24 Dec 2017 10:09:13 GMT Received: from abhmp0016.oracle.com (abhmp0016.oracle.com [141.146.116.22]) by userv0121.oracle.com (8.14.4/8.13.8) with ESMTP id vBOA9DwA031172; Sun, 24 Dec 2017 10:09:13 GMT Received: from spark.ravello.local (/213.57.127.2) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Sun, 24 Dec 2017 02:09:13 -0800 From: Arbel Moshe To: pbonzini@redhat.com, rkrcmar@redhat.com, kvm@vger.kernel.org Cc: idan.brown@oracle.com, liran.alon@oracle.com, Arbel Moshe , Konrad Rzeszutek Wilk Subject: [PATCH 5/5] x86: Add VMware backdoor unit test Date: Sun, 24 Dec 2017 12:08:01 +0200 Message-Id: <20171224100801.145806-6-arbel.moshe@oracle.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171224100801.145806-1-arbel.moshe@oracle.com> References: <20171224100801.145806-1-arbel.moshe@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=5900 definitions=8754 signatures=668650 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=0 malwarescore=0 phishscore=0 bulkscore=0 spamscore=0 mlxscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1711220000 definitions=main-1712240137 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add VMware backdoors unit test. VMware backdoors, is a PV interface VMware ESX and Workstation expose to their running VMs, in order to better operate in a virtualized environment. There are 2 main backdoor mechanisms: I/O ports & Pseduo-PMCs. VMware backdoor I/O ports: VMware expose a special I/O port which sends/gives ParaVirtualize info. The I/O port is accessible from User Mode, even if the TSS I/O permission bitmap states otherwise. VMware backdoor Pseduo-PMCs: VMware exposes 3 Pseduo-PMCs to its running VMS, that lets the VMs collect information regarding host time. For more info, see: www.vmware.com/files/pdf/techpaper/Timekeeping-In-VirtualMachines.pdf This unit test tests the functionality of these backdoors. They are tested both from User Mode and Kernel Mode, as they will be accessible running on ESX. Signed-off-by: Arbel Moshe Reviewed-by: Liran Alon Signed-off-by: Konrad Rzeszutek Wilk --- x86/Makefile.common | 1 + x86/unittests.cfg | 4 ++ x86/vmware_backdoors.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 x86/vmware_backdoors.c diff --git a/x86/Makefile.common b/x86/Makefile.common index cbd5847..f544636 100644 --- a/x86/Makefile.common +++ b/x86/Makefile.common @@ -56,6 +56,7 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \ $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \ $(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \ $(TEST_DIR)/hyperv_connections.flat \ + $(TEST_DIR)/vmware_backdoors.flat\ ifdef API tests-api = api/api-sample api/dirty-log api/dirty-log-perf diff --git a/x86/unittests.cfg b/x86/unittests.cfg index 91d1c75..5410177 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -150,6 +150,10 @@ file = pmu.flat extra_params = -cpu host check = /proc/sys/kernel/nmi_watchdog=0 +[vmware_backdoors] +file = vmware_backdoors.flat +extra_params = -machine vmport=on + [port80] file = port80.flat diff --git a/x86/vmware_backdoors.c b/x86/vmware_backdoors.c new file mode 100644 index 0000000..f718f16 --- /dev/null +++ b/x86/vmware_backdoors.c @@ -0,0 +1,191 @@ + +#include "x86/msr.h" +#include "x86/processor.h" +#include "x86/apic-defs.h" +#include "x86/apic.h" +#include "x86/desc.h" +#include "x86/isr.h" +#include "alloc.h" +#include "setjmp.h" +#include "usermode.h" +#include "fault_test.h" + +#include "libcflat.h" +#include + +#define VMWARE_BACKDOOR_PMC_HOST_TSC 0x10000 +#define VMWARE_BACKDOOR_PMC_REAL_TIME 0x10001 +#define VMWARE_BACKDOOR_PMC_APPARENT_TIME 0x10002 + +#define VMWARE_BACKDOOR_PORT 0x5658 +#define VMWARE_MAGIC 0x564D5868 + +#define VMPORT_CMD_GETVERSION 0x0a +#define VMPORT_CMD_ILLEGAL 0xfff + +#define VMPORT_DEFAULT_RETVAL 0xdeadbeef + +#define RANDOM_IO_PORT 0x1234 + +struct backdoor_port_result { + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; +}; + +static bool vmware_backdoor_port_callback(struct fault_test_arg *arg) +{ + struct backdoor_port_result *res = + (struct backdoor_port_result *) arg->retval; + + switch (arg->arg[2]) { + case VMPORT_CMD_GETVERSION: + return (res->rbx == VMWARE_MAGIC); + case VMPORT_CMD_ILLEGAL: + return (res->rbx == VMPORT_DEFAULT_RETVAL); + } + return false; +} + +static uint64_t vmware_backdoor_port(uint64_t vmport, uint64_t vmport_magic, + uint64_t command) +{ + struct backdoor_port_result *res = + (struct backdoor_port_result *) + malloc(sizeof(struct backdoor_port_result)); + + res->rax = VMPORT_DEFAULT_RETVAL; + res->rbx = VMPORT_DEFAULT_RETVAL; + res->rcx = VMPORT_DEFAULT_RETVAL; + res->rdx = VMPORT_DEFAULT_RETVAL; + + asm volatile( + "mov %[rax], %%rax\n\t" + "mov %[rdx], %%rdx\n\t" + "mov %[rcx], %%rcx\n\t" + "inl %%dx, %%eax\n\t" + : + "+a"(res->rax), + "+b"(res->rbx), + "+c"(res->rcx), + "+d"(res->rdx) + : + [rax]"m"(vmport_magic), + [rdx]"m"(vmport), + [rcx]"m"(command) + ); + + return (uint64_t) res; +} + +#define FAULT true +#define NO_FAULT false +#define USER_MODE true +#define KERNEL_MODE false + +#define RDPMC_ARG(n, m, sf) {.usermode = m, \ + .func = (test_fault_func) rdpmc, .fault_vector = GP_VECTOR, \ + .should_fault = sf, .arg = {n, 0, 0, 0}, .callback = NULL} + +#define RDPMC_TEST(name, a, m, sf) FAULT_TEST("rdpmc_test: "name, \ + RDPMC_ARG(a, m, sf)) + +#define PORT_ARG(a, b, c, m, sf) {.usermode = m, \ + .func = (test_fault_func) vmware_backdoor_port, \ + .fault_vector = GP_VECTOR, .should_fault = sf, .arg = {a, b, c, 0}, \ + .callback = vmware_backdoor_port_callback} + +#define PORT_TEST(name, a, b, c, m, sf) FAULT_TEST("port_test: "name, \ + PORT_ARG(a, b, c, m, sf)) + + +struct fault_test vmware_backdoor_tests[] = { + RDPMC_TEST("HOST_TSC kernel", VMWARE_BACKDOOR_PMC_HOST_TSC, + KERNEL_MODE, NO_FAULT), + RDPMC_TEST("REAL_TIME kernel", VMWARE_BACKDOOR_PMC_REAL_TIME, + KERNEL_MODE, NO_FAULT), + RDPMC_TEST("APPARENT_TIME kernel", VMWARE_BACKDOOR_PMC_APPARENT_TIME, + KERNEL_MODE, NO_FAULT), + RDPMC_TEST("HOST_TSC user", VMWARE_BACKDOOR_PMC_HOST_TSC, + USER_MODE, NO_FAULT), + RDPMC_TEST("REAL_TIME user", VMWARE_BACKDOOR_PMC_REAL_TIME, + USER_MODE, NO_FAULT), + RDPMC_TEST("APPARENT_TIME user", VMWARE_BACKDOOR_PMC_APPARENT_TIME, + USER_MODE, NO_FAULT), + RDPMC_TEST("RANDOM PMC user", 0xfff, USER_MODE, FAULT), + + PORT_TEST("CMD_GETVERSION user", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC, + VMPORT_CMD_GETVERSION, USER_MODE, NO_FAULT), + PORT_TEST("CMD_GETVERSION kernel", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC, + VMPORT_CMD_GETVERSION, KERNEL_MODE, NO_FAULT), + PORT_TEST("CMD_ILLEGAL user", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC, + VMPORT_CMD_ILLEGAL, USER_MODE, NO_FAULT), + PORT_TEST("RANDOM port user", RANDOM_IO_PORT, VMWARE_MAGIC, 0xfff, + USER_MODE, FAULT), + { NULL }, +}; + +/* + * Set TSS IO Perm to throw GP on RANDOM_IO_PORT and VMWARE_BACKDOOR_PORT + * from User Mode + */ +static void set_tss_ioperm(void) +{ + struct descriptor_table_ptr gdt; + struct segment_desc64 *gdt_table; + struct segment_desc64 *tss_entry; + u16 tr = 0; + tss64_t *tss; + unsigned char *ioperm_bitmap; + uint64_t tss_base; + + sgdt(&gdt); + tr = str(); + gdt_table = (struct segment_desc64 *) gdt.base; + tss_entry = &gdt_table[tr / sizeof(struct segment_desc64)]; + tss_base = ((uint64_t) tss_entry->base1 | + ((uint64_t) tss_entry->base2 << 16) | + ((uint64_t) tss_entry->base3 << 24) | + ((uint64_t) tss_entry->base4 << 32)); + tss = (tss64_t *)tss_base; + tss->iomap_base = sizeof(*tss); + ioperm_bitmap = ((unsigned char *)tss+tss->iomap_base); + + /* We want GP on RANDOM_IO_PORT and VMWARE_BACKDOOR_PORT */ + ioperm_bitmap[RANDOM_IO_PORT / 8] |= + 1 << (RANDOM_IO_PORT % 8); + ioperm_bitmap[VMWARE_BACKDOOR_PORT / 8] |= + 1 << (VMWARE_BACKDOOR_PORT % 8); + *(uint64_t *)tss_entry &= ~DESC_BUSY; + + /* Update TSS */ + ltr(tr); +} + +static void check_vmware_backdoors(void) +{ + int i; + + /* Disable Permissions for IO PORTS */ + set_tss_ioperm(); + /* Disable Permission to run rdpmc from user mode */ + write_cr4(read_cr4() & ~X86_CR4_PCE); + + report_prefix_push("vmware_backdoors"); + + for (i = 0; vmware_backdoor_tests[i].name != NULL; i++) + test_run(&vmware_backdoor_tests[i]); + + report_prefix_pop(); +} + +int main(int ac, char **av) +{ + setup_vm(); + setup_idt(); + + check_vmware_backdoors(); + + return report_summary(); +}