From patchwork Fri Dec 7 12:47:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ahmed Abd El Mawgood X-Patchwork-Id: 10718091 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 222EA1759 for ; Fri, 7 Dec 2018 12:55:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 12E662DF26 for ; Fri, 7 Dec 2018 12:55:51 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0624E2E006; Fri, 7 Dec 2018 12:55:51 +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=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id 3AFB52DF26 for ; Fri, 7 Dec 2018 12:55:49 +0000 (UTC) Received: (qmail 9860 invoked by uid 550); 7 Dec 2018 12:55:42 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Delivered-To: moderator for kernel-hardening@lists.openwall.com Received: (qmail 1673 invoked from network); 7 Dec 2018 12:49:03 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mena-vt-edu.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=DU7M5piB0Rvr3KyQYQ6V1yh0wa36ooPj9QZW0CCD+Y8=; b=cSU1cVB9KCuBGlEeWVp6IcB3lNQiouoLV/w/JRBvclbuTZthEsJ6tnxD6hSXO2+4dK 8JC2tibVV0lv6hFG2jpXY+wLTXKpXT9I+ApY51qsiPLsoDJiMeoK3tmPP4cMVE/3Ixsm 2H03FCopLGrTTIfAxUlFP7ndXtBdMJpLqvLXtYrD8Y3P4yh+vvFwT0jMhoghr3VR0h4X Pu3URCe6HknbBOry1QaRvs1P1wAgMKoYJ64hnxjHdmLLVeTyS2xQ96tkKkDqPV6qcOMp VJ98RFEyhkixt/wdsrLjYLlhHEKp0t8I5I0DYqNRsnH01O0uGugvZZHo2Oc76ZSjcXVq CxSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=DU7M5piB0Rvr3KyQYQ6V1yh0wa36ooPj9QZW0CCD+Y8=; b=ikX12pSDcGPOYFSpKFYGbOm5KwQGFxci5rzDS6Gu6E5tnrMUBh/DKTRWWhIInW6ptl LSG08CxO9vYJLi8IgyzJIcclWhicn5J1lrHoZWLhiXF+MEkjsgHlD0aq9SLcR7LB2tZ2 K4vS6OCoxN+dUunyct8UQbE5VJ5U77RaCK2tN3JHGWNFardaGwcU1N66CYLGkpVjQb0q DflAGRbM0Le3Z+9cIS256nM9toEB8xB/WjeryKlhoIimbbtDXXvpdBGNaEgmo6YF3xxL LqnMcYo3C1h9F1BuQeOiL076XgIBXA139rZANFS1hL1p/NsARlHE03Py8goDA1USEAJL rU1A== X-Gm-Message-State: AA+aEWZVdAIi60OIbRaGjlahTP/wqCZx+NjLCiUuMpxknuL5FejNx/Oo 5UnJ1Fci43UM0yHul4nr3Dc0oA== X-Google-Smtp-Source: AFSGD/VD5A9bP8tcLxrmke4ui26mgs0SJBgedL/b6iChfzDt0Fm09UUCW7OdnezygTMA0WRirXDUIA== X-Received: by 2002:a1c:544f:: with SMTP id p15mr2079564wmi.37.1544186932211; Fri, 07 Dec 2018 04:48:52 -0800 (PST) From: Ahmed Abd El Mawgood To: Paolo Bonzini , rkrcmar@redhat.com, Jonathan Corbet , Thomas Gleixner , Ingo Molnar , Borislav Petkov , hpa@zytor.com, x86@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, ahmedsoliman0x666@gmail.com, ovich00@gmail.com, kernel-hardening@lists.openwall.com, nigel.edwards@hpe.com, Boris Lukashev , Igor Stoppa Cc: Ahmed Abd El Mawgood Subject: [PATCH 01/10] KVM: State whether memory should be freed in kvm_free_memslot Date: Fri, 7 Dec 2018 14:47:54 +0200 Message-Id: <20181207124803.10828-2-ahmedsoliman@mena.vt.edu> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> References: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> MIME-Version: 1.0 X-Virus-Scanned: ClamAV using ClamSMTP The conditions upon which kvm_free_memslot are kind of ad-hock, it will be hard to extend memslot with allocatable data that needs to be freed, so I replaced the current mechanism by clear flag that states if the memory slot should be freed. Signed-off-by: Ahmed Abd El Mawgood --- virt/kvm/kvm_main.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 2679e476b6..039c1ef9a7 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -549,9 +549,10 @@ static void kvm_destroy_dirty_bitmap(struct kvm_memory_slot *memslot) * Free any memory in @free but not in @dont. */ static void kvm_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free, - struct kvm_memory_slot *dont) + struct kvm_memory_slot *dont, + enum kvm_mr_change change) { - if (!dont || free->dirty_bitmap != dont->dirty_bitmap) + if (change == KVM_MR_DELETE) kvm_destroy_dirty_bitmap(free); kvm_arch_free_memslot(kvm, free, dont); @@ -567,7 +568,7 @@ static void kvm_free_memslots(struct kvm *kvm, struct kvm_memslots *slots) return; kvm_for_each_memslot(memslot, slots) - kvm_free_memslot(kvm, memslot, NULL); + kvm_free_memslot(kvm, memslot, NULL, KVM_MR_DELETE); kvfree(slots); } @@ -1063,14 +1064,14 @@ int __kvm_set_memory_region(struct kvm *kvm, kvm_arch_commit_memory_region(kvm, mem, &old, &new, change); - kvm_free_memslot(kvm, &old, &new); + kvm_free_memslot(kvm, &old, &new, change); kvfree(old_memslots); return 0; out_slots: kvfree(slots); out_free: - kvm_free_memslot(kvm, &new, &old); + kvm_free_memslot(kvm, &new, &old, change); out: return r; } From patchwork Fri Dec 7 12:47:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ahmed Abd El Mawgood X-Patchwork-Id: 10718093 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C467E1750 for ; Fri, 7 Dec 2018 12:56:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B421D2DFEC for ; Fri, 7 Dec 2018 12:56:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A68F92E00E; Fri, 7 Dec 2018 12:56:00 +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=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id 63DB42DFEC for ; Fri, 7 Dec 2018 12:55:59 +0000 (UTC) Received: (qmail 10127 invoked by uid 550); 7 Dec 2018 12:55:45 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Delivered-To: moderator for kernel-hardening@lists.openwall.com Received: (qmail 1754 invoked from network); 7 Dec 2018 12:49:08 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mena-vt-edu.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=gaEl9B+1fs5S3TQoH2KhHb3ZJ2VSYAnXotEb17ocZSY=; b=oZHFny5AgpoiZULh1yYM+egFIww1rygmpHkoXI+D0CcLC2JwJTaDD8Kt15Wxc3Hnc5 akZDh9gmX8HWr85IUpkbDooPXlwkP0hliQVSWKyYuMlmn5jDu0hInPl2V8VHVbSZWB39 YnIw+jyhFH6WfdspwyrTw/U3Iav5Y2Wp/BwzuP7oWdeUjX5IbE0M9a5dk7Oi86vehHAe WYxDMiflh3aHfmTHQhE0yvJixTt/u3MWRSc+U7py4TcLr3Yn7mDAIzkl4vl16+/uY8BV JP0ffub73j1l5ae3m+UgILHO+Ydwtk1uLI78OnYw1G2yp2ul8UFIt/E0s/+SBnrO6hye H9zg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=gaEl9B+1fs5S3TQoH2KhHb3ZJ2VSYAnXotEb17ocZSY=; b=mXQkbJFAZNmWubFnlx4j+TzFxjXlECovd+hI5yT7l/v4kQwnYo4IckQN4lk/MoDhpH XhmTAHiKZcwxzRS8FBGXJcZA6kSthKnabKUqn8Zvw/mFJnmCYRCv1cW3H+dKP3bKQaZh ANmw18CLUvYyeJYHQcyJL90P9Rb+ihyZ7raLtkApt7qW5+PyrLKSHlbIrUJxfIwTdgfY 9ginDLxLiBPeCaGD42T7l1HIJaQO7bKM4k+jj6ufQkDP3MPOuUOajg+cpfXCmyUpakkh zC6S6gIrv/bkAxRix5XL3QWB3D8mVQy7KA7XTRKFyeWUfy6Xl1hKwqbZYKQAJXAUMmtn hUQw== X-Gm-Message-State: AA+aEWZ1lHNjXoAihYe+gP9uqQVNA1jIFN3K7RwRqf8tXw48mI8FT5kj 94S+BzeDOPPj7VLbbc4gOmVE6w== X-Google-Smtp-Source: AFSGD/V8u7Pc6TiTxTpXvK0xrD0lAvavKdeiWpCwIDXtVBtXh5+16jKAxEgR3z+pm3Jyx+3tIxjTLA== X-Received: by 2002:a1c:848c:: with SMTP id g134mr1965101wmd.93.1544186937074; Fri, 07 Dec 2018 04:48:57 -0800 (PST) From: Ahmed Abd El Mawgood To: Paolo Bonzini , rkrcmar@redhat.com, Jonathan Corbet , Thomas Gleixner , Ingo Molnar , Borislav Petkov , hpa@zytor.com, x86@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, ahmedsoliman0x666@gmail.com, ovich00@gmail.com, kernel-hardening@lists.openwall.com, nigel.edwards@hpe.com, Boris Lukashev , Igor Stoppa Cc: Ahmed Abd El Mawgood Subject: [PATCH 02/10] KVM: X86: Add arbitrary data pointer in kvm memslot iterator functions Date: Fri, 7 Dec 2018 14:47:55 +0200 Message-Id: <20181207124803.10828-3-ahmedsoliman@mena.vt.edu> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> References: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> MIME-Version: 1.0 X-Virus-Scanned: ClamAV using ClamSMTP This will help sharing data into the slot_level_handler callback. In my case I need to a share a counter for the pages traversed to use it in some bitmap. Being able to send arbitrary memory pointer into the slot_level_handler callback made it easy. Signed-off-by: Ahmed Abd El Mawgood --- arch/x86/kvm/mmu.c | 65 ++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 7c03c0f354..b67d743c33 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1492,7 +1492,7 @@ static bool spte_write_protect(u64 *sptep, bool pt_protect) static bool __rmap_write_protect(struct kvm *kvm, struct kvm_rmap_head *rmap_head, - bool pt_protect) + bool pt_protect, void *data) { u64 *sptep; struct rmap_iterator iter; @@ -1531,7 +1531,8 @@ static bool wrprot_ad_disabled_spte(u64 *sptep) * - W bit on ad-disabled SPTEs. * Returns true iff any D or W bits were cleared. */ -static bool __rmap_clear_dirty(struct kvm *kvm, struct kvm_rmap_head *rmap_head) +static bool __rmap_clear_dirty(struct kvm *kvm, struct kvm_rmap_head *rmap_head, + void *data) { u64 *sptep; struct rmap_iterator iter; @@ -1557,7 +1558,8 @@ static bool spte_set_dirty(u64 *sptep) return mmu_spte_update(sptep, spte); } -static bool __rmap_set_dirty(struct kvm *kvm, struct kvm_rmap_head *rmap_head) +static bool __rmap_set_dirty(struct kvm *kvm, struct kvm_rmap_head *rmap_head, + void *data) { u64 *sptep; struct rmap_iterator iter; @@ -1589,7 +1591,7 @@ static void kvm_mmu_write_protect_pt_masked(struct kvm *kvm, while (mask) { rmap_head = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask), PT_PAGE_TABLE_LEVEL, slot); - __rmap_write_protect(kvm, rmap_head, false); + __rmap_write_protect(kvm, rmap_head, false, NULL); /* clear the first set bit */ mask &= mask - 1; @@ -1615,7 +1617,7 @@ void kvm_mmu_clear_dirty_pt_masked(struct kvm *kvm, while (mask) { rmap_head = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask), PT_PAGE_TABLE_LEVEL, slot); - __rmap_clear_dirty(kvm, rmap_head); + __rmap_clear_dirty(kvm, rmap_head, NULL); /* clear the first set bit */ mask &= mask - 1; @@ -1668,7 +1670,8 @@ bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm, for (i = PT_PAGE_TABLE_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) { rmap_head = __gfn_to_rmap(gfn, i, slot); - write_protected |= __rmap_write_protect(kvm, rmap_head, true); + write_protected |= __rmap_write_protect(kvm, rmap_head, true, + NULL); } return write_protected; @@ -1682,7 +1685,8 @@ static bool rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn) return kvm_mmu_slot_gfn_write_protect(vcpu->kvm, slot, gfn); } -static bool kvm_zap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head) +static bool kvm_zap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head, + void *data) { u64 *sptep; struct rmap_iterator iter; @@ -1702,7 +1706,7 @@ static int kvm_unmap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head, struct kvm_memory_slot *slot, gfn_t gfn, int level, unsigned long data) { - return kvm_zap_rmapp(kvm, rmap_head); + return kvm_zap_rmapp(kvm, rmap_head, NULL); } static int kvm_set_pte_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head, @@ -5514,13 +5518,15 @@ void kvm_mmu_uninit_vm(struct kvm *kvm) } /* The return value indicates if tlb flush on all vcpus is needed. */ -typedef bool (*slot_level_handler) (struct kvm *kvm, struct kvm_rmap_head *rmap_head); +typedef bool (*slot_level_handler) (struct kvm *kvm, + struct kvm_rmap_head *rmap_head, void *data); /* The caller should hold mmu-lock before calling this function. */ static __always_inline bool slot_handle_level_range(struct kvm *kvm, struct kvm_memory_slot *memslot, slot_level_handler fn, int start_level, int end_level, - gfn_t start_gfn, gfn_t end_gfn, bool lock_flush_tlb) + gfn_t start_gfn, gfn_t end_gfn, bool lock_flush_tlb, + void *data) { struct slot_rmap_walk_iterator iterator; bool flush = false; @@ -5528,7 +5534,7 @@ slot_handle_level_range(struct kvm *kvm, struct kvm_memory_slot *memslot, for_each_slot_rmap_range(memslot, start_level, end_level, start_gfn, end_gfn, &iterator) { if (iterator.rmap) - flush |= fn(kvm, iterator.rmap); + flush |= fn(kvm, iterator.rmap, data); if (need_resched() || spin_needbreak(&kvm->mmu_lock)) { if (flush && lock_flush_tlb) { @@ -5550,36 +5556,36 @@ slot_handle_level_range(struct kvm *kvm, struct kvm_memory_slot *memslot, static __always_inline bool slot_handle_level(struct kvm *kvm, struct kvm_memory_slot *memslot, slot_level_handler fn, int start_level, int end_level, - bool lock_flush_tlb) + bool lock_flush_tlb, void *data) { return slot_handle_level_range(kvm, memslot, fn, start_level, end_level, memslot->base_gfn, memslot->base_gfn + memslot->npages - 1, - lock_flush_tlb); + lock_flush_tlb, data); } static __always_inline bool slot_handle_all_level(struct kvm *kvm, struct kvm_memory_slot *memslot, - slot_level_handler fn, bool lock_flush_tlb) + slot_level_handler fn, bool lock_flush_tlb, void *data) { return slot_handle_level(kvm, memslot, fn, PT_PAGE_TABLE_LEVEL, - PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb); + PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb, data); } static __always_inline bool slot_handle_large_level(struct kvm *kvm, struct kvm_memory_slot *memslot, - slot_level_handler fn, bool lock_flush_tlb) + slot_level_handler fn, bool lock_flush_tlb, void *data) { return slot_handle_level(kvm, memslot, fn, PT_PAGE_TABLE_LEVEL + 1, - PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb); + PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb, data); } static __always_inline bool slot_handle_leaf(struct kvm *kvm, struct kvm_memory_slot *memslot, - slot_level_handler fn, bool lock_flush_tlb) + slot_level_handler fn, bool lock_flush_tlb, void *data) { return slot_handle_level(kvm, memslot, fn, PT_PAGE_TABLE_LEVEL, - PT_PAGE_TABLE_LEVEL, lock_flush_tlb); + PT_PAGE_TABLE_LEVEL, lock_flush_tlb, data); } void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end) @@ -5601,7 +5607,7 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end) slot_handle_level_range(kvm, memslot, kvm_zap_rmapp, PT_PAGE_TABLE_LEVEL, PT_MAX_HUGEPAGE_LEVEL, - start, end - 1, true); + start, end - 1, true, NULL); } } @@ -5609,9 +5615,10 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end) } static bool slot_rmap_write_protect(struct kvm *kvm, - struct kvm_rmap_head *rmap_head) + struct kvm_rmap_head *rmap_head, + void *data) { - return __rmap_write_protect(kvm, rmap_head, false); + return __rmap_write_protect(kvm, rmap_head, false, data); } void kvm_mmu_slot_remove_write_access(struct kvm *kvm, @@ -5621,7 +5628,7 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, spin_lock(&kvm->mmu_lock); flush = slot_handle_all_level(kvm, memslot, slot_rmap_write_protect, - false); + false, NULL); spin_unlock(&kvm->mmu_lock); /* @@ -5647,7 +5654,8 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, } static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm, - struct kvm_rmap_head *rmap_head) + struct kvm_rmap_head *rmap_head, + void *data) { u64 *sptep; struct rmap_iterator iter; @@ -5685,7 +5693,7 @@ void kvm_mmu_zap_collapsible_sptes(struct kvm *kvm, /* FIXME: const-ify all uses of struct kvm_memory_slot. */ spin_lock(&kvm->mmu_lock); slot_handle_leaf(kvm, (struct kvm_memory_slot *)memslot, - kvm_mmu_zap_collapsible_spte, true); + kvm_mmu_zap_collapsible_spte, true, NULL); spin_unlock(&kvm->mmu_lock); } @@ -5695,7 +5703,7 @@ void kvm_mmu_slot_leaf_clear_dirty(struct kvm *kvm, bool flush; spin_lock(&kvm->mmu_lock); - flush = slot_handle_leaf(kvm, memslot, __rmap_clear_dirty, false); + flush = slot_handle_leaf(kvm, memslot, __rmap_clear_dirty, false, NULL); spin_unlock(&kvm->mmu_lock); lockdep_assert_held(&kvm->slots_lock); @@ -5718,7 +5726,7 @@ void kvm_mmu_slot_largepage_remove_write_access(struct kvm *kvm, spin_lock(&kvm->mmu_lock); flush = slot_handle_large_level(kvm, memslot, slot_rmap_write_protect, - false); + false, NULL); spin_unlock(&kvm->mmu_lock); /* see kvm_mmu_slot_remove_write_access */ @@ -5735,7 +5743,8 @@ void kvm_mmu_slot_set_dirty(struct kvm *kvm, bool flush; spin_lock(&kvm->mmu_lock); - flush = slot_handle_all_level(kvm, memslot, __rmap_set_dirty, false); + flush = slot_handle_all_level(kvm, memslot, __rmap_set_dirty, false, + NULL); spin_unlock(&kvm->mmu_lock); lockdep_assert_held(&kvm->slots_lock); From patchwork Fri Dec 7 12:47:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ahmed Abd El Mawgood X-Patchwork-Id: 10718095 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9E5F91750 for ; Fri, 7 Dec 2018 12:56:16 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8F32D2DFEC for ; Fri, 7 Dec 2018 12:56:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 836992E00E; Fri, 7 Dec 2018 12:56:16 +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=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id B47AD2DFEC for ; Fri, 7 Dec 2018 12:56:15 +0000 (UTC) Received: (qmail 11889 invoked by uid 550); 7 Dec 2018 12:55:54 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Delivered-To: moderator for kernel-hardening@lists.openwall.com Received: (qmail 1815 invoked from network); 7 Dec 2018 12:49:13 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mena-vt-edu.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=qskwDCENsUJ4XJZgk7mw/D1NJ3EoY/jK2YNM77334Jg=; b=eBzgdhktIQ137s6FC7u+gCPBBBDYqLbuh6vzpN/BbPDS8ZmYTwukPjotz750UMPraN 9HElqnTsb3BVtqBDTmatcs6c5vRRC6ySaruowAOc/ZDEVkf8Ba0b6lh1zZwRFTrY9hhr 5MsheYQX6J4rTN0AyUyjB6thGWbLL3fcwC++9dqW6NJncg/te3AAKOIsfaPNXs4ON0TN O2EPUrg5aM3H2zIUOwdZgzNB7y3LJeDGitoPb514EJhQFRWIAT6hVpiuu7F8dMDWc4tM d3pVVADpadqjuH41NgKjOei5dzGkHqnjGFJpWPZyxQVktCEUlB44/Gy6K2LTYgOP5nv7 2MjA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=qskwDCENsUJ4XJZgk7mw/D1NJ3EoY/jK2YNM77334Jg=; b=oVI69b8UWNEBCNm2tqY7tKmOlzcG4+CI/8vAT/BHxLRJUiqKvW7eKfeMz7UEIeGLRk 9Dk7dCEEaGcKfXUXuTEelsObdWSVa66iwimQXISdBaqfmeqZ3dJiE7cEUo67TyY0GjCv BKA+7a5YmrMao6GPbpP8HSFMwzna/bbm4OcZw1ShTm2834Kek+oZ1RdWWFr8nquBGRQ5 gQeqvxhHjK3lyIfxf6RfaE10eJXL744lZ+Juldo5ysLA++SUaXqeygnbc+q3oVyPsfmV B03GU/YYHCPpsuDGjU2XgQvSsWiNqIPYTnztQ5vxlDZb427y1h1nSIIpEXOBaB506SQP X5Ew== X-Gm-Message-State: AA+aEWYLI8qmRAb20iSLWp8G/UJWpoYBI7K3iXZodbrUZpU7yCdEwxiY KOwk6gzsoOT4GB7FeMPCpzN9Uw== X-Google-Smtp-Source: AFSGD/XonZe40VF9RnZ4mhjjnNirD7PlzbAwQIiqaTMt5AApa7uw7RM0qOskDpWMLKRL1BmCis9VEA== X-Received: by 2002:adf:a4d9:: with SMTP id h25mr1582875wrb.167.1544186942211; Fri, 07 Dec 2018 04:49:02 -0800 (PST) From: Ahmed Abd El Mawgood To: Paolo Bonzini , rkrcmar@redhat.com, Jonathan Corbet , Thomas Gleixner , Ingo Molnar , Borislav Petkov , hpa@zytor.com, x86@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, ahmedsoliman0x666@gmail.com, ovich00@gmail.com, kernel-hardening@lists.openwall.com, nigel.edwards@hpe.com, Boris Lukashev , Igor Stoppa Cc: Ahmed Abd El Mawgood Subject: [PATCH 03/10] KVM: X86: Add helper function to convert SPTE to GFN Date: Fri, 7 Dec 2018 14:47:56 +0200 Message-Id: <20181207124803.10828-4-ahmedsoliman@mena.vt.edu> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> References: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> MIME-Version: 1.0 X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Ahmed Abd El Mawgood --- arch/x86/kvm/mmu.c | 7 +++++++ arch/x86/kvm/mmu.h | 1 + 2 files changed, 8 insertions(+) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index b67d743c33..a300e4acb8 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1024,6 +1024,13 @@ static gfn_t kvm_mmu_page_get_gfn(struct kvm_mmu_page *sp, int index) return sp->gfn + (index << ((sp->role.level - 1) * PT64_LEVEL_BITS)); } +gfn_t spte_to_gfn(u64 *spte) +{ + struct kvm_mmu_page *sp; + + sp = page_header(__pa(spte)); + return kvm_mmu_page_get_gfn(sp, spte - sp->spt); +} static void kvm_mmu_page_set_gfn(struct kvm_mmu_page *sp, int index, gfn_t gfn) { diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index c7b333147c..49d7f2f002 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -211,4 +211,5 @@ void kvm_mmu_gfn_allow_lpage(struct kvm_memory_slot *slot, gfn_t gfn); bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm, struct kvm_memory_slot *slot, u64 gfn); int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu); +gfn_t spte_to_gfn(u64 *sptep); #endif From patchwork Fri Dec 7 12:47:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ahmed Abd El Mawgood X-Patchwork-Id: 10718097 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4E4061750 for ; Fri, 7 Dec 2018 12:56:34 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3E0C42E006 for ; Fri, 7 Dec 2018 12:56:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 308E12E01B; Fri, 7 Dec 2018 12:56:34 +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=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id 5C3A32E006 for ; Fri, 7 Dec 2018 12:56:33 +0000 (UTC) Received: (qmail 12031 invoked by uid 550); 7 Dec 2018 12:55:56 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Delivered-To: moderator for kernel-hardening@lists.openwall.com Received: (qmail 1877 invoked from network); 7 Dec 2018 12:49:18 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mena-vt-edu.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=S5NVvoOgAgdZo8wmN11QDMw/7RKccGkERCz5dFRhs3I=; b=HsAo0n5ZNHZaaJaRpG3bq8GeB9YXcLdfGtEPiqJR7TiK9RyHGc09ZiBOLVU2/W+GE0 V5xYVxwH0yMcAuvTT3IRWHgbtyrUSJjJzeMXPG/c6Dl1235iHf6MF6F7qX3JO7jHRj0n bQjlCVGAQt81pNjjoJSFNzVRYe8zmL8APySTvaZrLtQNWX/ZSF6bRA8M1TcoReAIk29r yVPaYrUMimHnqJ5kgHtagJ+L9KMndIbDBFw7ZFg1lOKmc8PE6RkiyIJqBdovX3EYwv8J 1tX5uw0LgZjnd0xFISAw71qw72AJlRkQhrupmJBtsifpJMophzJ+rkWe+16yl4pBfKDt jjDA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=S5NVvoOgAgdZo8wmN11QDMw/7RKccGkERCz5dFRhs3I=; b=dpD2Av6DsXUUIDzEGxGnuMprdZLUlwbPYlu84XNc5tWMfN8zYvaKghGOuKID0MvPGT 0Ykf9mlQoaxru6Ey010dv4HCHa2+TwDx3PpYLXUlk3db8KRZB/13G0ETlZRfu+OLS6zd VaD7ZMEEgfWvpAU90xoazuKCsVShBannPQZe6l9wUi3OgPLoi1JEK6ysgmF6Hl7JD5ul DQ0bsTFVRlaL9YyHHI/egt8/kcDWwtdfjdCNBOypL3MQN/LUasl3T7POZIrUKPrzVSbB 0D3KXkq43FDKss4wg9bdcfr6xvDri8XT9ss+VJv2jVH644dFuW/CaXTVhPXiyTTmsbbC u6Sg== X-Gm-Message-State: AA+aEWZBlBkOVQfThmdsyl/11Tp+57S8+Z28373L4TiyYTeG3jlutZcy omQ+hYDXpqFr2PFiqMKdEx+Xcw== X-Google-Smtp-Source: AFSGD/Xg0iVjxrHzmepdWCYZL5IIBms+bQjq3bJau9vmc8enLf7nlyrhxgrAgU168RFf41hftAmKlg== X-Received: by 2002:adf:fd03:: with SMTP id e3mr1640907wrr.280.1544186947022; Fri, 07 Dec 2018 04:49:07 -0800 (PST) From: Ahmed Abd El Mawgood To: Paolo Bonzini , rkrcmar@redhat.com, Jonathan Corbet , Thomas Gleixner , Ingo Molnar , Borislav Petkov , hpa@zytor.com, x86@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, ahmedsoliman0x666@gmail.com, ovich00@gmail.com, kernel-hardening@lists.openwall.com, nigel.edwards@hpe.com, Boris Lukashev , Igor Stoppa Cc: Ahmed Abd El Mawgood Subject: [PATCH 04/10] KVM: Document Memory ROE Date: Fri, 7 Dec 2018 14:47:57 +0200 Message-Id: <20181207124803.10828-5-ahmedsoliman@mena.vt.edu> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> References: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> MIME-Version: 1.0 X-Virus-Scanned: ClamAV using ClamSMTP ROE version documented here is implemented in the next 2 patches Signed-off-by: Ahmed Abd El Mawgood --- Documentation/virtual/kvm/hypercalls.txt | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Documentation/virtual/kvm/hypercalls.txt b/Documentation/virtual/kvm/hypercalls.txt index da24c138c8..a31f316ce6 100644 --- a/Documentation/virtual/kvm/hypercalls.txt +++ b/Documentation/virtual/kvm/hypercalls.txt @@ -141,3 +141,43 @@ a0 corresponds to the APIC ID in the third argument (a2), bit 1 corresponds to the APIC ID a2+1, and so on. Returns the number of CPUs to which the IPIs were delivered successfully. + +7. KVM_HC_ROE +---------------- +Architecture: x86 +Status: active +Purpose: Hypercall used to apply Read-Only Enforcement to guest memory and +registers +Usage 1: + a0: ROE_VERSION + +Returns non-signed number that represents the current version of ROE +implementation current version. + +Usage 2: + + a0: ROE_MPROTECT (requires version >= 1) + a1: Start address aligned to page boundary. + a2: Number of pages to be protected. + +This configuration lets a guest kernel have part of its read/write memory +converted into read-only. This action is irreversible. +Upon successful run, the number of pages protected is returned. + +Usage 3: + a0: ROE_MPROTECT_CHUNK (requires version >= 2) + a1: Start address aligned to page boundary. + a2: Number of bytes to be protected. +This configuration lets a guest kernel have part of its read/write memory +converted into read-only with bytes granularity. ROE_MPROTECT_CHUNK is +relatively slow compared to ROE_MPROTECT. This action is irreversible. +Upon successful run, the number of bytes protected is returned. + +Error codes: + -KVM_ENOSYS: system call being triggered from ring 3 or it is not + implemented. + -EINVAL: error based on given parameters. + +Notes: KVM_HC_ROE can not be triggered from guest Ring 3 (user mode). The +reason is that user mode malicious software can make use of it to enforce read +only protection on an arbitrary memory page thus crashing the kernel. From patchwork Fri Dec 7 12:47:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ahmed Abd El Mawgood X-Patchwork-Id: 10718099 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 618611750 for ; Fri, 7 Dec 2018 12:56:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 505B02E006 for ; Fri, 7 Dec 2018 12:56:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 41A542E01B; Fri, 7 Dec 2018 12:56:54 +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=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id B7CD52E006 for ; Fri, 7 Dec 2018 12:56:52 +0000 (UTC) Received: (qmail 12243 invoked by uid 550); 7 Dec 2018 12:55:59 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Delivered-To: moderator for kernel-hardening@lists.openwall.com Received: (qmail 1935 invoked from network); 7 Dec 2018 12:49:23 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mena-vt-edu.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=7p38KIh/qjIHeJWDZN0vtJf8Y3XSR7ZTvxKgeKrLtnw=; b=kS6DsnVPjuKMQ8GO7qFfE4Ju7bkjEDdN1VeaPUPwGP/qmoi5VKUJKcGP8T3U7QwLNN vw0+lu9n3Bw3YEaqSwlhljHLCcAlWqb42WZR+Oywq8/r3VWrqs8p2oUPr2fYjKi4spzf RocvhubAf6yOhAaEO73s0diJDHHmFiygLXCdYw4OP4iLUZODuhGKwFy7OvpPe1bzPPMO inrDL2/lZXPr/ABPJdbc/xIrrPwHCu6A3C37t7lEZurKPVKHxjmrIY1oXLWqhb2YROvZ TC5PL9mqLFe7OZ4npitIwasP/rUJHpfg/gtQ9vcBDGp1VoAMJ3cB3lTTc8cr7PEbTWpn eCyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=7p38KIh/qjIHeJWDZN0vtJf8Y3XSR7ZTvxKgeKrLtnw=; b=ifXWn+2iQZwqFrfW0WAHgFap8DFxoBbHRPqb+C64oI1Gpn5FaMCx6Ia75NU+InPrJ5 YWnp0vecjVJYGTJK02zEFxQtqVxZFIrKlVqUP9Y3cMcP26OXYv5uidLkCR2AjTH792OB rlcwNDkUrGR2oXlVWY0p7x7BHA4AxWCHQ11/M5WSXakB/2ffSj6n6ZsyH7lQI+gYCBJ2 qMkqN/b07WTw5GqsNuUFMCCKyevZ3TIdoTg7uKYpavYFNJG5coAKDpLzZOPLfoZMxWpO A87lq8Bhrr3cFQ9tZ6it1QekmenECw7vkEObkwVVor5YzLw349Rs7kQJegaA5e3zR/Ct CT6A== X-Gm-Message-State: AA+aEWYvIN+z+/jTETJrMCNvskodbQTGbWjmVOSNyr5YwEV+DWLH91eJ VtbazWW0wnfGNEa2Dysxd5CNjA== X-Google-Smtp-Source: AFSGD/VEgH5HrwPVtCGC2szkCjG1ZZ7dIDPKBxU+Ft/7m/oqqtd3fEqQihnHOPFuRlwj/M5NxgCBzQ== X-Received: by 2002:a1c:544f:: with SMTP id p15mr2080452wmi.37.1544186951999; Fri, 07 Dec 2018 04:49:11 -0800 (PST) From: Ahmed Abd El Mawgood To: Paolo Bonzini , rkrcmar@redhat.com, Jonathan Corbet , Thomas Gleixner , Ingo Molnar , Borislav Petkov , hpa@zytor.com, x86@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, ahmedsoliman0x666@gmail.com, ovich00@gmail.com, kernel-hardening@lists.openwall.com, nigel.edwards@hpe.com, Boris Lukashev , Igor Stoppa Cc: Ahmed Abd El Mawgood Subject: [PATCH 05/10] KVM: Create architecture independent ROE skeleton Date: Fri, 7 Dec 2018 14:47:58 +0200 Message-Id: <20181207124803.10828-6-ahmedsoliman@mena.vt.edu> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> References: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> MIME-Version: 1.0 X-Virus-Scanned: ClamAV using ClamSMTP This patch introduces a hypercall that can assist against subset of kernel rootkits, it works by place readonly protection in shadow PTE. The end result protection is also kept in a bitmap for each kvm_memory_slot and is used as reference when updating SPTEs. The whole goal is to protect the guest kernel static data from modification if attacker is running from guest ring 0, for this reason there is no hypercall to revert effect of Memory ROE hypercall. This patch doesn't implement integrity check on guest TLB so obvious attack on the current implementation will involve guest virtual address -> guest physical address remapping, but there are plans to fix that. For this patch to work on a given arch/ one would need to implement 2 function that are architecture specific: kvm_roe_arch_commit_protection() and kvm_roe_arch_is_userspace(). Also it would need to have kvm_roe invoked using the appropriate hypercall mechanism. Signed-off-by: Ahmed Abd El Mawgood --- include/kvm/roe.h | 16 ++++ include/linux/kvm_host.h | 1 + include/uapi/linux/kvm_para.h | 4 + virt/kvm/kvm_main.c | 19 +++-- virt/kvm/roe.c | 136 ++++++++++++++++++++++++++++++++++ virt/kvm/roe_generic.h | 19 +++++ 6 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 include/kvm/roe.h create mode 100644 virt/kvm/roe.c create mode 100644 virt/kvm/roe_generic.h diff --git a/include/kvm/roe.h b/include/kvm/roe.h new file mode 100644 index 0000000000..6a86866623 --- /dev/null +++ b/include/kvm/roe.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __KVM_ROE_H__ +#define __KVM_ROE_H__ +/* + * KVM Read Only Enforcement + * Copyright (c) 2018 Ahmed Abd El Mawgood + * + * Author Ahmed Abd El Mawgood + * + */ +void kvm_roe_arch_commit_protection(struct kvm *kvm, + struct kvm_memory_slot *slot); +int kvm_roe(struct kvm_vcpu *vcpu, u64 a0, u64 a1, u64 a2, u64 a3); +bool kvm_roe_arch_is_userspace(struct kvm_vcpu *vcpu); +#endif diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index c926698040..0baea5afcd 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -297,6 +297,7 @@ static inline int kvm_vcpu_exiting_guest_mode(struct kvm_vcpu *vcpu) struct kvm_memory_slot { gfn_t base_gfn; unsigned long npages; + unsigned long *roe_bitmap; unsigned long *dirty_bitmap; struct kvm_arch_memory_slot arch; unsigned long userspace_addr; diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h index 6c0ce49931..e6004e0750 100644 --- a/include/uapi/linux/kvm_para.h +++ b/include/uapi/linux/kvm_para.h @@ -28,7 +28,11 @@ #define KVM_HC_MIPS_CONSOLE_OUTPUT 8 #define KVM_HC_CLOCK_PAIRING 9 #define KVM_HC_SEND_IPI 10 +#define KVM_HC_ROE 11 +/* ROE Functionality parameters */ +#define ROE_VERSION 0 +#define ROE_MPROTECT 1 /* * hypercalls use architecture specific */ diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 039c1ef9a7..814ee0fd35 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -61,6 +61,7 @@ #include "coalesced_mmio.h" #include "async_pf.h" #include "vfio.h" +#include "roe_generic.h" #define CREATE_TRACE_POINTS #include @@ -552,9 +553,10 @@ static void kvm_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free, struct kvm_memory_slot *dont, enum kvm_mr_change change) { - if (change == KVM_MR_DELETE) + if (change == KVM_MR_DELETE) { + kvm_roe_free(free); kvm_destroy_dirty_bitmap(free); - + } kvm_arch_free_memslot(kvm, free, dont); free->npages = 0; @@ -1020,6 +1022,8 @@ int __kvm_set_memory_region(struct kvm *kvm, if (kvm_create_dirty_bitmap(&new) < 0) goto out_free; } + if (kvm_roe_init(&new) < 0) + goto out_free; slots = kvzalloc(sizeof(struct kvm_memslots), GFP_KERNEL); if (!slots) @@ -1273,13 +1277,18 @@ static bool memslot_is_readonly(struct kvm_memory_slot *slot) return slot->flags & KVM_MEM_READONLY; } +static bool gfn_is_readonly(struct kvm_memory_slot *slot, gfn_t gfn) +{ + return gfn_is_full_roe(slot, gfn) || memslot_is_readonly(slot); +} + static unsigned long __gfn_to_hva_many(struct kvm_memory_slot *slot, gfn_t gfn, gfn_t *nr_pages, bool write) { if (!slot || slot->flags & KVM_MEMSLOT_INVALID) return KVM_HVA_ERR_BAD; - if (memslot_is_readonly(slot) && write) + if (gfn_is_readonly(slot, gfn) && write) return KVM_HVA_ERR_RO_BAD; if (nr_pages) @@ -1327,7 +1336,7 @@ unsigned long gfn_to_hva_memslot_prot(struct kvm_memory_slot *slot, unsigned long hva = __gfn_to_hva_many(slot, gfn, NULL, false); if (!kvm_is_error_hva(hva) && writable) - *writable = !memslot_is_readonly(slot); + *writable = !gfn_is_readonly(slot, gfn); return hva; } @@ -1565,7 +1574,7 @@ kvm_pfn_t __gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn, } /* Do not map writable pfn in the readonly memslot. */ - if (writable && memslot_is_readonly(slot)) { + if (writable && gfn_is_readonly(slot, gfn)) { *writable = false; writable = NULL; } diff --git a/virt/kvm/roe.c b/virt/kvm/roe.c new file mode 100644 index 0000000000..3f6eb6ede2 --- /dev/null +++ b/virt/kvm/roe.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * KVM Read Only Enforcement + * Copyright (c) 2018 Ahmed Abd El Mawgood + * + * Author: Ahmed Abd El Mawgood + * + */ +#include +#include +#include +#include + +int kvm_roe_init(struct kvm_memory_slot *slot) +{ + slot->roe_bitmap = kvzalloc(BITS_TO_LONGS(slot->npages) * + sizeof(unsigned long), GFP_KERNEL); + if (!slot->roe_bitmap) + return -ENOMEM; + return 0; + +} + +void kvm_roe_free(struct kvm_memory_slot *slot) +{ + kvfree(slot->roe_bitmap); +} + +static void kvm_roe_protect_slot(struct kvm *kvm, struct kvm_memory_slot *slot, + gfn_t gfn, u64 npages) +{ + int i; + + for (i = gfn - slot->base_gfn; i < gfn + npages - slot->base_gfn; i++) + set_bit(i, slot->roe_bitmap); + kvm_roe_arch_commit_protection(kvm, slot); +} + + +static int __kvm_roe_protect_range(struct kvm *kvm, gpa_t gpa, u64 npages) +{ + struct kvm_memory_slot *slot; + gfn_t gfn = gpa >> PAGE_SHIFT; + int count = 0; + + while (npages != 0) { + slot = gfn_to_memslot(kvm, gfn); + if (!slot) { + gfn += 1; + npages -= 1; + continue; + } + if (gfn + npages > slot->base_gfn + slot->npages) { + u64 _npages = slot->base_gfn + slot->npages - gfn; + + kvm_roe_protect_slot(kvm, slot, gfn, _npages); + gfn += _npages; + count += _npages; + npages -= _npages; + } else { + kvm_roe_protect_slot(kvm, slot, gfn, npages); + count += npages; + npages = 0; + } + } + if (count == 0) + return -EINVAL; + return count; +} + +static int kvm_roe_protect_range(struct kvm *kvm, gpa_t gpa, u64 npages) +{ + int r; + + mutex_lock(&kvm->slots_lock); + r = __kvm_roe_protect_range(kvm, gpa, npages); + mutex_unlock(&kvm->slots_lock); + return r; +} + + +static int kvm_roe_full_protect_range(struct kvm_vcpu *vcpu, u64 gva, + u64 npages) +{ + struct kvm *kvm = vcpu->kvm; + gpa_t gpa; + u64 hva; + u64 count = 0; + int i; + int status; + + if (gva & ~PAGE_MASK) + return -EINVAL; + // We need to make sure that there will be no overflow + if ((npages << PAGE_SHIFT) >> PAGE_SHIFT != npages || npages == 0) + return -EINVAL; + for (i = 0; i < npages; i++) { + gpa = kvm_mmu_gva_to_gpa_system(vcpu, gva + (i << PAGE_SHIFT), + NULL); + hva = gfn_to_hva(kvm, gpa >> PAGE_SHIFT); + if (kvm_is_error_hva(hva)) + continue; + if (!access_ok(VERIFY_WRITE, hva, 1 << PAGE_SHIFT)) + continue; + status = kvm_roe_protect_range(vcpu->kvm, gpa, 1); + if (status > 0) + count += status; + } + if (count == 0) + return -EINVAL; + return count; +} + +int kvm_roe(struct kvm_vcpu *vcpu, u64 a0, u64 a1, u64 a2, u64 a3) +{ + int ret; + /* + * First we need to make sure that we are running from something that + * isn't usermode + */ + if (kvm_roe_arch_is_userspace(vcpu)) + return -KVM_ENOSYS; + switch (a0) { + case ROE_VERSION: + ret = 1; //current version + break; + case ROE_MPROTECT: + ret = kvm_roe_full_protect_range(vcpu, a1, a2); + break; + default: + ret = -EINVAL; + } + return ret; +} +EXPORT_SYMBOL_GPL(kvm_roe); diff --git a/virt/kvm/roe_generic.h b/virt/kvm/roe_generic.h new file mode 100644 index 0000000000..36e5b52c5b --- /dev/null +++ b/virt/kvm/roe_generic.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __KVM_ROE_GENERIC_H__ +#define __KVM_ROE_GENERIC_H__ +/* + * KVM Read Only Enforcement + * Copyright (c) 2018 Ahmed Abd El Mawgood + * + * Author Ahmed Abd El Mawgood + * + */ + +void kvm_roe_free(struct kvm_memory_slot *slot); +int kvm_roe_init(struct kvm_memory_slot *slot); +static inline bool gfn_is_full_roe(struct kvm_memory_slot *slot, gfn_t gfn) +{ + return test_bit(gfn - slot->base_gfn, slot->roe_bitmap); +} +#endif From patchwork Fri Dec 7 12:47:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ahmed Abd El Mawgood X-Patchwork-Id: 10718101 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E12621759 for ; Fri, 7 Dec 2018 12:57:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D06E72E006 for ; Fri, 7 Dec 2018 12:57:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C2A742E042; Fri, 7 Dec 2018 12:57:15 +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=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id 0C2192E006 for ; Fri, 7 Dec 2018 12:57:13 +0000 (UTC) Received: (qmail 13489 invoked by uid 550); 7 Dec 2018 12:56:03 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Delivered-To: moderator for kernel-hardening@lists.openwall.com Received: (qmail 1996 invoked from network); 7 Dec 2018 12:49:28 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mena-vt-edu.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=/9gDVqCBZ049LKb2pdMtzCpXTWMx0MNMSAP/7qdzAU8=; b=wF+nBG3cjnEZpuGz6d/ySLU7qurr0iM9ZSElOZJcdROYTaI9Iuww33oSoSX3nVLZgK LI1tobWF3Cl0SMuv1HuDit78xuPV7CkWdp08z8nAhH0X4IAjTRZf3/igJtO3NPzWt46w E76b/eBmzw5He4ux0Rw7lum+5Q9Va3jIHuB+u4BhPtgRmKSB3OSdVvjONKSKGPPtvo7m Xj/i1oxYXP77qMGSdy6eBI79hnAJjgG343RI8A4Bt7jOgLMJbTtlqrvePZ5zsPFhwTYr LtqhVX305jRBe2+n/dU0lXIAZnAKwImyQaBxNRcqsijwVHW/Dj2biYArOswiv1MY0Wpx DmHg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=/9gDVqCBZ049LKb2pdMtzCpXTWMx0MNMSAP/7qdzAU8=; b=KHpEEQ8Sok7PnPg7PEiv4OgdWo0EJENXWy6SpQDFKDEdHm2FA7TDvj99zDOKDf9sA7 0aivCv/cSp+qXucnF6kBf8lzXvYD+zkf7qzHcwVIYz9EztetSjuyYG6cz6t4XsHxjMll XexWLwPPD0ZPoV3PncMsU9BYcu7RWx2BgJ+d/maLALQIrsuMZ998aOJK3Ws0GEtL57gK KgZ7KaYFiKyKq/cD9DPiSUhcXzl9gq+k29HN/ZoffWBLVLjru1bScxQREqk2zQsOoLgJ oUUPvpQErd5yZOBl4QB2wjvG/5KQHBERaUZto1v131qW3cckI12fQrrSNtWuLuNUsfbt LSUQ== X-Gm-Message-State: AA+aEWZGTIiwXRef9t3TmljBrg9K4z8xXzkWWWkXiy6S2ZHmp/xBbToj 2/ZZRM9jpWzUc1rPftM/qkgAoQ== X-Google-Smtp-Source: AFSGD/W6HMCVGJvb2LASGsxHG2J4z2voN3mU9kftOEqBLpneCzqhmhbID2nd9AKebT7DrQGXQAxSaQ== X-Received: by 2002:a1c:c87:: with SMTP id 129mr2001330wmm.116.1544186957122; Fri, 07 Dec 2018 04:49:17 -0800 (PST) From: Ahmed Abd El Mawgood To: Paolo Bonzini , rkrcmar@redhat.com, Jonathan Corbet , Thomas Gleixner , Ingo Molnar , Borislav Petkov , hpa@zytor.com, x86@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, ahmedsoliman0x666@gmail.com, ovich00@gmail.com, kernel-hardening@lists.openwall.com, nigel.edwards@hpe.com, Boris Lukashev , Igor Stoppa Cc: Ahmed Abd El Mawgood Subject: [PATCH 06/10] KVM: X86: Enable ROE for x86 Date: Fri, 7 Dec 2018 14:47:59 +0200 Message-Id: <20181207124803.10828-7-ahmedsoliman@mena.vt.edu> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> References: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> MIME-Version: 1.0 X-Virus-Scanned: ClamAV using ClamSMTP This patch implements kvm_roe_arch_commit_protection and kvm_roe_arch_is_userspace for x86, and invoke kvm_roe via the appropriate vmcall. Signed-off-by: Ahmed Abd El Mawgood --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/Makefile | 4 +- arch/x86/kvm/mmu.c | 71 +++++----------------- arch/x86/kvm/mmu.h | 30 +++++++++- arch/x86/kvm/roe.c | 101 ++++++++++++++++++++++++++++++++ arch/x86/kvm/roe_arch.h | 28 +++++++++ arch/x86/kvm/x86.c | 11 ++-- 7 files changed, 183 insertions(+), 64 deletions(-) create mode 100644 arch/x86/kvm/roe.c create mode 100644 arch/x86/kvm/roe_arch.h diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index fbda5a917c..e56903e6ff 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1230,7 +1230,7 @@ void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask, u64 acc_track_mask, u64 me_mask); void kvm_mmu_reset_context(struct kvm_vcpu *vcpu); -void kvm_mmu_slot_remove_write_access(struct kvm *kvm, +void kvm_mmu_slot_apply_write_access(struct kvm *kvm, struct kvm_memory_slot *memslot); void kvm_mmu_zap_collapsible_sptes(struct kvm *kvm, const struct kvm_memory_slot *memslot); diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index dc4f2fdf5e..a8c915a326 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile @@ -9,7 +9,9 @@ CFLAGS_vmx.o := -I. KVM := ../../../virt/kvm kvm-y += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o \ - $(KVM)/eventfd.o $(KVM)/irqchip.o $(KVM)/vfio.o + $(KVM)/eventfd.o $(KVM)/irqchip.o $(KVM)/vfio.o \ + $(KVM)/roe.o roe.o + kvm-$(CONFIG_KVM_ASYNC_PF) += $(KVM)/async_pf.o kvm-y += x86.o mmu.o emulate.o i8259.o irq.o lapic.o \ diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index a300e4acb8..fde565c8a1 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -23,7 +23,7 @@ #include "x86.h" #include "kvm_cache_regs.h" #include "cpuid.h" - +#include "roe_arch.h" #include #include #include @@ -1314,8 +1314,8 @@ static void pte_list_remove(struct kvm_rmap_head *rmap_head, u64 *sptep) __pte_list_remove(sptep, rmap_head); } -static struct kvm_rmap_head *__gfn_to_rmap(gfn_t gfn, int level, - struct kvm_memory_slot *slot) +struct kvm_rmap_head *__gfn_to_rmap(gfn_t gfn, int level, + struct kvm_memory_slot *slot) { unsigned long idx; @@ -1365,16 +1365,6 @@ static void rmap_remove(struct kvm *kvm, u64 *spte) __pte_list_remove(spte, rmap_head); } -/* - * Used by the following functions to iterate through the sptes linked by a - * rmap. All fields are private and not assumed to be used outside. - */ -struct rmap_iterator { - /* private fields */ - struct pte_list_desc *desc; /* holds the sptep if not NULL */ - int pos; /* index of the sptep */ -}; - /* * Iteration must be started by this function. This should also be used after * removing/dropping sptes from the rmap link because in such cases the @@ -1382,8 +1372,7 @@ struct rmap_iterator { * * Returns sptep if found, NULL otherwise. */ -static u64 *rmap_get_first(struct kvm_rmap_head *rmap_head, - struct rmap_iterator *iter) +u64 *rmap_get_first(struct kvm_rmap_head *rmap_head, struct rmap_iterator *iter) { u64 *sptep; @@ -1409,7 +1398,7 @@ static u64 *rmap_get_first(struct kvm_rmap_head *rmap_head, * * Returns sptep if found, NULL otherwise. */ -static u64 *rmap_get_next(struct rmap_iterator *iter) +u64 *rmap_get_next(struct rmap_iterator *iter) { u64 *sptep; @@ -1480,7 +1469,7 @@ static void drop_large_spte(struct kvm_vcpu *vcpu, u64 *sptep) * * Return true if tlb need be flushed. */ -static bool spte_write_protect(u64 *sptep, bool pt_protect) +bool spte_write_protect(u64 *sptep, bool pt_protect) { u64 spte = *sptep; @@ -1498,8 +1487,7 @@ static bool spte_write_protect(u64 *sptep, bool pt_protect) } static bool __rmap_write_protect(struct kvm *kvm, - struct kvm_rmap_head *rmap_head, - bool pt_protect, void *data) + struct kvm_rmap_head *rmap_head, bool pt_protect) { u64 *sptep; struct rmap_iterator iter; @@ -1598,7 +1586,7 @@ static void kvm_mmu_write_protect_pt_masked(struct kvm *kvm, while (mask) { rmap_head = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask), PT_PAGE_TABLE_LEVEL, slot); - __rmap_write_protect(kvm, rmap_head, false, NULL); + __rmap_write_protect(kvm, rmap_head, false); /* clear the first set bit */ mask &= mask - 1; @@ -1668,22 +1656,6 @@ int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu) return 0; } -bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm, - struct kvm_memory_slot *slot, u64 gfn) -{ - struct kvm_rmap_head *rmap_head; - int i; - bool write_protected = false; - - for (i = PT_PAGE_TABLE_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) { - rmap_head = __gfn_to_rmap(gfn, i, slot); - write_protected |= __rmap_write_protect(kvm, rmap_head, true, - NULL); - } - - return write_protected; -} - static bool rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn) { struct kvm_memory_slot *slot; @@ -5524,10 +5496,6 @@ void kvm_mmu_uninit_vm(struct kvm *kvm) kvm_page_track_unregister_notifier(kvm, node); } -/* The return value indicates if tlb flush on all vcpus is needed. */ -typedef bool (*slot_level_handler) (struct kvm *kvm, - struct kvm_rmap_head *rmap_head, void *data); - /* The caller should hold mmu-lock before calling this function. */ static __always_inline bool slot_handle_level_range(struct kvm *kvm, struct kvm_memory_slot *memslot, @@ -5571,9 +5539,8 @@ slot_handle_level(struct kvm *kvm, struct kvm_memory_slot *memslot, lock_flush_tlb, data); } -static __always_inline bool -slot_handle_all_level(struct kvm *kvm, struct kvm_memory_slot *memslot, - slot_level_handler fn, bool lock_flush_tlb, void *data) +bool slot_handle_all_level(struct kvm *kvm, struct kvm_memory_slot *memslot, + slot_level_handler fn, bool lock_flush_tlb, void *data) { return slot_handle_level(kvm, memslot, fn, PT_PAGE_TABLE_LEVEL, PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb, data); @@ -5625,21 +5592,15 @@ static bool slot_rmap_write_protect(struct kvm *kvm, struct kvm_rmap_head *rmap_head, void *data) { - return __rmap_write_protect(kvm, rmap_head, false, data); + return __rmap_write_protect(kvm, rmap_head, false); } -void kvm_mmu_slot_remove_write_access(struct kvm *kvm, - struct kvm_memory_slot *memslot) +void kvm_mmu_slot_apply_write_access(struct kvm *kvm, + struct kvm_memory_slot *memslot) { - bool flush; - - spin_lock(&kvm->mmu_lock); - flush = slot_handle_all_level(kvm, memslot, slot_rmap_write_protect, - false, NULL); - spin_unlock(&kvm->mmu_lock); - + bool flush = protect_all_levels(kvm, memslot); /* - * kvm_mmu_slot_remove_write_access() and kvm_vm_ioctl_get_dirty_log() + * kvm_mmu_slot_apply_write_access() and kvm_vm_ioctl_get_dirty_log() * which do tlb flush out of mmu-lock should be serialized by * kvm->slots_lock otherwise tlb flush would be missed. */ @@ -5736,7 +5697,7 @@ void kvm_mmu_slot_largepage_remove_write_access(struct kvm *kvm, false, NULL); spin_unlock(&kvm->mmu_lock); - /* see kvm_mmu_slot_remove_write_access */ + /* see kvm_mmu_slot_apply_write_access*/ lockdep_assert_held(&kvm->slots_lock); if (flush) diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 49d7f2f002..35b46a6a0a 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -4,7 +4,7 @@ #include #include "kvm_cache_regs.h" - +#include "roe_arch.h" #define PT64_PT_BITS 9 #define PT64_ENT_PER_PAGE (1 << PT64_PT_BITS) #define PT32_PT_BITS 10 @@ -43,6 +43,24 @@ #define PT32_ROOT_LEVEL 2 #define PT32E_ROOT_LEVEL 3 +#define for_each_rmap_spte(_rmap_head_, _iter_, _spte_) \ + for (_spte_ = rmap_get_first(_rmap_head_, _iter_); \ + _spte_; _spte_ = rmap_get_next(_iter_)) + +/* + * Used by the following functions to iterate through the sptes linked by a + * rmap. All fields are private and not assumed to be used outside. + */ +struct rmap_iterator { + /* private fields */ + struct pte_list_desc *desc; /* holds the sptep if not NULL */ + int pos; /* index of the sptep */ +}; + +u64 *rmap_get_first(struct kvm_rmap_head *rmap_head, + struct rmap_iterator *iter); +u64 *rmap_get_next(struct rmap_iterator *iter); +bool spte_write_protect(u64 *sptep, bool pt_protect); static inline u64 rsvd_bits(int s, int e) { if (e < s) @@ -203,13 +221,19 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, return -(u32)fault & errcode; } +/* The return value indicates if tlb flush on all vcpus is needed. */ +typedef bool (*slot_level_handler) (struct kvm *kvm, + struct kvm_rmap_head *rmap_head, void *data); + void kvm_mmu_invalidate_zap_all_pages(struct kvm *kvm); void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end); void kvm_mmu_gfn_disallow_lpage(struct kvm_memory_slot *slot, gfn_t gfn); void kvm_mmu_gfn_allow_lpage(struct kvm_memory_slot *slot, gfn_t gfn); -bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm, - struct kvm_memory_slot *slot, u64 gfn); int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu); gfn_t spte_to_gfn(u64 *sptep); +bool slot_handle_all_level(struct kvm *kvm, struct kvm_memory_slot *memslot, + slot_level_handler fn, bool lock_flush_tlb, void *data); +struct kvm_rmap_head *__gfn_to_rmap(gfn_t gfn, int level, + struct kvm_memory_slot *slot); #endif diff --git a/arch/x86/kvm/roe.c b/arch/x86/kvm/roe.c new file mode 100644 index 0000000000..f787106be8 --- /dev/null +++ b/arch/x86/kvm/roe.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * KVM Read Only Enforcement + * Copyright (c) 2018 Ahmed Abd El Mawgood + * + * Author: Ahmed Abd El Mawgood + * + */ +#include +#include +#include + + +#include +#include "kvm_cache_regs.h" +#include "mmu.h" +#include "roe_arch.h" + +static bool __rmap_write_protect_roe(struct kvm *kvm, + struct kvm_rmap_head *rmap_head, bool pt_protect, + struct kvm_memory_slot *memslot) +{ + u64 *sptep; + struct rmap_iterator iter; + bool prot; + bool flush = false; + + for_each_rmap_spte(rmap_head, &iter, sptep) { + int idx = spte_to_gfn(sptep) - memslot->base_gfn; + + prot = !test_bit(idx, memslot->roe_bitmap) && pt_protect; + flush |= spte_write_protect(sptep, prot); + } + return flush; +} + +bool kvm_mmu_slot_gfn_write_protect_roe(struct kvm *kvm, + struct kvm_memory_slot *slot, u64 gfn) +{ + struct kvm_rmap_head *rmap_head; + int i; + bool write_protected = false; + + for (i = PT_PAGE_TABLE_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) { + rmap_head = __gfn_to_rmap(gfn, i, slot); + write_protected |= __rmap_write_protect_roe(kvm, rmap_head, + true, slot); + } + return write_protected; +} + +static bool slot_rmap_apply_protection(struct kvm *kvm, + struct kvm_rmap_head *rmap_head, void *data) +{ + struct kvm_memory_slot *memslot = (struct kvm_memory_slot *) data; + bool prot_mask = !(memslot->flags & KVM_MEM_READONLY); + + return __rmap_write_protect_roe(kvm, rmap_head, prot_mask, memslot); +} + +bool roe_protect_all_levels(struct kvm *kvm, struct kvm_memory_slot *memslot) +{ + bool flush; + + spin_lock(&kvm->mmu_lock); + flush = slot_handle_all_level(kvm, memslot, slot_rmap_apply_protection, + false, memslot); + spin_unlock(&kvm->mmu_lock); + return flush; +} + +void kvm_roe_arch_commit_protection(struct kvm *kvm, + struct kvm_memory_slot *slot) +{ + kvm_mmu_slot_apply_write_access(kvm, slot); + kvm_arch_flush_shadow_memslot(kvm, slot); +} +EXPORT_SYMBOL_GPL(kvm_roe_arch_commit_protection); + +bool kvm_roe_arch_is_userspace(struct kvm_vcpu *vcpu) +{ + u64 rflags; + u64 cr0 = kvm_read_cr0(vcpu); + u64 iopl; + + // first checking we are not in protected mode + if ((cr0 & 1) == 0) + return false; + /* + * we don't need to worry about comments in __get_regs + * because we are sure that this function will only be + * triggered at the end of a hypercall instruction. + */ + rflags = kvm_get_rflags(vcpu); + iopl = (rflags >> 12) & 3; + if (iopl != 3) + return false; + return true; +} +EXPORT_SYMBOL_GPL(kvm_roe_arch_is_userspace); diff --git a/arch/x86/kvm/roe_arch.h b/arch/x86/kvm/roe_arch.h new file mode 100644 index 0000000000..17a8b79d36 --- /dev/null +++ b/arch/x86/kvm/roe_arch.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __KVM_ROE_HARCH_H__ +#define __KVM_ROE_HARCH_H__ +/* + * KVM Read Only Enforcement + * Copyright (c) 2018 Ahmed Abd El Mawgood + * + * Author: Ahmed Abd El Mawgood + * + */ +#include "mmu.h" + +bool roe_protect_all_levels(struct kvm *kvm, struct kvm_memory_slot *memslot); + +static inline bool protect_all_levels(struct kvm *kvm, + struct kvm_memory_slot *memslot) +{ + return roe_protect_all_levels(kvm, memslot); +} +bool kvm_mmu_slot_gfn_write_protect_roe(struct kvm *kvm, + struct kvm_memory_slot *slot, u64 gfn); +static inline bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm, + struct kvm_memory_slot *slot, u64 gfn) +{ + return kvm_mmu_slot_gfn_write_protect_roe(kvm, slot, gfn); +} +#endif diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d02937760c..28475c83f9 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -20,6 +20,7 @@ */ #include +#include #include "irq.h" #include "mmu.h" #include "i8254.h" @@ -4409,7 +4410,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) /* * All the TLBs can be flushed out of mmu lock, see the comments in - * kvm_mmu_slot_remove_write_access(). + * kvm_mmu_slot_apply_write_access(). */ lockdep_assert_held(&kvm->slots_lock); if (is_dirty) @@ -6928,7 +6929,6 @@ static int kvm_pv_clock_pairing(struct kvm_vcpu *vcpu, gpa_t paddr, return ret; } #endif - /* * kvm_pv_kick_cpu_op: Kick a vcpu. * @@ -7000,6 +7000,9 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) ret = kvm_pv_send_ipi(vcpu->kvm, a0, a1, a2, a3, op_64_bit); break; #endif + case KVM_HC_ROE: + ret = kvm_roe(vcpu, a0, a1, a2, a3); + break; default: ret = -KVM_ENOSYS; break; @@ -9263,8 +9266,8 @@ static void kvm_mmu_slot_apply_flags(struct kvm *kvm, struct kvm_memory_slot *new) { /* Still write protect RO slot */ + kvm_mmu_slot_apply_write_access(kvm, new); if (new->flags & KVM_MEM_READONLY) { - kvm_mmu_slot_remove_write_access(kvm, new); return; } @@ -9302,7 +9305,7 @@ static void kvm_mmu_slot_apply_flags(struct kvm *kvm, if (kvm_x86_ops->slot_enable_log_dirty) kvm_x86_ops->slot_enable_log_dirty(kvm, new); else - kvm_mmu_slot_remove_write_access(kvm, new); + kvm_mmu_slot_apply_write_access(kvm, new); } else { if (kvm_x86_ops->slot_disable_log_dirty) kvm_x86_ops->slot_disable_log_dirty(kvm, new); From patchwork Fri Dec 7 12:48:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ahmed Abd El Mawgood X-Patchwork-Id: 10718103 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D26D61750 for ; Fri, 7 Dec 2018 12:57:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BE72A2E006 for ; Fri, 7 Dec 2018 12:57:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AE8F92E01B; Fri, 7 Dec 2018 12:57:37 +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=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id 100902E006 for ; Fri, 7 Dec 2018 12:57:35 +0000 (UTC) Received: (qmail 14182 invoked by uid 550); 7 Dec 2018 12:56:18 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Delivered-To: moderator for kernel-hardening@lists.openwall.com Received: (qmail 3100 invoked from network); 7 Dec 2018 12:49:34 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mena-vt-edu.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=WFm+9E+UnB+5zHhGwZfdy/tJxE4uPkVq9Z/8MO+Mr58=; b=FwfVLIQQj0GF3CAqCXbKWEKmffl7UehYfQxgkJmqqIeOEMZnIL2lTmLpSehraeOPkn jLUMn8ojs1tW+kYoMcu2py14aDoh19c/AflVATtWvCu1X/ylYl1Muyyhj9KRLj31ierE dcKwaVc4NQ0QjjTBR7dqcbE5+wR4PF8d9fvDZSb4syO2apCJMWo4NrSQMYxMiX6ZBscO 1l479oWr3lgfbAYBlHveTaYKQHfF5MQI0xK4MSeNV7D5x7fha4w5N2G0fB9Yyc4slN6g VnlLB9dUqH/+qVtT0XTBIxHJSjRW/E2dgjzLE3xfMRDTwFuMRWm1gL+MGIRc4n/Cnt99 GAJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=WFm+9E+UnB+5zHhGwZfdy/tJxE4uPkVq9Z/8MO+Mr58=; b=SbagHFX7IALWUvvkZRlPJTprj+egV7mv0Q6nNk48+nDPY3PM/Zaz4IJAMRz/tpg0sF g6PgdjK4X8ntJOELrTw9cSF6kncbT2iz7S92hqmFAPdkmXyTp4TC+OjodNXDUcyokeYw cUZn4XCmhK5hFUbRD08SwcLBtCWguyVKV2wP27AKhN6xg4d0CPnt5KKVftxFuYjsBQPg 91hfStdWEaa9au3M9b5o4+VicFZhMu1a7MFKG4k/ITjFo8qihEWVCNH1kMFvKgDtPvy/ P5IF+nNhGL5wZYdj8V5NJYNxmCXQisJ1sWxyELFPfbfMSdqJvOFD3Mfuw/FVOROqse4h y5JQ== X-Gm-Message-State: AA+aEWY12kipf2quA+t8Ae4IOeZ8Gu12x+iTcNe2dPM483DD7BkKzcze Zg/5ji62MJJmHvOeG/yrYhJIOw== X-Google-Smtp-Source: AFSGD/XIA0BX2iWpbj3OnFH5xrSCmKZF/cfizoy9v5Cm7239Sd3d8i8mSY3VapkbXWtW9CxE2JdpCQ== X-Received: by 2002:a5d:65ce:: with SMTP id e14mr1638802wrw.150.1544186962697; Fri, 07 Dec 2018 04:49:22 -0800 (PST) From: Ahmed Abd El Mawgood To: Paolo Bonzini , rkrcmar@redhat.com, Jonathan Corbet , Thomas Gleixner , Ingo Molnar , Borislav Petkov , hpa@zytor.com, x86@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, ahmedsoliman0x666@gmail.com, ovich00@gmail.com, kernel-hardening@lists.openwall.com, nigel.edwards@hpe.com, Boris Lukashev , Igor Stoppa Cc: Ahmed Abd El Mawgood Subject: [PATCH 07/10] KVM: Add support for byte granular memory ROE Date: Fri, 7 Dec 2018 14:48:00 +0200 Message-Id: <20181207124803.10828-8-ahmedsoliman@mena.vt.edu> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> References: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> MIME-Version: 1.0 X-Virus-Scanned: ClamAV using ClamSMTP This patch documents and implements ROE_MPROTECT_CHUNK, a part of ROE hypercall designed to protect regions of a memory page with byte granularity. This feature provides a key primitive to protect against attacks involving pages remapping. Signed-off-by: Ahmed Abd El Mawgood --- include/linux/kvm_host.h | 24 ++++ include/uapi/linux/kvm_para.h | 1 + virt/kvm/kvm_main.c | 24 +++- virt/kvm/roe.c | 212 ++++++++++++++++++++++++++++++++-- virt/kvm/roe_generic.h | 6 + 5 files changed, 253 insertions(+), 14 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 0baea5afcd..159bef3450 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -294,10 +294,34 @@ static inline int kvm_vcpu_exiting_guest_mode(struct kvm_vcpu *vcpu) */ #define KVM_MEM_MAX_NR_PAGES ((1UL << 31) - 1) +/* + * This structure is used to hold memory areas that are to be protected in a + * memory frame with mixed page permissions. + **/ +struct protected_chunk { + gpa_t gpa; + u64 size; + struct list_head list; +}; + +static inline bool kvm_roe_range_overlap(struct protected_chunk *chunk, + gpa_t gpa, int len) { + /* + * https://stackoverflow.com/questions/325933/ + * determine-whether-two-date-ranges-overlap + * Assuming that it works, that link ^ provides a solution that is + * better than anything I would ever come up with. + */ + return (gpa <= chunk->gpa + chunk->size - 1) && + (gpa + len - 1 >= chunk->gpa); +} + struct kvm_memory_slot { gfn_t base_gfn; unsigned long npages; unsigned long *roe_bitmap; + unsigned long *partial_roe_bitmap; + struct list_head *prot_list; unsigned long *dirty_bitmap; struct kvm_arch_memory_slot arch; unsigned long userspace_addr; diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h index e6004e0750..4a84f974bc 100644 --- a/include/uapi/linux/kvm_para.h +++ b/include/uapi/linux/kvm_para.h @@ -33,6 +33,7 @@ /* ROE Functionality parameters */ #define ROE_VERSION 0 #define ROE_MPROTECT 1 +#define ROE_MPROTECT_CHUNK 2 /* * hypercalls use architecture specific */ diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 814ee0fd35..0d129b05d5 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1279,18 +1279,19 @@ static bool memslot_is_readonly(struct kvm_memory_slot *slot) static bool gfn_is_readonly(struct kvm_memory_slot *slot, gfn_t gfn) { - return gfn_is_full_roe(slot, gfn) || memslot_is_readonly(slot); + return gfn_is_full_roe(slot, gfn) || + gfn_is_partial_roe(slot, gfn) || + memslot_is_readonly(slot); } + static unsigned long __gfn_to_hva_many(struct kvm_memory_slot *slot, gfn_t gfn, gfn_t *nr_pages, bool write) { if (!slot || slot->flags & KVM_MEMSLOT_INVALID) return KVM_HVA_ERR_BAD; - if (gfn_is_readonly(slot, gfn) && write) return KVM_HVA_ERR_RO_BAD; - if (nr_pages) *nr_pages = slot->npages - (gfn - slot->base_gfn); @@ -1852,14 +1853,29 @@ int kvm_vcpu_read_guest_atomic(struct kvm_vcpu *vcpu, gpa_t gpa, return __kvm_read_guest_atomic(slot, gfn, data, offset, len); } EXPORT_SYMBOL_GPL(kvm_vcpu_read_guest_atomic); +static u64 roe_gfn_to_hva(struct kvm_memory_slot *slot, gfn_t gfn, int offset, + int len) +{ + u64 addr; + if (!slot) + return KVM_HVA_ERR_RO_BAD; + if (kvm_roe_check_range(slot, gfn, offset, len)) + return KVM_HVA_ERR_RO_BAD; + if (memslot_is_readonly(slot)) + return KVM_HVA_ERR_RO_BAD; + if (gfn_is_full_roe(slot, gfn)) + return KVM_HVA_ERR_RO_BAD; + addr = __gfn_to_hva_many(slot, gfn, NULL, false); + return addr; +} static int __kvm_write_guest_page(struct kvm_memory_slot *memslot, gfn_t gfn, const void *data, int offset, int len) { int r; unsigned long addr; - addr = gfn_to_hva_memslot(memslot, gfn); + addr = roe_gfn_to_hva(memslot, gfn, offset, len); if (kvm_is_error_hva(addr)) return -EFAULT; r = __copy_to_user((void __user *)addr + offset, data, len); diff --git a/virt/kvm/roe.c b/virt/kvm/roe.c index 3f6eb6ede2..dfb1de314c 100644 --- a/virt/kvm/roe.c +++ b/virt/kvm/roe.c @@ -11,34 +11,89 @@ #include #include #include +#include "roe_generic.h" int kvm_roe_init(struct kvm_memory_slot *slot) { slot->roe_bitmap = kvzalloc(BITS_TO_LONGS(slot->npages) * sizeof(unsigned long), GFP_KERNEL); if (!slot->roe_bitmap) - return -ENOMEM; + goto fail1; + slot->partial_roe_bitmap = kvzalloc(BITS_TO_LONGS(slot->npages) * + sizeof(unsigned long), GFP_KERNEL); + if (!slot->partial_roe_bitmap) + goto fail2; + slot->prot_list = kvzalloc(sizeof(struct list_head), GFP_KERNEL); + if (!slot->prot_list) + goto fail3; + INIT_LIST_HEAD(slot->prot_list); return 0; +fail3: + kvfree(slot->partial_roe_bitmap); +fail2: + kvfree(slot->roe_bitmap); +fail1: + return -ENOMEM; + +} + +static bool kvm_roe_protected_range(struct kvm_memory_slot *slot, gpa_t gpa, + int len) +{ + struct list_head *pos; + struct protected_chunk *cur_chunk; + + list_for_each(pos, slot->prot_list) { + cur_chunk = list_entry(pos, struct protected_chunk, list); + if (kvm_roe_range_overlap(cur_chunk, gpa, len)) + return true; + } + return false; +} + +bool kvm_roe_check_range(struct kvm_memory_slot *slot, gfn_t gfn, int offset, + int len) +{ + gpa_t gpa = (gfn << PAGE_SHIFT) + offset; + if (!gfn_is_partial_roe(slot, gfn)) + return false; + return kvm_roe_protected_range(slot, gpa, len); } + void kvm_roe_free(struct kvm_memory_slot *slot) { + struct protected_chunk *pos, *n; + struct list_head *head = slot->prot_list; + kvfree(slot->roe_bitmap); + kvfree(slot->partial_roe_bitmap); + list_for_each_entry_safe(pos, n, head, list) { + list_del(&pos->list); + kvfree(pos); + } + kvfree(slot->prot_list); } static void kvm_roe_protect_slot(struct kvm *kvm, struct kvm_memory_slot *slot, - gfn_t gfn, u64 npages) + gfn_t gfn, u64 npages, bool partial) { int i; + void *bitmap; + if (partial) + bitmap = slot->partial_roe_bitmap; + else + bitmap = slot->roe_bitmap; for (i = gfn - slot->base_gfn; i < gfn + npages - slot->base_gfn; i++) - set_bit(i, slot->roe_bitmap); + set_bit(i, bitmap); kvm_roe_arch_commit_protection(kvm, slot); } -static int __kvm_roe_protect_range(struct kvm *kvm, gpa_t gpa, u64 npages) +static int __kvm_roe_protect_range(struct kvm *kvm, gpa_t gpa, u64 npages, + bool partial) { struct kvm_memory_slot *slot; gfn_t gfn = gpa >> PAGE_SHIFT; @@ -54,12 +109,12 @@ static int __kvm_roe_protect_range(struct kvm *kvm, gpa_t gpa, u64 npages) if (gfn + npages > slot->base_gfn + slot->npages) { u64 _npages = slot->base_gfn + slot->npages - gfn; - kvm_roe_protect_slot(kvm, slot, gfn, _npages); + kvm_roe_protect_slot(kvm, slot, gfn, _npages, partial); gfn += _npages; count += _npages; npages -= _npages; } else { - kvm_roe_protect_slot(kvm, slot, gfn, npages); + kvm_roe_protect_slot(kvm, slot, gfn, npages, partial); count += npages; npages = 0; } @@ -69,12 +124,13 @@ static int __kvm_roe_protect_range(struct kvm *kvm, gpa_t gpa, u64 npages) return count; } -static int kvm_roe_protect_range(struct kvm *kvm, gpa_t gpa, u64 npages) +static int kvm_roe_protect_range(struct kvm *kvm, gpa_t gpa, u64 npages, + bool partial) { int r; mutex_lock(&kvm->slots_lock); - r = __kvm_roe_protect_range(kvm, gpa, npages); + r = __kvm_roe_protect_range(kvm, gpa, npages, partial); mutex_unlock(&kvm->slots_lock); return r; } @@ -103,7 +159,7 @@ static int kvm_roe_full_protect_range(struct kvm_vcpu *vcpu, u64 gva, continue; if (!access_ok(VERIFY_WRITE, hva, 1 << PAGE_SHIFT)) continue; - status = kvm_roe_protect_range(vcpu->kvm, gpa, 1); + status = kvm_roe_protect_range(vcpu->kvm, gpa, 1, false); if (status > 0) count += status; } @@ -112,6 +168,139 @@ static int kvm_roe_full_protect_range(struct kvm_vcpu *vcpu, u64 gva, return count; } +static int kvm_roe_insert_chunk_next(struct list_head *pos, u64 gpa, u64 size) +{ + struct protected_chunk *chunk; + + chunk = kvzalloc(sizeof(struct protected_chunk), GFP_KERNEL); + chunk->gpa = gpa; + chunk->size = size; + INIT_LIST_HEAD(&chunk->list); + list_add(&chunk->list, pos); + return size; +} + +static int kvm_roe_expand_chunk(struct protected_chunk *pos, u64 gpa, u64 size) +{ + u64 old_ptr = pos->gpa; + u64 old_size = pos->size; + + if (gpa < old_ptr) + pos->gpa = gpa; + if (gpa + size > old_ptr + old_size) + pos->size = gpa + size - pos->gpa; + return size; +} + +static bool kvm_roe_merge_chunks(struct protected_chunk *chunk) +{ + /*attempt merging 2 consecutive given the first one*/ + struct protected_chunk *next = list_next_entry(chunk, list); + + if (!kvm_roe_range_overlap(chunk, next->gpa, next->size)) + return false; + kvm_roe_expand_chunk(chunk, next->gpa, next->size); + list_del(&next->list); + kvfree(next); + return true; +} + +static int __kvm_roe_insert_chunk(struct kvm_memory_slot *slot, u64 gpa, + u64 size) +{ + /* kvm->slots_lock must be acquired*/ + struct protected_chunk *pos; + struct list_head *head = slot->prot_list; + + if (list_empty(head)) + return kvm_roe_insert_chunk_next(head, gpa, size); + /* + * pos here will never get deleted maybe the next one will + * that is why list_for_each_entry_safe is completely unsafe + */ + list_for_each_entry(pos, head, list) { + if (kvm_roe_range_overlap(pos, gpa, size)) { + int ret = kvm_roe_expand_chunk(pos, gpa, size); + + while (head != pos->list.next) + if (!kvm_roe_merge_chunks(pos)) + break; + return ret; + } + if (pos->gpa > gpa) { + struct protected_chunk *prev; + + prev = list_prev_entry(pos, list); + return kvm_roe_insert_chunk_next(&prev->list, gpa, + size); + } + } + pos = list_last_entry(head, struct protected_chunk, list); + + return kvm_roe_insert_chunk_next(&pos->list, gpa, size); +} + +static int kvm_roe_insert_chunk(struct kvm *kvm, u64 gpa, u64 size) +{ + struct kvm_memory_slot *slot; + gfn_t gfn = gpa >> PAGE_SHIFT; + int ret; + + mutex_lock(&kvm->slots_lock); + slot = gfn_to_memslot(kvm, gfn); + ret = __kvm_roe_insert_chunk(slot, gpa, size); + mutex_unlock(&kvm->slots_lock); + return ret; +} + +static int kvm_roe_partial_page_protect(struct kvm_vcpu *vcpu, u64 gva, + u64 size) +{ + gpa_t gpa = kvm_mmu_gva_to_gpa_system(vcpu, gva, NULL); + + kvm_roe_protect_range(vcpu->kvm, gpa, 1, true); + return kvm_roe_insert_chunk(vcpu->kvm, gpa, size); +} + +static int kvm_roe_partial_protect(struct kvm_vcpu *vcpu, u64 gva, u64 size) +{ + u64 gva_start = gva; + u64 gva_end = gva+size; + u64 gpn_start = gva_start >> PAGE_SHIFT; + u64 gpn_end = gva_end >> PAGE_SHIFT; + u64 _size; + int count = 0; + // We need to make sure that there will be no overflow or zero size + if (gva_end <= gva_start) + return -EINVAL; + + // protect the partial page at the start + if (gpn_end > gpn_start) + _size = PAGE_SIZE - (gva_start & PAGE_MASK) + 1; + else + _size = size; + size -= _size; + count += kvm_roe_partial_page_protect(vcpu, gva_start, _size); + // full protect in the middle pages + if (gpn_end - gpn_start > 1) { + int ret; + u64 _gva = (gpn_start + 1) << PAGE_SHIFT; + u64 npages = gpn_end - gpn_start - 1; + + size -= npages << PAGE_SHIFT; + ret = kvm_roe_full_protect_range(vcpu, _gva, npages); + if (ret > 0) + count += ret << PAGE_SHIFT; + } + // protect the partial page at the end + if (size != 0) + count += kvm_roe_partial_page_protect(vcpu, + gpn_end << PAGE_SHIFT, size); + if (count == 0) + return -EINVAL; + return count; +} + int kvm_roe(struct kvm_vcpu *vcpu, u64 a0, u64 a1, u64 a2, u64 a3) { int ret; @@ -123,11 +312,14 @@ int kvm_roe(struct kvm_vcpu *vcpu, u64 a0, u64 a1, u64 a2, u64 a3) return -KVM_ENOSYS; switch (a0) { case ROE_VERSION: - ret = 1; //current version + ret = 2; //current version break; case ROE_MPROTECT: ret = kvm_roe_full_protect_range(vcpu, a1, a2); break; + case ROE_MPROTECT_CHUNK: + ret = kvm_roe_partial_protect(vcpu, a1, a2); + break; default: ret = -EINVAL; } diff --git a/virt/kvm/roe_generic.h b/virt/kvm/roe_generic.h index 36e5b52c5b..ad121372f2 100644 --- a/virt/kvm/roe_generic.h +++ b/virt/kvm/roe_generic.h @@ -12,8 +12,14 @@ void kvm_roe_free(struct kvm_memory_slot *slot); int kvm_roe_init(struct kvm_memory_slot *slot); +bool kvm_roe_check_range(struct kvm_memory_slot *slot, gfn_t gfn, int offset, + int len); static inline bool gfn_is_full_roe(struct kvm_memory_slot *slot, gfn_t gfn) { return test_bit(gfn - slot->base_gfn, slot->roe_bitmap); } +static inline bool gfn_is_partial_roe(struct kvm_memory_slot *slot, gfn_t gfn) +{ + return test_bit(gfn - slot->base_gfn, slot->partial_roe_bitmap); +} #endif From patchwork Fri Dec 7 12:48:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ahmed Abd El Mawgood X-Patchwork-Id: 10718105 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B6D281750 for ; Fri, 7 Dec 2018 12:57:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9FF062E006 for ; Fri, 7 Dec 2018 12:57:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8FB2B2E01B; Fri, 7 Dec 2018 12:57:59 +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=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id C157E2E006 for ; Fri, 7 Dec 2018 12:57:58 +0000 (UTC) Received: (qmail 14281 invoked by uid 550); 7 Dec 2018 12:56:19 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Delivered-To: moderator for kernel-hardening@lists.openwall.com Received: (qmail 3158 invoked from network); 7 Dec 2018 12:49:38 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mena-vt-edu.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ibxTSM7aAfMxp0mh34e5XoCF9bu27Z34+6gCZTrPT34=; b=ZtGj2HHQ1QdQqkzxKnkhyG6zbN40ooJhtxiFxmtMZB2G6JXMbNVeLRlBclZc1ByuBt rJkGbokdWxQ0B4Z/lVF47mJXfpvZg6onuNs38evpR6F0plHgzidl0tnlt5rJTh3WpIX0 xXvr8J/Yp27UtUoFGtdUgpFJ6up0leTOytBXoBP3vyuv2whs8HO6r7g4e5dNAiOckiEq S4Jkfj+slyqpYESweAypsVAe8xa4+M+/i961soZgwCd01iqS8UtJC/jK7GFRWxJ15VKF iteVo2+659CaouRtxIESOgKb838vu10UoGWA0UJYtGjsBcL2ia6Cz6nFHafS5PeNz3tx ntcQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ibxTSM7aAfMxp0mh34e5XoCF9bu27Z34+6gCZTrPT34=; b=oTtsH99TPrH91S80YL3/cxaGg3O9sBd+jU0+lsozoHpFR1YCElaM1S74I5dSRWbnSj xPv9izvIF8mCkAj4iBKK73mmqG5Oo4HLZJdjsAiZUPsvZL4kNcHzdy09TtQ5b7m9qRWV y06WNxkAKCylANkKYV51PJw4zCJwMnPApu7zqoyT4CzgcZw6gnWLcgFdUHgfUSRziFO7 PpldihUNIH4bO96uYF3kVrj1Lb7nLoAo79GsUhpNXDk7JE84h3PCqCWy+3tVrRHj7Bln oqMKrasXlRctMkJ4qqQvdSD7yotG8FjnWBbvjzjGu/djpIZd7QruOkH1fWLxQfF4rZ/i uqLw== X-Gm-Message-State: AA+aEWbzEIpnKugAj5f3CNDlEtT8vZPmj2xn+HyXMzXbYLxHPwNmDTjf 1oUa+pAwXvrcRrpj41I5IHqg2g== X-Google-Smtp-Source: AFSGD/XycEJqUK3+cMbWlXGqoLuR+oFh9trApfppGt82EltYcdXfLPRSVVY6b30XONttXSMdK4nsLQ== X-Received: by 2002:adf:c846:: with SMTP id e6mr1624715wrh.243.1544186966936; Fri, 07 Dec 2018 04:49:26 -0800 (PST) From: Ahmed Abd El Mawgood To: Paolo Bonzini , rkrcmar@redhat.com, Jonathan Corbet , Thomas Gleixner , Ingo Molnar , Borislav Petkov , hpa@zytor.com, x86@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, ahmedsoliman0x666@gmail.com, ovich00@gmail.com, kernel-hardening@lists.openwall.com, nigel.edwards@hpe.com, Boris Lukashev , Igor Stoppa Cc: Ahmed Abd El Mawgood Subject: [PATCH 08/10] KVM: X86: Port ROE_MPROTECT_CHUNK to x86 Date: Fri, 7 Dec 2018 14:48:01 +0200 Message-Id: <20181207124803.10828-9-ahmedsoliman@mena.vt.edu> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> References: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> MIME-Version: 1.0 X-Virus-Scanned: ClamAV using ClamSMTP Apply d->memslot->partial_roe_bitmap to shadow page table entries too. Signed-off-by: Ahmed Abd El Mawgood --- arch/x86/kvm/roe.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/roe.c b/arch/x86/kvm/roe.c index f787106be8..700f69823b 100644 --- a/arch/x86/kvm/roe.c +++ b/arch/x86/kvm/roe.c @@ -25,11 +25,14 @@ static bool __rmap_write_protect_roe(struct kvm *kvm, struct rmap_iterator iter; bool prot; bool flush = false; + void *full_bmp = memslot->roe_bitmap; + void *part_bmp = memslot->partial_roe_bitmap; for_each_rmap_spte(rmap_head, &iter, sptep) { int idx = spte_to_gfn(sptep) - memslot->base_gfn; - prot = !test_bit(idx, memslot->roe_bitmap) && pt_protect; + prot = !(test_bit(idx, full_bmp) || test_bit(idx, part_bmp)); + prot = prot && pt_protect; flush |= spte_write_protect(sptep, prot); } return flush; From patchwork Fri Dec 7 12:48:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ahmed Abd El Mawgood X-Patchwork-Id: 10718107 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9F4731759 for ; Fri, 7 Dec 2018 12:58:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8F40F2E006 for ; Fri, 7 Dec 2018 12:58:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 828D42E01B; Fri, 7 Dec 2018 12:58:23 +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=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id 6B4EC2E006 for ; Fri, 7 Dec 2018 12:58:22 +0000 (UTC) Received: (qmail 15453 invoked by uid 550); 7 Dec 2018 12:56:22 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Delivered-To: moderator for kernel-hardening@lists.openwall.com Received: (qmail 3214 invoked from network); 7 Dec 2018 12:49:42 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mena-vt-edu.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=6aBx4Uf0AXPUXYaYC8L7IOOvH1hBcTiqrQSEjZvFMvY=; b=ZRLrCoeXD9HW8NIerF03oCdBCfs49Kp1L+4nSKW3GXD2Oq7tL/6qr6EIac2uT/L0el DPWzzOG+eEgD/0CL1mm/lzRuqDFU+j7TXH05SlfQOurMEQpG0S4fTGcgQveCjfkHmJaI pCTNXx5TrQmu8OJZeNA3vWJ+SgSft7oEwlepT2AFDZXeGXqvfsIkEUVwyGrtWJfN/Uti QrqdD+0d+avOGwZHD+JXLAr9++3byKWfskeJv9HgdL1DfhB2Ki4prBhvK9q3w5vvDJ12 zMoR4r0b2LmF2kZvzdwd8smerBUM+M6obbMfBIoyeFSHT+JT5lOx6MlH8cJvvyCk6oSP 6jrQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=6aBx4Uf0AXPUXYaYC8L7IOOvH1hBcTiqrQSEjZvFMvY=; b=Xf+DFsJh5yyTgxMn1fFDdDc/rAvjF2GaiX3wDVfjM1HvYy7rPGRIP8H25RH4QTpQfl drqzflw4yUOtZiWF9qzKaRX5A3fwuxltvBhYvSndO1PcvLiPwMwIWQ+pE2PN9q0AAnKp 0OLY0gjSEt+7/PqSZRZxNEGKHLXNSDv9YkMCvAV442lxPQmdbrQP+hpx9iwI3xgEN4PJ DYk1tSDiUCvQtkn5qgautFV8aknWxsE/vFjfo6FnGTNdXzyI/YKzH+ggnrNjF9tZ8SrI 08aNh0iMBtC7Ll7tDNZUtZt8dlf/E+ID/e9AOEtvLBNwt3hez5Mg5TDq7P2dvsWS+xaT 23Tg== X-Gm-Message-State: AA+aEWauYxV4IUK17ud87o54ZfmJ7uY81L/u4vkTUqzvmcpSRxmE1XN2 fn5Yspmi4cUcmOxRv5+LNQEcMA== X-Google-Smtp-Source: AFSGD/UgbVwxu0T4GOFk5WoSSvUhKOVLjgnI86o17K0DWzUsnEBQw6xC+04yacjI7Psv/elfu6Qi9A== X-Received: by 2002:a1c:2b45:: with SMTP id r66mr2063076wmr.7.1544186971172; Fri, 07 Dec 2018 04:49:31 -0800 (PST) From: Ahmed Abd El Mawgood To: Paolo Bonzini , rkrcmar@redhat.com, Jonathan Corbet , Thomas Gleixner , Ingo Molnar , Borislav Petkov , hpa@zytor.com, x86@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, ahmedsoliman0x666@gmail.com, ovich00@gmail.com, kernel-hardening@lists.openwall.com, nigel.edwards@hpe.com, Boris Lukashev , Igor Stoppa Cc: Ahmed Abd El Mawgood Subject: [PATCH 09/10] KVM: Add new exit reason For ROE violations Date: Fri, 7 Dec 2018 14:48:02 +0200 Message-Id: <20181207124803.10828-10-ahmedsoliman@mena.vt.edu> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> References: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> MIME-Version: 1.0 X-Virus-Scanned: ClamAV using ClamSMTP The problem is that qemu will not be able to detect ROE violations, so one option would be create host API to tell if a given page is ROE protected, or create ROE violation exit reason. Signed-off-by: Ahmed Abd El Mawgood --- arch/x86/kvm/x86.c | 10 +++++++++- include/kvm/roe.h | 12 ++++++++++++ include/uapi/linux/kvm.h | 2 +- virt/kvm/kvm_main.c | 1 + virt/kvm/roe.c | 2 +- virt/kvm/roe_generic.h | 9 +-------- 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 28475c83f9..ddd15bb1a7 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5334,6 +5334,7 @@ static int emulator_read_write(struct x86_emulate_ctxt *ctxt, const struct read_write_emulator_ops *ops) { struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); + struct kvm_memory_slot *slot; gpa_t gpa; int rc; @@ -5375,7 +5376,14 @@ static int emulator_read_write(struct x86_emulate_ctxt *ctxt, vcpu->run->mmio.len = min(8u, vcpu->mmio_fragments[0].len); vcpu->run->mmio.is_write = vcpu->mmio_is_write = ops->write; - vcpu->run->exit_reason = KVM_EXIT_MMIO; + slot = kvm_vcpu_gfn_to_memslot(vcpu, gpa >> PAGE_SHIFT); + if (slot && ops->write && (kvm_roe_check_range(slot, gpa>>PAGE_SHIFT, + gpa - (gpa & PAGE_MASK), bytes) || + gfn_is_full_roe(slot, gpa>>PAGE_SHIFT))) + vcpu->run->exit_reason = KVM_EXIT_ROE; + else + vcpu->run->exit_reason = KVM_EXIT_MMIO; + vcpu->run->mmio.phys_addr = gpa; return ops->read_write_exit_mmio(vcpu, gpa, val, bytes); diff --git a/include/kvm/roe.h b/include/kvm/roe.h index 6a86866623..3121a67753 100644 --- a/include/kvm/roe.h +++ b/include/kvm/roe.h @@ -13,4 +13,16 @@ void kvm_roe_arch_commit_protection(struct kvm *kvm, struct kvm_memory_slot *slot); int kvm_roe(struct kvm_vcpu *vcpu, u64 a0, u64 a1, u64 a2, u64 a3); bool kvm_roe_arch_is_userspace(struct kvm_vcpu *vcpu); +bool kvm_roe_check_range(struct kvm_memory_slot *slot, gfn_t gfn, int offset, + int len); +static inline bool gfn_is_full_roe(struct kvm_memory_slot *slot, gfn_t gfn) +{ + return test_bit(gfn - slot->base_gfn, slot->roe_bitmap); + +} +static inline bool gfn_is_partial_roe(struct kvm_memory_slot *slot, gfn_t gfn) +{ + return test_bit(gfn - slot->base_gfn, slot->partial_roe_bitmap); +} + #endif diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 2b7a652c9f..185767e512 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -235,7 +235,7 @@ struct kvm_hyperv_exit { #define KVM_EXIT_S390_STSI 25 #define KVM_EXIT_IOAPIC_EOI 26 #define KVM_EXIT_HYPERV 27 - +#define KVM_EXIT_ROE 28 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ #define KVM_INTERNAL_ERROR_EMULATION 1 diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 0d129b05d5..c3a21d3bc8 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -62,6 +62,7 @@ #include "async_pf.h" #include "vfio.h" #include "roe_generic.h" +#include #define CREATE_TRACE_POINTS #include diff --git a/virt/kvm/roe.c b/virt/kvm/roe.c index dfb1de314c..6555838f0c 100644 --- a/virt/kvm/roe.c +++ b/virt/kvm/roe.c @@ -60,7 +60,7 @@ bool kvm_roe_check_range(struct kvm_memory_slot *slot, gfn_t gfn, int offset, return false; return kvm_roe_protected_range(slot, gpa, len); } - +EXPORT_SYMBOL_GPL(kvm_roe_check_range); void kvm_roe_free(struct kvm_memory_slot *slot) { diff --git a/virt/kvm/roe_generic.h b/virt/kvm/roe_generic.h index ad121372f2..f1ce4a8aec 100644 --- a/virt/kvm/roe_generic.h +++ b/virt/kvm/roe_generic.h @@ -14,12 +14,5 @@ void kvm_roe_free(struct kvm_memory_slot *slot); int kvm_roe_init(struct kvm_memory_slot *slot); bool kvm_roe_check_range(struct kvm_memory_slot *slot, gfn_t gfn, int offset, int len); -static inline bool gfn_is_full_roe(struct kvm_memory_slot *slot, gfn_t gfn) -{ - return test_bit(gfn - slot->base_gfn, slot->roe_bitmap); -} -static inline bool gfn_is_partial_roe(struct kvm_memory_slot *slot, gfn_t gfn) -{ - return test_bit(gfn - slot->base_gfn, slot->partial_roe_bitmap); -} + #endif From patchwork Fri Dec 7 12:48:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ahmed Abd El Mawgood X-Patchwork-Id: 10718109 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7D71E1750 for ; Fri, 7 Dec 2018 12:58:48 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6CC822DB3B for ; Fri, 7 Dec 2018 12:58:48 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 605452DC57; Fri, 7 Dec 2018 12:58:48 +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=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id 8CB912DB3B for ; Fri, 7 Dec 2018 12:58:47 +0000 (UTC) Received: (qmail 15680 invoked by uid 550); 7 Dec 2018 12:56:27 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Delivered-To: moderator for kernel-hardening@lists.openwall.com Received: (qmail 3295 invoked from network); 7 Dec 2018 12:49:46 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mena-vt-edu.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=8WR3nfZ+UXawr7R//GnRUy/7E5Oz6Kr5I5N3ItmtOwA=; b=XgJFjDXXpxuO5DPzmfvD7ouX2XxqdC6F4pcGXKK0R2tvBXJyw+Nw5D38eOQKsUv1yJ w/DIegcnPPPWksE8FPD5ium12Lvwj6kPzCoek9IsWuK7gwEDoMt7dR9zTdkS+T9s9bvq ZLAsnkr91HoIltBgUbHteWWnl1Hh3XhHRQDYlhY+rzJLRRT/L9mYY5J5R4Iy5LXlvi9j z7ch89Mf2xau8p8XP7PJzWvQ6/wUrjKuz3VZPvW+Zo28sQNrFswQiwGz4XzlxcPy2dlz oSY3/koIjjyHIri9oT4KDnieBCua/yB8JxnS69UUKcxzElquzW2ljPTlPoFBqAKpXBJu 7aYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=8WR3nfZ+UXawr7R//GnRUy/7E5Oz6Kr5I5N3ItmtOwA=; b=epp1o4WKltKXUbxv/5Ub+ABlX+WEJktPNPRIr2yYq5z5L0Jo4ReMh7fXbFjQzC4CSL hK/K9OATpZ3gDzJncWxwBR5yISQGC2/JTe5m1+PpUPcQ8lNuQeKWBidEAHRFaXIWIqqm x/BSRAaJDVYpgLvyWAT6nhYgl34BVXFaAkUzm+cCqkzfXwc/0MWuuMstDXFsBHj7W45P WJlGOf/vjGUh4w+uuhQeKdgRKxx/cSMD4EFdhwKQo3Q4HgGk5x5yM031o4XhvsPMoCMr ROYv5YTEb+bPr6CbQsvU1uYKLGKx4B6pxAvUj+48KIV/53LOVcgFxOSbuOP4T/jNLtSH F+pA== X-Gm-Message-State: AA+aEWa3ZiCOl39TyRzEt5+Y67KD/BQTqsnUmbNiQ694m+hRVu6ufLHR 7zWaDURX5fIK+529eAzB1jqiZA== X-Google-Smtp-Source: AFSGD/Uvbb9zxQ6Le59/z2g9FbUPsfQ3vtkpDzJJRcigKi93yPTIA3dAjUHEfENdbeVJt5hQt2tGqA== X-Received: by 2002:adf:e707:: with SMTP id c7mr1616063wrm.196.1544186975504; Fri, 07 Dec 2018 04:49:35 -0800 (PST) From: Ahmed Abd El Mawgood To: Paolo Bonzini , rkrcmar@redhat.com, Jonathan Corbet , Thomas Gleixner , Ingo Molnar , Borislav Petkov , hpa@zytor.com, x86@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, ahmedsoliman0x666@gmail.com, ovich00@gmail.com, kernel-hardening@lists.openwall.com, nigel.edwards@hpe.com, Boris Lukashev , Igor Stoppa Cc: Ahmed Abd El Mawgood Subject: [PATCH 10/10] KVM: Log ROE violations in system log Date: Fri, 7 Dec 2018 14:48:03 +0200 Message-Id: <20181207124803.10828-11-ahmedsoliman@mena.vt.edu> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> References: <20181207124803.10828-1-ahmedsoliman@mena.vt.edu> MIME-Version: 1.0 X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Ahmed Abd El Mawgood --- virt/kvm/kvm_main.c | 5 +++++ virt/kvm/roe.c | 14 ++++++++++++++ virt/kvm/roe_generic.h | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index c3a21d3bc8..661933053f 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1870,6 +1870,7 @@ static u64 roe_gfn_to_hva(struct kvm_memory_slot *slot, gfn_t gfn, int offset, addr = __gfn_to_hva_many(slot, gfn, NULL, false); return addr; } + static int __kvm_write_guest_page(struct kvm_memory_slot *memslot, gfn_t gfn, const void *data, int offset, int len) { @@ -1877,6 +1878,10 @@ static int __kvm_write_guest_page(struct kvm_memory_slot *memslot, gfn_t gfn, unsigned long addr; addr = roe_gfn_to_hva(memslot, gfn, offset, len); + if (gfn_is_full_roe(memslot, gfn) || + kvm_roe_check_range(memslot, gfn, offset, len)) + kvm_warning_roe_violation((gfn << PAGE_SHIFT) + offset, data, + len); if (kvm_is_error_hva(addr)) return -EFAULT; r = __copy_to_user((void __user *)addr + offset, data, len); diff --git a/virt/kvm/roe.c b/virt/kvm/roe.c index 6555838f0c..36b85fb303 100644 --- a/virt/kvm/roe.c +++ b/virt/kvm/roe.c @@ -76,6 +76,20 @@ void kvm_roe_free(struct kvm_memory_slot *slot) kvfree(slot->prot_list); } +void kvm_warning_roe_violation(u64 addr, const void *data, int len) +{ + int i; + const char *d = data; + char *buf = kvmalloc(len * 3 + 1, GFP_KERNEL); + + for (i = 0; i < len; i++) + sprintf(buf+3*i, " %02x", d[i]); + pr_warn("ROE violation:\n"); + pr_warn("\tAttempt to write %d bytes at address 0x%08llx\n", len, addr); + pr_warn("\tData: %s\n", buf); + kvfree(buf); +} + static void kvm_roe_protect_slot(struct kvm *kvm, struct kvm_memory_slot *slot, gfn_t gfn, u64 npages, bool partial) { diff --git a/virt/kvm/roe_generic.h b/virt/kvm/roe_generic.h index f1ce4a8aec..8c191362cd 100644 --- a/virt/kvm/roe_generic.h +++ b/virt/kvm/roe_generic.h @@ -14,5 +14,5 @@ void kvm_roe_free(struct kvm_memory_slot *slot); int kvm_roe_init(struct kvm_memory_slot *slot); bool kvm_roe_check_range(struct kvm_memory_slot *slot, gfn_t gfn, int offset, int len); - +void kvm_warning_roe_violation(u64 addr, const void *data, int len); #endif