Received: by 2002:a25:7ec1:0:0:0:0:0 with SMTP id z184csp6018873ybc; Wed, 27 Nov 2019 13:30:41 -0800 (PST) X-Google-Smtp-Source: APXvYqyUwTNb23azrNRtH3A3c1q/IOlUUHWxKlr22zYy4LpAzCUYMlHMkg/ts4XgF6xw5qZXmO4j X-Received: by 2002:aa7:d45a:: with SMTP id q26mr11726518edr.158.1574890241223; Wed, 27 Nov 2019 13:30:41 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1574890241; cv=none; d=google.com; s=arc-20160816; b=PbBco41SuJ/OCIHiaZxhWYdPoDrY4bpxGYUKSUWJjRS3+j5kdNlnKTJ1S9bAVuoJWf PRlLoW12hKTumTLmSGjf+u/hUSt8w9ZOXRWk6ykaeLScH+j8VBhXjaEI1Qp2waJ0eDhV H/dYOlXalvK54vibj/cPYl9AbhmAx07ILkQyd6mLxTF8B0r57y5p/ZlH0D19GtyIw4H/ TpBMRjbfLtqgdc+6A5uJ+fn03Uy4aSrQQqvKMFsd9TDHas+E4JR2OE7fZd5Cy62NMZ+B ooqiI9EzBw37iADtn9g7a5K8q1tlhL+6iCSOc7pkZxzLvoSQZQb5DsoI108jDV9kIQDU D46Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=jxqY/i9zrqDHPhxAKRbA3T4EjExS43P1KNIqSUIrUHQ=; b=n6dshpwvwz1UnnMcplDunP1OZdPy9Un2ld52iaYpQz7iIdFrMM+8AosvEWsky7QHMZ ruJo0FAvBeQJ0VRJdYqtPvrdYdQI9a56DZdXmNexYvPVXiPLJPYfv6kZdNr7isE5oDgM sP2uN5/MMjLpK3I+mPaRyMih0Ap12J6taa3mWtyWkmM7HOpEkX3oo2fdTFmphHwiA1Dl Dgc8jU68XiE4qzN3RHpVRF7L30v7fHwb1HBhhUR1/66hLIV0bU4yZ8GY2JSuqQ/8b7gt 1peqSaSFzNwmQaCLpyyQzvjukY0EZibHjSp23zSUNFW/jzOQ9qKaaIqP8CYkRmJBb0ZD udPg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=YlBxlUQY; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id dm19si3152038edb.214.2019.11.27.13.30.17; Wed, 27 Nov 2019 13:30:41 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=YlBxlUQY; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731094AbfK0U6q (ORCPT + 99 others); Wed, 27 Nov 2019 15:58:46 -0500 Received: from mail.kernel.org ([198.145.29.99]:50046 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730443AbfK0U6m (ORCPT ); Wed, 27 Nov 2019 15:58:42 -0500 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 20D592084D; Wed, 27 Nov 2019 20:58:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1574888321; bh=1AEe6262HdcOwAQh2tB2daek/J3BYWc1JBiEqovCau0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YlBxlUQYFoeOVhgIIQRBJja2Uo5MOT0PgU7xKMzyrl/cepdh9YMFxe434Ho5whCEM WBMPRyH00WmtkYtf3FQH0wMbMqCTsfb/MllRsIE1fCr0VSdbOFKjHxRXjsv4DZzJpJ sLeP6t0cZHt/wL1Yedaj+l8UnVOUmTfSZUWVTzl8= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Dave Chinner , Brian Foster , Dave Chinner , Sasha Levin Subject: [PATCH 4.19 088/306] xfs: fix use-after-free race in xfs_buf_rele Date: Wed, 27 Nov 2019 21:28:58 +0100 Message-Id: <20191127203121.350680123@linuxfoundation.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191127203114.766709977@linuxfoundation.org> References: <20191127203114.766709977@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Dave Chinner [ Upstream commit 37fd1678245f7a5898c1b05128bc481fb403c290 ] When looking at a 4.18 based KASAN use after free report, I noticed that racing xfs_buf_rele() may race on dropping the last reference to the buffer and taking the buffer lock. This was the symptom displayed by the KASAN report, but the actual issue that was reported had already been fixed in 4.19-rc1 by commit e339dd8d8b04 ("xfs: use sync buffer I/O for sync delwri queue submission"). Despite this, I think there is still an issue with xfs_buf_rele() in this code: release = atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock); spin_lock(&bp->b_lock); if (!release) { ..... If two threads race on the b_lock after both dropping a reference and one getting dropping the last reference so release = true, we end up with: CPU 0 CPU 1 atomic_dec_and_lock() atomic_dec_and_lock() spin_lock(&bp->b_lock) spin_lock(&bp->b_lock) b_lru_ref = 0> freebuf = true spin_unlock(&bp->b_lock) xfs_buf_free(bp) spin_unlock(&bp->b_lock) IOWs, we can't safely take bp->b_lock after dropping the hold reference because the buffer may go away at any time after we drop that reference. However, this can be fixed simply by taking the bp->b_lock before we drop the reference. It is safe to nest the pag_buf_lock inside bp->b_lock as the pag_buf_lock is only used to serialise against lookup in xfs_buf_find() and no other locks are held over or under the pag_buf_lock there. Make this clear by documenting the buffer lock orders at the top of the file. Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Reviewed-by: Carlos Maiolino Signed-off-by: Sasha Levin --- fs/xfs/xfs_buf.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index e839907e8492f..f4a89c94c931b 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -37,6 +37,32 @@ static kmem_zone_t *xfs_buf_zone; #define xb_to_gfp(flags) \ ((((flags) & XBF_READ_AHEAD) ? __GFP_NORETRY : GFP_NOFS) | __GFP_NOWARN) +/* + * Locking orders + * + * xfs_buf_ioacct_inc: + * xfs_buf_ioacct_dec: + * b_sema (caller holds) + * b_lock + * + * xfs_buf_stale: + * b_sema (caller holds) + * b_lock + * lru_lock + * + * xfs_buf_rele: + * b_lock + * pag_buf_lock + * lru_lock + * + * xfs_buftarg_wait_rele + * lru_lock + * b_lock (trylock due to inversion) + * + * xfs_buftarg_isolate + * lru_lock + * b_lock (trylock due to inversion) + */ static inline int xfs_buf_is_vmapped( @@ -1006,8 +1032,18 @@ xfs_buf_rele( ASSERT(atomic_read(&bp->b_hold) > 0); - release = atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock); + /* + * We grab the b_lock here first to serialise racing xfs_buf_rele() + * calls. The pag_buf_lock being taken on the last reference only + * serialises against racing lookups in xfs_buf_find(). IOWs, the second + * to last reference we drop here is not serialised against the last + * reference until we take bp->b_lock. Hence if we don't grab b_lock + * first, the last "release" reference can win the race to the lock and + * free the buffer before the second-to-last reference is processed, + * leading to a use-after-free scenario. + */ spin_lock(&bp->b_lock); + release = atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock); if (!release) { /* * Drop the in-flight state if the buffer is already on the LRU -- 2.20.1