Received: by 2002:a05:6a10:af89:0:0:0:0 with SMTP id iu9csp3721585pxb; Mon, 24 Jan 2022 16:18:47 -0800 (PST) X-Google-Smtp-Source: ABdhPJz51Fdn5o8Ye9mh0pvTgHYXYlcug2KMWW9Xaf7yGtMtrMWBZ/VTDLoxUmDUoQjbWmmtlGDk X-Received: by 2002:aa7:8e06:0:b0:4c8:fab2:4b2d with SMTP id c6-20020aa78e06000000b004c8fab24b2dmr7784077pfr.27.1643069927232; Mon, 24 Jan 2022 16:18:47 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1643069927; cv=none; d=google.com; s=arc-20160816; b=Bde//d9O9/8zb18CjdmHipuR7H7R3uJ5Z2tt2eTjksPOeTUKl41oE8Ze0syW9WiT6l 6FOlXDu/C5SNOd2WPxs65ozC8RyNSEmDlVkRZDKOiEHH3aypTc1chASR/9xBqn1uFkyz tFE9Or7UE9fFjzl3SIhTnXwJ6eBfoKCy60XhBJBTVjEdTbaZzAEE9sieKqRA4W6FJQzD T4F5Q65JDNVEXUleL2V0sSoh+N4iIUjuCf1gwpxwIwe3opfHxii6hWQjA4g/VBLUxewH +LsBodw0kFF2n+RAdctfq4yVHjf99eKttJjA8l7QB3BK8oz2Iie2yccvo08rxWS+cDlF lEiA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=MlTBX17eiPkvfQ2HLE8X6tFQ4Y1sE+Mc3X2V2rh+JRA=; b=InOz+swWSFMam3NERthIyL9jgsdMvam/0KOUmko/DxdPtqG85C8Ilx9hweWA9sX44J tUW4VPM+QLl2L1KMO2WLJ4H568IIonJUpBl+MdmwZ6ZxSRxJ9VUKF+1NyUaNwUrfLpJh vvPbtpPj3liITXeL3IXg5Gson/EF/knC8e1qOd64xacwFyaiGvqxs4XjVz3Sn+eUvUm9 TnNBDPPrYZ9e8887Cr9OS8YRl17N2U1KlSB2mGNhTRS0s/O79Hc9p4zY2UeQcXdgIDp2 WGsnTok8KsxJ1H7jS6oWpurWrmiGGqdgmvbCHVwxhaYbCPXtC5sQ9D7npwOUCRlco1Mw fR6w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=Vsx3NpfS; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id d3si14522359pgh.861.2022.01.24.16.18.35; Mon, 24 Jan 2022 16:18:47 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=Vsx3NpfS; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2373069AbiAYANB (ORCPT + 99 others); Mon, 24 Jan 2022 19:13:01 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52996 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1835949AbiAXX20 (ORCPT ); Mon, 24 Jan 2022 18:28:26 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EFFC0C075940; Mon, 24 Jan 2022 13:33:38 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 93C07B80FA1; Mon, 24 Jan 2022 21:33:38 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 007F5C340E4; Mon, 24 Jan 2022 21:33:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1643060017; bh=ifDCbOlvlfDMlQSljIfCesPKWuSzZT3V2906vyaUncs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Vsx3NpfSgi7qWnb05eNWT/kDcxcxJJN5TAbMdOtOzGTArC1+GZSNK5wlO5TFw1k6S zSzLEGMWRoMGD5Pp8e7w47XtUPkr8/UZ8Qz7F23ek5k5YuW31GUFOXm6ULPe+0v/qV 0gn1bEiKY/AgtD+Q+sOOiws1ZgzUlD30cyoqvuwM= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Vitaly Kuznetsov , Michael Kelley , Wei Liu , Sasha Levin Subject: [PATCH 5.16 0812/1039] x86/hyperv: Properly deal with empty cpumasks in hyperv_flush_tlb_multi() Date: Mon, 24 Jan 2022 19:43:21 +0100 Message-Id: <20220124184152.605053380@linuxfoundation.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220124184125.121143506@linuxfoundation.org> References: <20220124184125.121143506@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: Vitaly Kuznetsov [ Upstream commit 51500b71d500f251037ed339047a4d9e7d7e295b ] KASAN detected the following issue: BUG: KASAN: slab-out-of-bounds in hyperv_flush_tlb_multi+0xf88/0x1060 Read of size 4 at addr ffff8880011ccbc0 by task kcompactd0/33 CPU: 1 PID: 33 Comm: kcompactd0 Not tainted 5.14.0-39.el9.x86_64+debug #1 Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS Hyper-V UEFI Release v4.0 12/17/2019 Call Trace: dump_stack_lvl+0x57/0x7d print_address_description.constprop.0+0x1f/0x140 ? hyperv_flush_tlb_multi+0xf88/0x1060 __kasan_report.cold+0x7f/0x11e ? hyperv_flush_tlb_multi+0xf88/0x1060 kasan_report+0x38/0x50 hyperv_flush_tlb_multi+0xf88/0x1060 flush_tlb_mm_range+0x1b1/0x200 ptep_clear_flush+0x10e/0x150 ... Allocated by task 0: kasan_save_stack+0x1b/0x40 __kasan_kmalloc+0x7c/0x90 hv_common_init+0xae/0x115 hyperv_init+0x97/0x501 apic_intr_mode_init+0xb3/0x1e0 x86_late_time_init+0x92/0xa2 start_kernel+0x338/0x3eb secondary_startup_64_no_verify+0xc2/0xcb The buggy address belongs to the object at ffff8880011cc800 which belongs to the cache kmalloc-1k of size 1024 The buggy address is located 960 bytes inside of 1024-byte region [ffff8880011cc800, ffff8880011ccc00) 'hyperv_flush_tlb_multi+0xf88/0x1060' points to hv_cpu_number_to_vp_number() and '960 bytes' means we're trying to get VP_INDEX for CPU#240. 'nr_cpus' here is exactly 240 so we're trying to access past hv_vp_index's last element. This can (and will) happen when 'cpus' mask is empty and cpumask_last() will return '>=nr_cpus'. Commit ad0a6bad4475 ("x86/hyperv: check cpu mask after interrupt has been disabled") tried to deal with empty cpumask situation but apparently didn't fully fix the issue. 'cpus' cpumask which is passed to hyperv_flush_tlb_multi() is 'mm_cpumask(mm)' (which is '&mm->cpu_bitmap'). This mask changes every time the particular mm is scheduled/unscheduled on some CPU (see switch_mm_irqs_off()), disabling IRQs on the CPU which is performing remote TLB flush has zero influence on whether the particular process can get scheduled/unscheduled on _other_ CPUs so e.g. in the case where the mm was scheduled on one other CPU and got unscheduled during hyperv_flush_tlb_multi()'s execution will lead to cpumask becoming empty. It doesn't seem that there's a good way to protect 'mm_cpumask(mm)' from changing during hyperv_flush_tlb_multi()'s execution. It would be possible to copy it in the very beginning of the function but this is a waste. It seems we can deal with changing cpumask just fine. When 'cpus' cpumask changes during hyperv_flush_tlb_multi()'s execution, there are two possible issues: - 'Under-flushing': we will not flush TLB on a CPU which got added to the mask while hyperv_flush_tlb_multi() was already running. This is not a problem as this is equal to mm getting scheduled on that CPU right after TLB flush. - 'Over-flushing': we may flush TLB on a CPU which is already cleared from the mask. First, extra TLB flush preserves correctness. Second, Hyper-V's TLB flush hypercall takes 'mm->pgd' argument so Hyper-V may avoid the flush if CR3 doesn't match. Fix the immediate issue with cpumask_last()/hv_cpu_number_to_vp_number() and remove the pointless cpumask_empty() check from the beginning of the function as it really doesn't protect anything. Also, avoid the hypercall altogether when 'flush->processor_mask' ends up being empty. Fixes: ad0a6bad4475 ("x86/hyperv: check cpu mask after interrupt has been disabled") Signed-off-by: Vitaly Kuznetsov Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/20220106094611.1404218-1-vkuznets@redhat.com Signed-off-by: Wei Liu Signed-off-by: Sasha Levin --- arch/x86/hyperv/mmu.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/x86/hyperv/mmu.c b/arch/x86/hyperv/mmu.c index bd13736d0c054..0ad2378fe6ad7 100644 --- a/arch/x86/hyperv/mmu.c +++ b/arch/x86/hyperv/mmu.c @@ -68,15 +68,6 @@ static void hyperv_flush_tlb_multi(const struct cpumask *cpus, local_irq_save(flags); - /* - * Only check the mask _after_ interrupt has been disabled to avoid the - * mask changing under our feet. - */ - if (cpumask_empty(cpus)) { - local_irq_restore(flags); - return; - } - flush_pcpu = (struct hv_tlb_flush **) this_cpu_ptr(hyperv_pcpu_input_arg); @@ -115,7 +106,9 @@ static void hyperv_flush_tlb_multi(const struct cpumask *cpus, * must. We will also check all VP numbers when walking the * supplied CPU set to remain correct in all cases. */ - if (hv_cpu_number_to_vp_number(cpumask_last(cpus)) >= 64) + cpu = cpumask_last(cpus); + + if (cpu < nr_cpumask_bits && hv_cpu_number_to_vp_number(cpu) >= 64) goto do_ex_hypercall; for_each_cpu(cpu, cpus) { @@ -131,6 +124,12 @@ static void hyperv_flush_tlb_multi(const struct cpumask *cpus, __set_bit(vcpu, (unsigned long *) &flush->processor_mask); } + + /* nothing to flush if 'processor_mask' ends up being empty */ + if (!flush->processor_mask) { + local_irq_restore(flags); + return; + } } /* -- 2.34.1