From nobody Mon Sep 28 05:45:30 2026 Received: from mta1.migadu.com (out-19.mta1.migadu.com [95.215.58.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 379B81DD0EF for ; Wed, 26 Aug 2026 00:26:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787703973; cv=none; b=kstBM2vsPwYsrB/t7/PGXa52i8y14yTxuxrOBgpZU7P7GHtBhbxD2zYugs6gHfb4N8IIbN2IhvO4sFYdMhDuew5bTqWoQ8Pu7CeicUtcaFXdCVquuDsdZarfIJu+mgeJpGdic9XW07iiwRRkeUTo8NcIX9mOeAFBfA/JC3gh2ZE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787703973; c=relaxed/simple; bh=NxDKxbFlED+fFDd4TCm7HQl8oeKXvA3b2POunZDitW4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=TPfvvesqqh12kJI0qGdqqTR87J28kNRQ5JAMVmpnbZbUPC+z7J5IL/SN5ZQovt80oOgJGyu4N/GibLULu/LSfVFVRURJf4pEiMvUMjjWtJrPO4oROMNhwFHOM5XuPFnKNGJiyq34NCryeASHV6/AbPpZ5lL45/xer+ciV97S5lE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cressey.dev; spf=pass smtp.mailfrom=cressey.dev; dkim=pass (2048-bit key) header.d=cressey.dev header.i=@cressey.dev header.b=Ok/NPpyr; arc=none smtp.client-ip=95.215.58.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cressey.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cressey.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cressey.dev header.i=@cressey.dev header.b="Ok/NPpyr" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=NxDKxbFlED+fFDd4TCm7HQl8oeKXvA3b2POunZDitW4=; c=simple/simple; d=cressey.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1787703968; v=1; x=1788308768; b=Ok/NPpyrHHlbR7PjBTv125E5c3em3ivPhaAMtladNLyc6z/L0I3YTdjZ+zYv13uITsW7c4Ao TnNB1/+mylPowudXrkpC/gxvEEqXoUyaFUmojE7Qf7/CdyDeao6qeEAfq7qa6C98UZFUMgCODd0 QuiCYm2nmUGN9WSf9XeHNW3nTvBGm/tF8vy5YwFiGl2Dzoo42LckDYBVa1Hc5gvoXfvZ4hZ2+sf 2vPmxwr2crAeFpi1a+u9LI/qYqwdYmAQ98kx3H7LVjWIFZ/VWwgdejM/YmV65A6gbhRvyJfv9DT tfByI9qFs2z/cTIpRRadU2Fhl2TvhZYzyBOPtHoHIxF9w== X-Envelope-To: linux-kernel@vger.kernel.org Received: from coder-bcressey-whiskers-0.coder-bcressey-whiskers.remote-dev.svc.cluster.local (35.83.186.167) by smtp.migadu.com with ESMTPS id d88eb38d4e98656b; Wed, 26 Aug 2026 00:26:07 +0000 X-Mizu-Trace-ID: d88eb38d4e98656b X-Migadu-Flow: FLOW_OUT From: Ben Cressey Date: Wed, 26 Aug 2026 00:25:33 +0000 Subject: [PATCH] dm-crypt: fix a tiny race condition in crypt_dec_pending Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260826-dm-crypt-dec-pending-v1-1-395bfee3576b@cressey.dev> X-B4-Tracking: v=1; b=H4sIAHwyjmoC/22NyQ6CMBCGX4XM2QnYyKKvYjyU6Qjj0jZT3EJ4d wGvHr9/HSGxCic4ZCMoPyVJ8DNsNxlQb33HKG5mMIWpisaU6O5I+okDOiaM7J34DndVzQ3ZfV2 VDHM1Kp/lvc4eTz9Oj/bCNCxbS6K1ibFV66lfpFvMKbyCXlnz1fp3A9P0BZHs6qOwAAAA X-Change-ID: 20260825-dm-crypt-dec-pending-467e8ca9765e To: Alasdair Kergon , Mike Snitzer , Mikulas Patocka , Benjamin Marzinski , Milan Broz Cc: dm-devel@lists.linux.dev, linux-kernel@vger.kernel.org, stable@vger.kernel.org, "Jose Fernandez (Anthropic)" , Ben Cressey X-Mailer: b4 0.15.2 crypt_dec_pending reads io->error before calling atomic_dec_and_test. Another context, for example crypt_endio called from an interrupt, may set io->error and drop its reference between the read and the decrement. crypt_dec_pending then drops the last reference and completes the bio with the stale status - so a read that failed and was never decrypted, or a write that failed, is reported as successful. The read was placed before the decrement by commit b35f8caa0890 ("dm crypt: wait for endio to complete before destruction"), because that commit freed dm_crypt_io before calling bio_endio. This is no longer the case, dm_crypt_io lives in the per-bio data now. Read io->error after atomic_dec_and_test instead. atomic_dec_and_test is fully ordered, so no additional barrier is needed. Fixes: b35f8caa0890 ("dm crypt: wait for endio to complete before destructi= on") Cc: stable@vger.kernel.org Reviewed-by: Jose Fernandez (Anthropic) Signed-off-by: Ben Cressey Assisted-by: Claude:unspecified --- Found by inspection. On x86-64 the load and the lock decl are adjacent instructions, so in practice this needs an interrupt or preemption on the CPU doing the final crypt_dec_pending. It could only be demonstrated with an mdelay() inserted between the two in kcryptd context: with dm-crypt on top of the "error" target, 20 of 20 failed direct writes were then reported as successful, and 0 of 20 with this patch and the same delay. The affected pairs include kcryptd_io_read_work vs the read clone's crypt_endio (deferred or recheck read), kcryptd_crypt_write_convert vs the write clone's crypt_endio, and with an async cipher the read and write convert paths vs kcryptd_async_done. --- drivers/md/dm-crypt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 608b617fb817f..9e170de50ad32 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1745,7 +1745,6 @@ static void crypt_dec_pending(struct dm_crypt_io *io) { struct crypt_config *cc =3D io->cc; struct bio *base_bio =3D io->base_bio; - blk_status_t error =3D io->error; =20 if (!atomic_dec_and_test(&io->io_pending)) return; @@ -1767,7 +1766,7 @@ static void crypt_dec_pending(struct dm_crypt_io *io) else kfree(io->integrity_metadata); =20 - base_bio->bi_status =3D error; + base_bio->bi_status =3D io->error; =20 bio_endio(base_bio); } --- base-commit: 39c5aa3bd8ec3912d2cd0b3fe092642b0d2b0713 change-id: 20260825-dm-crypt-dec-pending-467e8ca9765e