From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.5 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2A82DC4320A for ; Mon, 26 Jul 2021 16:02:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0E3A560FDA for ; Mon, 26 Jul 2021 16:02:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237296AbhGZPWT (ORCPT ); Mon, 26 Jul 2021 11:22:19 -0400 Received: from mail.kernel.org ([198.145.29.99]:54246 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236896AbhGZPPn (ORCPT ); Mon, 26 Jul 2021 11:15:43 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id C62346056C; Mon, 26 Jul 2021 15:54:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1627314885; bh=+g91EDqtZGLLsoig7Mbbmnh2dGAiLGprv6mcMqVJhVw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jzqttzc1KFlAmYBSAvsco5m6t75cbteuULEoG2tDgsUqrN4DNYrAx68ZEtIXy9yx+ Zb3mJskbjVhVBIyuCmNd7fUuYrpnLkLABmMCPx7cYxJPkDPiKKKNRSYY8o0qrKcP/j obmYCAzO7bogdlQymW8E8KED3qOQEGxJm7WMlQkk= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Nicholas Piggin , Paolo Bonzini , Ovidiu Panait Subject: [PATCH 4.19 112/120] KVM: do not allow mapping valid but non-reference-counted pages Date: Mon, 26 Jul 2021 17:39:24 +0200 Message-Id: <20210726153836.067876550@linuxfoundation.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210726153832.339431936@linuxfoundation.org> References: <20210726153832.339431936@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Nicholas Piggin commit f8be156be163a052a067306417cd0ff679068c97 upstream. It's possible to create a region which maps valid but non-refcounted pages (e.g., tail pages of non-compound higher order allocations). These host pages can then be returned by gfn_to_page, gfn_to_pfn, etc., family of APIs, which take a reference to the page, which takes it from 0 to 1. When the reference is dropped, this will free the page incorrectly. Fix this by only taking a reference on valid pages if it was non-zero, which indicates it is participating in normal refcounting (and can be released with put_page). This addresses CVE-2021-22543. Signed-off-by: Nicholas Piggin Tested-by: Paolo Bonzini Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: Ovidiu Panait Signed-off-by: Greg Kroah-Hartman --- virt/kvm/kvm_main.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1489,6 +1489,13 @@ static bool vma_is_valid(struct vm_area_ return true; } +static int kvm_try_get_pfn(kvm_pfn_t pfn) +{ + if (kvm_is_reserved_pfn(pfn)) + return 1; + return get_page_unless_zero(pfn_to_page(pfn)); +} + static int hva_to_pfn_remapped(struct vm_area_struct *vma, unsigned long addr, bool *async, bool write_fault, bool *writable, @@ -1538,13 +1545,21 @@ static int hva_to_pfn_remapped(struct vm * Whoever called remap_pfn_range is also going to call e.g. * unmap_mapping_range before the underlying pages are freed, * causing a call to our MMU notifier. + * + * Certain IO or PFNMAP mappings can be backed with valid + * struct pages, but be allocated without refcounting e.g., + * tail pages of non-compound higher order allocations, which + * would then underflow the refcount when the caller does the + * required put_page. Don't allow those pages here. */ - kvm_get_pfn(pfn); + if (!kvm_try_get_pfn(pfn)) + r = -EFAULT; out: pte_unmap_unlock(ptep, ptl); *p_pfn = pfn; - return 0; + + return r; } /*