From patchwork Thu Jul 13 14:08:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Luczaj X-Patchwork-Id: 13312446 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BAC7CC0015E for ; Thu, 13 Jul 2023 15:54:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232503AbjGMPyw (ORCPT ); Thu, 13 Jul 2023 11:54:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52470 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229689AbjGMPyv (ORCPT ); Thu, 13 Jul 2023 11:54:51 -0400 X-Greylist: delayed 6147 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Thu, 13 Jul 2023 08:54:49 PDT Received: from mailtransmit05.runbox.com (mailtransmit05.runbox.com [IPv6:2a0c:5a00:149::26]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2D89D26AE for ; Thu, 13 Jul 2023 08:54:49 -0700 (PDT) Received: from mailtransmit03.runbox ([10.9.9.163] helo=aibo.runbox.com) by mailtransmit05.runbox.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.93) (envelope-from ) id 1qJx3L-000wFe-Gy; Thu, 13 Jul 2023 16:12:19 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rbox.co; s=selector1; h=Content-Transfer-Encoding:MIME-Version:Message-ID:Date:Subject :Cc:To:From; bh=srfvtAuZTlZfeDu1t/9mVfKjQ9ungTgfaR0/nPFqtM4=; b=XMOqjpwADu7xn rTS0vksQZJ3aQlMljzZ4WUnqf9IP/TrtJwDVpqmqXkZK5bY6g4QFPVLxlSvrqAb12yuH2X284XmOX uVKs64ClwaJemicqBm9eOD8DAcgZswClYFwOa/p5+oBHSz4ipWrakmqc5+jcPYEvb1FwbfHvIZ9qg cQmlSPNgHqy0VeFE2T3pBFs526edFUDTc+Eye9zRl8wXiVvWPvmdFbI3/ZNccJhZgP+8pDUnFwhRW 6F2GgIYoSxX9KlDzQMvJSkBb41h1GhXlt4qu/0FpGc8gCyHAfbbcUlX/VEVeHQ8B6F9NLTI5iIaKo OPBBDe7LIv7McBw5DM4vw==; Received: from [10.9.9.72] (helo=submission01.runbox) by mailtransmit03.runbox with esmtp (Exim 4.86_2) (envelope-from ) id 1qJx3K-0008I0-OZ; Thu, 13 Jul 2023 16:12:19 +0200 Received: by submission01.runbox with esmtpsa [Authenticated ID (604044)] (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) id 1qJx3C-0001y6-Up; Thu, 13 Jul 2023 16:12:11 +0200 From: Michal Luczaj To: kvm@vger.kernel.org Cc: seanjc@google.com, pbonzini@redhat.com, Michal Luczaj Subject: [kvm-unit-tests RFC PATCH] x86/emulator: Test indirect CALL (gpa_available) Date: Thu, 13 Jul 2023 16:08:01 +0200 Message-ID: <20230713141136.1179342-1-mhal@rbox.co> X-Mailer: git-send-email 2.41.0 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org It seems em_call_near_abs() is missing a TwoMemOp flag. If there's a match between ~PAGE_MASK (lower 12) bits of - address of memory storing CALL's target, and - stack pointer at the time of pushing the return address, emulator, while pushing the return address, will skip GVA->GPA walk and use GPA provided by nPF. See arch/x86/kvm/x86.c:emulator_read_write_onepage(). Problem is that nPF came from reading CALL's SrcMem (pointer to CALL's target), so the "push" will overwrite CALL's SrcMem, not touching the stack at all. Then RET comes along and attempts to pop the return address, which was never written. I guess it's hight time I admit I have no idea if such indirect CALL + nPF setup was meant to be supported and/or this has any real world consequences :) That said, here's a KUT testcase where the bamboozled emulator makes RET twist the execution flow. Please let me know if this is worth submitting a TwoMemOp patch. em_call_far() appears to have the same "problem". Signed-off-by: Michal Luczaj --- x86/emulator.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/x86/emulator.c b/x86/emulator.c index ad94374..425f838 100644 --- a/x86/emulator.c +++ b/x86/emulator.c @@ -787,6 +787,49 @@ static void test_mov_pop_ss_code_db(void) handle_exception(DB_VECTOR, old_db_handler); } +static void test_indirect_call(void) +{ + long page1, page2, old_sp, sp, dest, tmp; + int status; + + page1 = (long)vmap(IORAM_BASE_PHYS, PAGE_SIZE * 2); + page2 = page1 + PAGE_SIZE; + + sp = page1 + PAGE_SIZE; + dest = page2 + PAGE_SIZE - sizeof(dest); + + assert(((sp - sizeof(sp)) & ~PAGE_MASK) == (dest & ~PAGE_MASK)); + + asm volatile("mov %%"R "sp, %[old_sp]\n\t" + "mov %[sp], %%"R "sp\n\t" + + "lea Lret_diverted, %0\n\t" + "mov %0, -"S"(%%"R "sp)\n\t" + + "lea Lcall_target, %0\n\t" + "mov %0, (%[dest])\n\t" + + "mov $-1, %[status]\n\t" + "call *(%[dest])\n\t" + "jmp Lout\n\t" + + "Lcall_target:\n\t" + "endbr" xstr(BITS_PER_LONG)"\n\t" + "mov $0, %[status]\n\t" + "ret\n\t" + + "Lret_diverted:\n\t" + "mov $1, %[status]\n\t" + + "Lout:\n\t" + "mov %[old_sp], %%"R "sp\n\t" + : "=&r"(tmp), [old_sp]"=&r"(old_sp), [status]"=&r"(status) + : [sp]"r"(sp), [dest]"r"(dest) + : "memory"); + + report(!status, "indirect call (gpa_val), status = %d", status); +} + int main(void) { void *mem; @@ -834,6 +877,7 @@ int main(void) test_string_io_mmio(mem); test_illegal_movbe(); test_mov_pop_ss_code_db(); + test_indirect_call(); #ifdef __x86_64__ test_emulator_64(mem);