From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754180AbbFAWyt (ORCPT ); Mon, 1 Jun 2015 18:54:49 -0400 Received: from mail-lb0-f178.google.com ([209.85.217.178]:33477 "EHLO mail-lb0-f178.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752852AbbFAWyk (ORCPT ); Mon, 1 Jun 2015 18:54:40 -0400 MIME-Version: 1.0 In-Reply-To: <556C8209.1030007@osg.samsung.com> References: <09a9916761e0a9e42d4922f147af45a0079cc1e8.1432936374.git.luto@kernel.org> <556C8209.1030007@osg.samsung.com> From: Andy Lutomirski Date: Mon, 1 Jun 2015 15:54:18 -0700 Message-ID: Subject: Re: [PATCH] x86_32, entry, selftests: Add a selftest for kernel entries from vm86 mode To: Shuah Khan Cc: Andy Lutomirski , Ingo Molnar , Jan Beulich , X86 ML , "linux-kernel@vger.kernel.org" Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Mon, Jun 1, 2015 at 9:02 AM, Shuah Khan wrote: > On 05/29/2015 03:58 PM, Andy Lutomirski wrote: >> Test a couple of special cases in 32-bit kernels for entries from >> vm86 mode. This will OOPS both old kernels due to a bug and and >> 4.1-rc5 due to a regression I introduced, and it should make sure >> that the SYSENTER-from-vm86-mode hack in the kernel keeps working. >> >> Tests: 394838c96013 x86/asm/entry/32: Fix user_mode() misuses >> Tests: 7ba554b5ac69 x86/asm/entry/32: Really make user_mode() work correctly for VM86 mode >> Signed-off-by: Andy Lutomirski >> --- >> >> Ingo, Shuah: I think this should go in through -tip. (In general, I think >> new x86 tests that don't have interesting interactions with the kselftest >> infrastructure should go in through -tip, especially tests such as this one >> that are related to recent regressions.) > > No problem going through tip. Could you please make sure > > "make kselftest" run from top level and > tools/testing/selftests/kselftest_install.sh > > don't break? Both 'make kselftest -j12 TARGETS=x86' and ../../../tools/testing/selftests/kselftest_install.sh work for me. (The .. thing is annoying -- would it make sense to fix it to work from the kernel tree root?) --Andy > > Once the above are verified, here is my > > Acked-by: Shuah Khan > > Thanks, > -- Shuah > >> >> tools/testing/selftests/x86/Makefile | 6 +- >> tools/testing/selftests/x86/entry_from_vm86.c | 114 ++++++++++++++++++++++++++ >> 2 files changed, 118 insertions(+), 2 deletions(-) >> create mode 100644 tools/testing/selftests/x86/entry_from_vm86.c >> >> diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile >> index 5bdb781163d1..9b0d8baf2934 100644 >> --- a/tools/testing/selftests/x86/Makefile >> +++ b/tools/testing/selftests/x86/Makefile >> @@ -5,8 +5,10 @@ include ../lib.mk >> .PHONY: all all_32 all_64 warn_32bit_failure clean >> >> TARGETS_C_BOTHBITS := sigreturn single_step_syscall >> +TARGETS_C_32BIT_ONLY := entry_from_vm86 >> >> -BINARIES_32 := $(TARGETS_C_BOTHBITS:%=%_32) >> +TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) >> +BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32) >> BINARIES_64 := $(TARGETS_C_BOTHBITS:%=%_64) >> >> CFLAGS := -O2 -g -std=gnu99 -pthread -Wall >> @@ -32,7 +34,7 @@ all_64: $(BINARIES_64) >> clean: >> $(RM) $(BINARIES_32) $(BINARIES_64) >> >> -$(TARGETS_C_BOTHBITS:%=%_32): %_32: %.c >> +$(TARGETS_C_32BIT_ALL:%=%_32): %_32: %.c >> $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl >> >> $(TARGETS_C_BOTHBITS:%=%_64): %_64: %.c >> diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c >> new file mode 100644 >> index 000000000000..5c38a187677b >> --- /dev/null >> +++ b/tools/testing/selftests/x86/entry_from_vm86.c >> @@ -0,0 +1,114 @@ >> +/* >> + * entry_from_vm86.c - tests kernel entries from vm86 mode >> + * Copyright (c) 2014-2015 Andrew Lutomirski >> + * >> + * This exercises a few paths that need to special-case vm86 mode. >> + * >> + * GPL v2. >> + */ >> + >> +#define _GNU_SOURCE >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +static unsigned long load_addr = 0x10000; >> +static int nerrs = 0; >> + >> +asm ( >> + ".pushsection .rodata\n\t" >> + ".type vmcode_bound, @object\n\t" >> + "vmcode:\n\t" >> + "vmcode_bound:\n\t" >> + ".code16\n\t" >> + "bound %ax, (2048)\n\t" >> + "int3\n\t" >> + "vmcode_sysenter:\n\t" >> + "sysenter\n\t" >> + ".size vmcode, . - vmcode\n\t" >> + "end_vmcode:\n\t" >> + ".code32\n\t" >> + ".popsection" >> + ); >> + >> +extern unsigned char vmcode[], end_vmcode[]; >> +extern unsigned char vmcode_bound[], vmcode_sysenter[]; >> + >> +static void do_test(struct vm86plus_struct *v86, unsigned long eip, >> + const char *text) >> +{ >> + long ret; >> + >> + printf("[RUN]\t%s from vm86 mode\n", text); >> + v86->regs.eip = eip; >> + ret = vm86(VM86_ENTER, v86); >> + >> + if (ret == -1 && errno == ENOSYS) { >> + printf("[SKIP]\tvm86 not supported\n"); >> + return; >> + } >> + >> + if (VM86_TYPE(ret) == VM86_INTx) { >> + char trapname[32]; >> + int trapno = VM86_ARG(ret); >> + if (trapno == 13) >> + strcpy(trapname, "GP"); >> + else if (trapno == 5) >> + strcpy(trapname, "BR"); >> + else if (trapno == 14) >> + strcpy(trapname, "PF"); >> + else >> + sprintf(trapname, "%d", trapno); >> + >> + printf("[OK]\tExited vm86 mode due to #%s\n", trapname); >> + } else if (VM86_TYPE(ret) == VM86_UNKNOWN) { >> + printf("[OK]\tExited vm86 mode due to unhandled GP fault\n"); >> + } else { >> + printf("[OK]\tExited vm86 mode due to type %ld, arg %ld\n", >> + VM86_TYPE(ret), VM86_ARG(ret)); >> + } >> +} >> + >> +int main(void) >> +{ >> + struct vm86plus_struct v86; >> + unsigned char *addr = mmap((void *)load_addr, 4096, >> + PROT_READ | PROT_WRITE | PROT_EXEC, >> + MAP_ANONYMOUS | MAP_PRIVATE, -1,0); >> + if (addr != (unsigned char *)load_addr) >> + err(1, "mmap"); >> + >> + memcpy(addr, vmcode, end_vmcode - vmcode); >> + addr[2048] = 2; >> + addr[2050] = 3; >> + >> + memset(&v86, 0, sizeof(v86)); >> + >> + v86.regs.cs = load_addr / 16; >> + v86.regs.ss = load_addr / 16; >> + v86.regs.ds = load_addr / 16; >> + v86.regs.es = load_addr / 16; >> + >> + assert((v86.regs.cs & 3) == 0); /* Looks like RPL = 0 */ >> + >> + /* #BR -- should deliver SIG??? */ >> + do_test(&v86, vmcode_bound - vmcode, "#BR"); >> + >> + /* SYSENTER -- should cause #GP or #UD depending on CPU */ >> + do_test(&v86, vmcode_sysenter - vmcode, "SYSENTER"); >> + >> + return (nerrs == 0 ? 0 : 1); >> +} >> > > > -- > Shuah Khan > Sr. Linux Kernel Developer > Open Source Innovation Group > Samsung Research America (Silicon Valley) > shuahkh@osg.samsung.com | (970) 217-8978 -- Andy Lutomirski AMA Capital Management, LLC