From nobody Tue Jun 16 20:38:48 2026 Received: from mail-qt1-f181.google.com (mail-qt1-f181.google.com [209.85.160.181]) (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 4F91D2DF153 for ; Wed, 29 Apr 2026 08:11:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777450290; cv=none; b=cA+7trTd0ixzyG/SFhknp8zqKU8fVO8+RxJgZKSDygBWUdfFIUVyLUBjlNHv8NS0o+EwLOzPm0AD17D2gbB/TSEGj5FnxeX2YCNopaJr42JgkZkL384O3reTEY3vHGa9KUtRzejsAUmb0SzfvaRdbvkSzOgWIoy9v9syXKxPZMg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777450290; c=relaxed/simple; bh=uNMsmh+NPA5fGVoZPoDZ55WYbmr94ejVtsDB04UU/IY=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=aAiByEQCeg5h4U9mZ9MWP7pPIdk7pWquOSYoCB6SoSOE6giCa9aMRNw42WcZOaRKyYa4CO3S92gRj2HEZ7Y30l4dYt2cvKW6Pt0GIyyX5P6Mu1LdCldYoNCGf8F9CqquKZacC/6jvA0MIJwE8L9JPxD+5Bq8wvJg2a4PqPr29uM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=reject dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=hvSRiMSI; arc=none smtp.client-ip=209.85.160.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=reject dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hvSRiMSI" Received: by mail-qt1-f181.google.com with SMTP id d75a77b69052e-50e5c7eb565so108612811cf.3 for ; Wed, 29 Apr 2026 01:11:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1777450287; x=1778055087; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:sender:from:to:cc:subject:date:message-id:reply-to; bh=4luoH6khuhqnxfmTEORpTdVfrcz2VCE+xEJQwn3VEp0=; b=hvSRiMSIMewrnOel53as+CmO2Zbf5uAn7G7z1f2djP8BDiKE95PLKiYvg2WEVyDgVY j+s/XepzddZE5HCiiVhXWqq7aE1MfsahZlwGE4xUb8r5uZz1LkX0QwRO1M7ABmVYw53y I/3XbjAsOC8Lvtk92aAV4U7A5NCcKYI+mxr5z9xMKOt3/D7+Tlbvr9M9vddu5S5+A3YE Hgtu3qeC9ISGQ0BcbYo6gNptq/P6TBHA/Unvv6VIsw30t0wDRU+xZNFK84q2Zx3SMiFG k//Iy2V2LcAvfPANzeOJdGIFntaTSwwRf0Pn4KsjdxTRBsGmQ2X2xb+riMs5e/D528g+ 0l0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777450287; x=1778055087; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:sender:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=4luoH6khuhqnxfmTEORpTdVfrcz2VCE+xEJQwn3VEp0=; b=AJCwxpKeIF0LMgwmc5BBFS+0PrYC320l6GyNX9xIzqaefNSeqEL+i7ASCd3wsb+Abu JWPxsB03yYig2cDtC/V5GfpC81gSp8z83CUaksa+EDvYH/ineKexn1KOY2Yk32OTK4QV 8vjML3LSPwfPhYn9jw7gD9WOSoOf61mjXQOIv5yV2ToDsDMG385nMWtI59e2Zr0C0VEu HurDiqevmgKN1Mv7uTIloIXTwfjH7aa9tj2znwgWU8JG0KnxY8lOe15YCkh03IX8hlbb ElkSiYUMG039ZdbET3+Vyj3+/lpFiQtNwQBNOXj6anyNw3LlRJ5KZbnW5Pnxb7buv3l1 6U9w== X-Forwarded-Encrypted: i=1; AFNElJ/0vTLabC0MDneL7zjrJnLkv/Vq4jBDsjGAgGmaoDDd2bnuJNrdKE8Qm7wi1ZtdFXOgrsOhFdPHIzWdrfs=@vger.kernel.org X-Gm-Message-State: AOJu0Yxl4IEdHRWDB32yJOflDinWz6L3vek2pDS7SRmlEOzbbJoxYeTs guxeNaGdV7mzbWvMFMA6ujPP6tPAJbwj2VvFa5Nw7sLGQW+Xs0byLu8v X-Gm-Gg: AeBDievVtPSF/Go5avCkmV2wmaaPUC5IsEhI1UQu0Gn5sWlSyToU+ZSnF9WAHfw3Gm+ hypCOpVbENNyCXlNLRIPvP70RTSEylzj+Dky+G2KCVRHlsSPv12NHBnZSv9/5lbUimvqtHMj27n /LiFkyitE1+1+SBQ/e4+Arj7U4HznlYrgjCDnnYliLXPH1qN2Zd4MdQEmR7gL6QIf6EPpJM2l9f umW+mxI+FgY21ltj5BIOQHdzfNv1Wr3ahD0Rs7l8QqN6PE1Sp/2lIqwoJQmREG4rBEPTdsHIKGZ QgLZtIsJSmNk+V7TtDAeKTQ7VkRro7qHAiFKJfBksOEj8kkqnSDcaKZfB4kUtHeJWI6Ueqamb7o C8i+JFvzC4cMX40phe1dbLroelIw5NFk0piewkq6gl3j7JWLmF+zvi+feMZ863sIZYT+a9XAaxC Osn5+WRNzuMZeDFvya X-Received: by 2002:ac8:5d90:0:b0:50d:7384:a660 with SMTP id d75a77b69052e-5100e0f4cb1mr83974981cf.6.1777450287085; Wed, 29 Apr 2026 01:11:27 -0700 (PDT) Received: from localhost ([2001:67c:1562:8007::aac:4468]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-5101ac9ffefsm11973191cf.6.2026.04.29.01.11.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Apr 2026 01:11:25 -0700 (PDT) Sender: AceLan Kao From: "Chia-Lin Kao (AceLan)" To: Keith Busch , Jens Axboe , Christoph Hellwig , Sagi Grimberg Cc: linux-nvme@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH] nvme-pci: fix use-after-free in nvme_free_host_mem() Date: Wed, 29 Apr 2026 16:11:16 +0800 Message-ID: <20260429081116.237733-1-acelan.kao@canonical.com> X-Mailer: git-send-email 2.53.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" nvme_free_host_mem() frees dev->hmb_sgt via dma_free_noncontiguous() but never clears the pointer afterward. This leads to a use-after-free if nvme_free_host_mem() is called twice in the same error path. This can happen during nvme_probe() when nvme_setup_host_mem() succeeds in allocating the HMB (setting dev->hmb_sgt) but nvme_set_host_mem() fails with an I/O error: nvme_setup_host_mem() nvme_alloc_host_mem_single() -> sets dev->hmb_sgt nvme_set_host_mem() -> fails with -EIO nvme_free_host_mem() -> frees hmb_sgt, but does NOT NULL it return error nvme_probe() error path: nvme_free_host_mem() -> dev->hmb_sgt is stale, use-after-free The second call dereferences the freed sgt, causing a NULL pointer dereference in iommu_dma_free_noncontiguous() when it accesses sgt->sgl->dma_address (the backing memory has been freed and zeroed). This is reproducible on Thunderbolt-attached NVMe devices (e.g., OWC Envoy Express behind a Dell WD22TB4 dock) where the device intermittently returns I/O errors during HMB setup due to PCIe link instability. BUG: kernel NULL pointer dereference, address: 0000000000000010 RIP: 0010:iommu_dma_free_noncontiguous+0x22/0x80 Call Trace: dma_free_noncontiguous+0x3b/0x130 nvme_free_host_mem+0x30/0xf0 [nvme] nvme_probe.cold+0xcc/0x275 [nvme] local_pci_probe+0x43/0xa0 pci_device_probe+0xeea/0x290 really_probe+0xf9/0x3b0 __driver_probe_device+0x8b/0x170 driver_probe_device+0x24/0xd0 __driver_attach_async_helper+0x6b/0x110 async_run_entry_fn+0x37/0x170 process_one_work+0x1ac/0x3d0 worker_thread+0x1b8/0x360 kthread+0xf7/0x130 ret_from_fork+0x2d8/0x3a0 ret_from_fork_asm+0x1a/0x30 Fix this by setting dev->hmb_sgt to NULL after freeing it, so the second call takes the multi-descriptor path which safely handles the already-cleaned-up state. Fixes: 63a5c7a4b4c4 ("nvme-pci: use dma_alloc_noncontigous if possible") Signed-off-by: Chia-Lin Kao (AceLan) --- drivers/nvme/host/pci.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 9fd04cd7c5cb1..94c423bed947b 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2533,11 +2533,13 @@ static void nvme_free_host_mem_multi(struct nvme_de= v *dev) =20 static void nvme_free_host_mem(struct nvme_dev *dev) { - if (dev->hmb_sgt) + if (dev->hmb_sgt) { dma_free_noncontiguous(dev->dev, dev->host_mem_size, dev->hmb_sgt, DMA_BIDIRECTIONAL); - else + dev->hmb_sgt =3D NULL; + } else { nvme_free_host_mem_multi(dev); + } =20 dma_free_coherent(dev->dev, dev->host_mem_descs_size, dev->host_mem_descs, dev->host_mem_descs_dma); --=20 2.53.0