Received: by 2002:a05:6a10:1d13:0:0:0:0 with SMTP id pp19csp2911497pxb; Tue, 24 Aug 2021 10:25:15 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxqWHkXwfPoiRWtu6+Emu94IBKJoCr5MdR6JuK0sbhqk9XBy3W3NuXK5b6PvyQc1k47YpdH X-Received: by 2002:a92:c26f:: with SMTP id h15mr21743891ild.47.1629825914834; Tue, 24 Aug 2021 10:25:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1629825914; cv=none; d=google.com; s=arc-20160816; b=EfsFjxLJAtQtPLF7nnCn/T998Zl4Y2V9CfpKJ6k03e+YqCsEr0o5IUkakwprQFpSua mt/peP19QfDr6FNHA/BZJ0RySWXvmuYeLojzP/r6soB1SOkchtjFlWujsysQ8hbHx15F umXFS9nCF/KXTR7sQXJJPUlAxGJcHOaw9wcRj6XXLuKvk841yN/esGlqYa++0X1M4ljF 1ActLH7WjANR5Hfo+t+S/PfuokullfqhQmuVkk6XLVxQBFQgUwzQcTsR16iUal1nJmRR HZiD9kciyX4QSLFbZqGbzKFgV2rclkUyq6Ufvw679Bh843MVFzmSDAd8vv66LiSYZjy5 q7wQ== 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 :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=rzaQRYq1NhkJkfUYNq/gHFBdyUzmSg+/YYs+VmMZZE4=; b=T/w9QBYj5C9P/2BQFb2JOSiEmd9JiAIuOxEj5QVucxWwP/dLXEn0/QXHxUqj1uXTwV vaZbeeHeEi4SiTQTzEmux4DQd/ET+n3QkONaYgeI7Yiu0SuBtzU7icGt9itYRoug3UC/ iCV7Iwv6mmCmAjTaKOhRolCxkbv+KxRlfq4/IwNnsfQM2OF48BWXOA0APNBgzNDPlpHX xzatWpuFQyqX+8jNvo0ww3+wZAxPx9ydjGpY7vMLGiSjUyf0iT+Eexj0EpLHAMAecmmH PzGOFiF+OX/19CalgGXKaU4th8L2IiJOR/fTmA7jnP3+mN6SAJAbRL/xB3EMehJHv59M w0Ag== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=Hfnte5R7; 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=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id y20si198463jao.34.2021.08.24.10.25.02; Tue, 24 Aug 2021 10:25:14 -0700 (PDT) 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=@kernel.org header.s=k20201202 header.b=Hfnte5R7; 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=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239851AbhHXRXI (ORCPT + 99 others); Tue, 24 Aug 2021 13:23:08 -0400 Received: from mail.kernel.org ([198.145.29.99]:56898 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241087AbhHXRT4 (ORCPT ); Tue, 24 Aug 2021 13:19:56 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id D4C4E61AAA; Tue, 24 Aug 2021 17:03:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1629824593; bh=bajO0Kol85BvNrCsoksz87gJnb3Par/bcbLe53eKC6U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Hfnte5R7BzRC6iB9npvzJ3Kj5Ll32jyDLaR67PuerRY0xKEVJLGtS9LxVBrMEC2Qh 5ccsJBI/5jnvkqaDnhej+M4L+d8s7yJZsHESbU5KcVh+WI12Pg8qNzeCCwUcJMCDBt ZqemkM7CnKG9B8rJam50mZs7sLZUSyE6cvmZdsJw9HF+lT9+FuGMwB4/o5kgZvL31O yBiJ0IeCpRZ2Z2d5/mzgZNkn5TbacZL4R+jYG3m8Duf8v3Pr/3MDMgtBHBkN5oPDKY qjnio3A1MPfM2qhZwejk6NTtCiA11gPsbNwWWsuM88VtZoNCtN7cMV0S4vECtwRVQp iWLHMM12OVL3A== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Maximilian Heyne , Boris Ostrovsky , Sasha Levin Subject: [PATCH 4.19 22/84] xen/events: Fix race in set_evtchn_to_irq Date: Tue, 24 Aug 2021 13:01:48 -0400 Message-Id: <20210824170250.710392-23-sashal@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210824170250.710392-1-sashal@kernel.org> References: <20210824170250.710392-1-sashal@kernel.org> MIME-Version: 1.0 X-KernelTest-Patch: http://kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.19.205-rc1.gz X-KernelTest-Tree: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git X-KernelTest-Branch: linux-4.19.y X-KernelTest-Patches: git://git.kernel.org/pub/scm/linux/kernel/git/stable/stable-queue.git X-KernelTest-Version: 4.19.205-rc1 X-KernelTest-Deadline: 2021-08-26T17:02+00:00 X-stable: review X-Patchwork-Hint: Ignore Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Maximilian Heyne [ Upstream commit 88ca2521bd5b4e8b83743c01a2d4cb09325b51e9 ] There is a TOCTOU issue in set_evtchn_to_irq. Rows in the evtchn_to_irq mapping are lazily allocated in this function. The check whether the row is already present and the row initialization is not synchronized. Two threads can at the same time allocate a new row for evtchn_to_irq and add the irq mapping to the their newly allocated row. One thread will overwrite what the other has set for evtchn_to_irq[row] and therefore the irq mapping is lost. This will trigger a BUG_ON later in bind_evtchn_to_cpu: INFO: pci 0000:1a:15.4: [1d0f:8061] type 00 class 0x010802 INFO: nvme 0000:1a:12.1: enabling device (0000 -> 0002) INFO: nvme nvme77: 1/0/0 default/read/poll queues CRIT: kernel BUG at drivers/xen/events/events_base.c:427! WARN: invalid opcode: 0000 [#1] SMP NOPTI WARN: Workqueue: nvme-reset-wq nvme_reset_work [nvme] WARN: RIP: e030:bind_evtchn_to_cpu+0xc2/0xd0 WARN: Call Trace: WARN: set_affinity_irq+0x121/0x150 WARN: irq_do_set_affinity+0x37/0xe0 WARN: irq_setup_affinity+0xf6/0x170 WARN: irq_startup+0x64/0xe0 WARN: __setup_irq+0x69e/0x740 WARN: ? request_threaded_irq+0xad/0x160 WARN: request_threaded_irq+0xf5/0x160 WARN: ? nvme_timeout+0x2f0/0x2f0 [nvme] WARN: pci_request_irq+0xa9/0xf0 WARN: ? pci_alloc_irq_vectors_affinity+0xbb/0x130 WARN: queue_request_irq+0x4c/0x70 [nvme] WARN: nvme_reset_work+0x82d/0x1550 [nvme] WARN: ? check_preempt_wakeup+0x14f/0x230 WARN: ? check_preempt_curr+0x29/0x80 WARN: ? nvme_irq_check+0x30/0x30 [nvme] WARN: process_one_work+0x18e/0x3c0 WARN: worker_thread+0x30/0x3a0 WARN: ? process_one_work+0x3c0/0x3c0 WARN: kthread+0x113/0x130 WARN: ? kthread_park+0x90/0x90 WARN: ret_from_fork+0x3a/0x50 This patch sets evtchn_to_irq rows via a cmpxchg operation so that they will be set only once. The row is now cleared before writing it to evtchn_to_irq in order to not create a race once the row is visible for other threads. While at it, do not require the page to be zeroed, because it will be overwritten with -1's in clear_evtchn_to_irq_row anyway. Signed-off-by: Maximilian Heyne Fixes: d0b075ffeede ("xen/events: Refactor evtchn_to_irq array to be dynamically allocated") Link: https://lore.kernel.org/r/20210812130930.127134-1-mheyne@amazon.de Reviewed-by: Boris Ostrovsky Signed-off-by: Boris Ostrovsky Signed-off-by: Sasha Levin --- drivers/xen/events/events_base.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index a2f8130e18fe..d138027034fd 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -133,12 +133,12 @@ static void disable_dynirq(struct irq_data *data); static DEFINE_PER_CPU(unsigned int, irq_epoch); -static void clear_evtchn_to_irq_row(unsigned row) +static void clear_evtchn_to_irq_row(int *evtchn_row) { unsigned col; for (col = 0; col < EVTCHN_PER_ROW; col++) - WRITE_ONCE(evtchn_to_irq[row][col], -1); + WRITE_ONCE(evtchn_row[col], -1); } static void clear_evtchn_to_irq_all(void) @@ -148,7 +148,7 @@ static void clear_evtchn_to_irq_all(void) for (row = 0; row < EVTCHN_ROW(xen_evtchn_max_channels()); row++) { if (evtchn_to_irq[row] == NULL) continue; - clear_evtchn_to_irq_row(row); + clear_evtchn_to_irq_row(evtchn_to_irq[row]); } } @@ -156,6 +156,7 @@ static int set_evtchn_to_irq(unsigned evtchn, unsigned irq) { unsigned row; unsigned col; + int *evtchn_row; if (evtchn >= xen_evtchn_max_channels()) return -EINVAL; @@ -168,11 +169,18 @@ static int set_evtchn_to_irq(unsigned evtchn, unsigned irq) if (irq == -1) return 0; - evtchn_to_irq[row] = (int *)get_zeroed_page(GFP_KERNEL); - if (evtchn_to_irq[row] == NULL) + evtchn_row = (int *) __get_free_pages(GFP_KERNEL, 0); + if (evtchn_row == NULL) return -ENOMEM; - clear_evtchn_to_irq_row(row); + clear_evtchn_to_irq_row(evtchn_row); + + /* + * We've prepared an empty row for the mapping. If a different + * thread was faster inserting it, we can drop ours. + */ + if (cmpxchg(&evtchn_to_irq[row], NULL, evtchn_row) != NULL) + free_page((unsigned long) evtchn_row); } WRITE_ONCE(evtchn_to_irq[row][col], irq); -- 2.30.2