From nobody Fri Sep 25 09:20:24 2026 Received: from mail-pf1-f198.google.com (mail-pf1-f198.google.com [209.85.210.198]) (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 5D372457E6D for ; Mon, 14 Sep 2026 14:49:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.198 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789397357; cv=none; b=ZRTBRWsvlo/DVP8F5i5pjbfuprlvCiC0Rr3ZUskZVuCqQ0mNs92BYalDDLuaqFLFT5nBTB8xX+DBgjw7ym8L5/AZUCORWas0fn1OqFmwzu2EO3aTSOv/CME5Fe6Eehce1iojBofF17o2FL04YD3mt3zqU6lWWExAg7kW2X3SUcY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789397357; c=relaxed/simple; bh=06CvAkHxZWNyIyQS4urvFuXxGr2JJSfmD6apJNlQn3Y=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=WAIcenU7hrVfQtrdpHMacYbr9T5KxQTuLtbbrG2E4mjCYgDl88S+OT2YR9UFQeKXAI1cSvNZ+7sYns9wcbgFNoOTAlR7OLU3TC3N6+YdggEWdk1i63k+K8gkGziC93dnn4o8d5uSXiI995WD6XfJCK9mNVmekXj0UN9cpJsaPZE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--stanleyjhu.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=azdXlTat; arc=none smtp.client-ip=209.85.210.198 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--stanleyjhu.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="azdXlTat" Received: by mail-pf1-f198.google.com with SMTP id d2e1a72fcca58-854f274dd69so3994844b3a.1 for ; Mon, 14 Sep 2026 07:49:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1789397355; x=1790002155; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=0DJi8X0xX37W1aEPPUVBbau+Duvv8iBwoY8wMaEV1PQ=; b=azdXlTatL4TCwfQaKrJHlsynmECxTn+54qxW1zR3ZzocFT9cqrGhdfGxQE4XLUm4Ge aH2q8+fe7tDAr6gWjuAuUxPZhZU+/Lwkz3v7RU69U1Vd9CJ7XAScthEeuJ67CpQ8aCRY flB2YhOuabHyEqemGemQ9UxCdGn9GevI/bARfQWJ7vTpiyYOcTdqJBy9nsFdKLiNDwq1 q92Tm4d4ScYAgIIWmF0KUvqKk3/3wTORb1zjVkpKZmymg2+LZW0CaKywHDQu39wOyfzU Fnl7kPrj/bd5Vzdbf0FD8Tx4/w/dUTMv1vYYJWcjrUGzuni4qHBCmrxkdPCKoyI5dF4i onUA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1789397355; x=1790002155; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=0DJi8X0xX37W1aEPPUVBbau+Duvv8iBwoY8wMaEV1PQ=; b=NFfSKN6BCOgLL998xFaQSeP8t1WIr/JPEPZBfhtBBd1pJZukWj33snJjNTgU0RpRCt GF8WdRcMTTPB9clTohk7f4vq4z/X3LXBa64OlkzeyEdPdQr0WyaKdSrurPetadIFgm4p cOXLdTlW5ndEORuMWN+6+bqzWMpy+tq8C5+Gzu0XXnSMDfRAN7PTevC6J7SLaFjhGnhI E6s9gRRLnjmfcIxzFJAlU18B8WDF7CVfDk/fR5Y58hkD5vtuWiEnv+EEnTJPXcEdNaTq VElbeqqaprlfmU6kj5WisskRTNxIrhOqGnWrkJ1jj+Uj16XsNboXV/0E33KRVuUxLgGd h7mg== X-Forwarded-Encrypted: i=1; AKwUvByDRZn6/u5Z/wueyjacghQy86PZ61QQQOh77jZCMYwkA1HvcLWBuvYE3DXVtub0eZ5PIQy01v/wYMouCP8=@vger.kernel.org X-Gm-Message-State: AFuF++lGqOcDMTw/oyUUF3pqyWkvSWLFXtVWzOv/WmccYb/LWFaoCp8a VDk63XIPdrykpYRv14eVn32r2i0sCYXOp7KCNnm2gieRC1JOdZCtM/GHGsMzlBGTSqehkttEj2j 32Te13PUum/vMUTqHa3pj9A== X-Received: from pfbdn1.prod.google.com ([2002:a05:6a00:4981:b0:86b:e98b:a8ab]) (user=stanleyjhu job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:1709:b0:86a:9be:6bf3 with SMTP id d2e1a72fcca58-86f863bede0mr5353125b3a.23.1789397354317; Mon, 14 Sep 2026 07:49:14 -0700 (PDT) Date: Mon, 14 Sep 2026 22:49:08 +0800 In-Reply-To: <20260914144910.931518-1-stanleyjhu@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260914144910.931518-1-stanleyjhu@google.com> X-Mailer: git-send-email 2.55.0.1007.g17ff1f9808-goog Message-ID: <20260914144910.931518-2-stanleyjhu@google.com> Subject: [PATCH v5 1/3] rpmb: core: Guard frame requests and teardown with mutex From: Stanley Jhu To: jenswi@kernel.org, mkp@kernel.org Cc: gregkh@linuxfoundation.org, arnd@arndb.de, bvanassche@acm.org, avri.altman@sandisk.com, alim.akhtar@samsung.com, beanhuo@micron.com, can.guo@oss.qualcomm.com, ulfh@kernel.org, linusw@kernel.org, shyamsaini@linux.microsoft.com, alex.bennee@linaro.org, James.Bottomley@hansenpartnership.com, linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org, Stanley Jhu , stable@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" rpmb_route_frames() has no serialisation. That has two independent consequences. Concurrent requests on one rpmb_dev corrupt each other. Two kthreads issuing RPMB_GET_WRITE_COUNTER against the same UFS RPMB region, 20000 iterations each: race complete: MISMATCH=3D17030 ERRORS=3D0 A mismatch is a response whose echoed nonce belongs to the other thread: 43% of requests returned somebody else's frame, with no transport error. An authenticated RPMB operation is not a single command. Per JESD220F 12.4.2 a region processes one at a time. Per 12.4.7 any request other than a result read overwrites the region's result register. The rpmb_dev is the granularity the device itself assumes. A request can also be in flight when the provider tears down. rpmb_dev_unregister() calls device_del(), which drops the reference device_add() took on the parent. The parent can then be freed while the rpmb_dev is still alive and routable through rdev->dev.parent. Unbinding a UFS host under a consumer that keeps issuing requests: BUG: KASAN: slab-use-after-free in ufs_rpmb_route_frames+0x328/0x420 Read of size 8 at addr fff00000c833bce8 by task rpmb_hold/100 Call trace: ufs_rpmb_route_frames+0x328/0x420 rpmb_route_frames+0x64/0xd0 Freed by task 1: kfree+0x2b8/0x5c4 ufs_rpmb_device_release+0x3c/0x60 device_release+0xa0/0x1fc device_unregister+0x20/0x38 ufs_rpmb_remove+0x130/0x230 ufshcd_remove+0x54/0x22c The stable tag is for eMMC. mmc_route_rpmb_frames() packs the sequence into one block request, so eMMC cannot interleave. The teardown window is still open there. mmc_blk_remove() reaches rpmb_dev_unregister() well before tearing down the queue that request goes to. That window is from source reading, not reproduced. Add a mutex and a dead flag to struct rpmb_dev. One lock held across the whole request both serialises requests and excludes unregistration. The kerneldoc is wrong as well: until rpmb_dev_unregister() runs, the child holds a reference that keeps the parent's release callback from running, so a provider cannot unregister from there. Both tests then report MISMATCH=3D0 and a clean unbind. Fixes: 1e9046e3a154 ("rpmb: add Replay Protected Memory Block (RPMB) subsys= tem") Cc: stable@vger.kernel.org Signed-off-by: Stanley Jhu Reviewed-by: Bean Huo --- Notes: Both measurements need all three patches applied: on current kernels no rpmb_dev registers on UFS, so this patch alone changes nothing there. drivers/misc/rpmb-core.c | 34 +++++++++++++++++++++++++++++----- include/linux/rpmb.h | 5 +++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/misc/rpmb-core.c b/drivers/misc/rpmb-core.c index ecf14acf230a..bbc3c404ad6f 100644 --- a/drivers/misc/rpmb-core.c +++ b/drivers/misc/rpmb-core.c @@ -45,16 +45,28 @@ EXPORT_SYMBOL_GPL(rpmb_dev_put); * @rsp: rpmb response frames * @rsp_len: length of rpmb response frames in bytes * + * Context: Might sleep. + * * Returns: < 0 on failure */ int rpmb_route_frames(struct rpmb_dev *rdev, u8 *req, unsigned int req_len, u8 *rsp, unsigned int rsp_len) { - if (!req || !req_len || !rsp || !rsp_len) + int ret; + + if (!rdev || !req || !req_len || !rsp || !rsp_len) return -EINVAL; =20 - return rdev->descr.route_frames(rdev->dev.parent, req, req_len, - rsp, rsp_len); + mutex_lock(&rdev->lock); + if (rdev->dead) { + mutex_unlock(&rdev->lock); + return -ENODEV; + } + + ret =3D rdev->descr.route_frames(rdev->dev.parent, req, req_len, + rsp, rsp_len); + mutex_unlock(&rdev->lock); + return ret; } EXPORT_SYMBOL_GPL(rpmb_route_frames); =20 @@ -62,6 +74,7 @@ static void rpmb_dev_release(struct device *dev) { struct rpmb_dev *rdev =3D to_rpmb_dev(dev); =20 + mutex_destroy(&rdev->lock); ida_free(&rpmb_ida, rdev->id); kfree(rdev->descr.dev_id); kfree(rdev); @@ -123,8 +136,9 @@ EXPORT_SYMBOL_GPL(rpmb_interface_unregister); * rpmb_dev_unregister() - unregister RPMB partition from the RPMB subsyst= em * @rdev: the rpmb device to unregister * - * This function should be called from the release function of the - * underlying device used when the RPMB device was registered. + * This function should be called from the remove or unbind callback of the + * underlying device used when the RPMB device was registered, never from + * a device release callback. * * Returns: < 0 on failure */ @@ -133,6 +147,14 @@ int rpmb_dev_unregister(struct rpmb_dev *rdev) if (!rdev) return -EINVAL; =20 + mutex_lock(&rdev->lock); + if (rdev->dead) { + mutex_unlock(&rdev->lock); + return 0; + } + rdev->dead =3D true; + mutex_unlock(&rdev->lock); + device_del(&rdev->dev); =20 rpmb_dev_put(rdev); @@ -164,6 +186,7 @@ struct rpmb_dev *rpmb_dev_register(struct device *dev, rdev =3D kzalloc_obj(*rdev); if (!rdev) return ERR_PTR(-ENOMEM); + mutex_init(&rdev->lock); rdev->descr =3D *descr; rdev->descr.dev_id =3D kmemdup(descr->dev_id, descr->dev_id_len, GFP_KERNEL); @@ -194,6 +217,7 @@ struct rpmb_dev *rpmb_dev_register(struct device *dev, err_free_dev_id: kfree(rdev->descr.dev_id); err_free_rdev: + mutex_destroy(&rdev->lock); kfree(rdev); return ERR_PTR(ret); } diff --git a/include/linux/rpmb.h b/include/linux/rpmb.h index ed3f8e431eff..65807f597735 100644 --- a/include/linux/rpmb.h +++ b/include/linux/rpmb.h @@ -7,6 +7,7 @@ #define __RPMB_H__ =20 #include +#include #include =20 /** @@ -48,15 +49,19 @@ struct rpmb_descr { * struct rpmb_dev - device which can support RPMB partition * * @dev : device + * @lock : serialises requests and protects them against teard= own * @id : device_id * @list_node : linked list node * @descr : RPMB description + * @dead : set to true when device is unregistered */ struct rpmb_dev { struct device dev; + struct mutex lock; /* Serialises route_frames(), guards @dead */ int id; struct list_head list_node; struct rpmb_descr descr; + bool dead; }; =20 #define to_rpmb_dev(x) container_of((x), struct rpmb_dev, dev) --=20 2.55.0.1007.g17ff1f9808-goog From nobody Fri Sep 25 09:20:24 2026 Received: from mail-pj1-f69.google.com (mail-pj1-f69.google.com [209.85.216.69]) (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 B4C2E481236 for ; Mon, 14 Sep 2026 14:49:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.69 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789397360; cv=none; b=oGBYBMiKRYj8V8EjGbNyi0GzzJhW8mCDmCf14oeFkj7zOSCg7jVTQS/JZjSgicGirGW2yI+zlC2ekfr5IXhdwVbU169WnQ7cbZmlHWn4LgPiYOVHoUaAIy8MpsY85eI7WiMT+uRPvt9DQC/tY96Xxp90GfJR/1NyM/M5YwDyOfo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789397360; c=relaxed/simple; bh=obl2cCjLYsRHvlddO35s9bo6IUhBqtQRCY0KgoD6MBQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=JnHe7bvanB4OXAa8Ybkom6aayL205uT5Cw2Se4NtPJLnioeV/1PrbahT9Gl+wdBtUQHcRlAPIFmW1O6SpxJzzm5K2fw8V9uY7o91LfhxVrqzL8QC6ZBTHgTpEpgukACBsP3mFDPlt/52wkIcMheBT8s9ikbHrqefL1Z2RAR/n58= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--stanleyjhu.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=HEoIP9Zu; arc=none smtp.client-ip=209.85.216.69 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--stanleyjhu.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="HEoIP9Zu" Received: by mail-pj1-f69.google.com with SMTP id 98e67ed59e1d1-38f283baf1fso3929414a91.3 for ; Mon, 14 Sep 2026 07:49:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1789397357; x=1790002157; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=IOO+RpAv5XBBhPyjNlwP8G1zq2cxe8MeaMUh9XKE/dI=; b=HEoIP9Zu8HBt2EJ8sfd1bgbUroI53OVg/AIJXElIVjYSvyXDcsFETULsfSKBrG8+UH TEo/5drw/e/eDjs/9NMoJMQBiJ3Wt96FkC/fDtHQ4gB0ldivKfffC+DlP8dZ/MdL7uN/ ySED9PJyFbn0rPfE1jsDKRCjpIGKvBDBP4DtmMwgqBFycFQBaqTqrOPIWUSWq0kX4VpV lQkbRkeywPB3IhI4kMPpG4hFFuKiXrFDQ01FQPDMoxhdCM5tmfvJKvVFOCxzt+yS4Rg2 Wz3UbM88HI0lGZKEPAAymo+JrRnML93Cxi2bghaKpApjXhkJhaZhvq0yZi/11fgqf5dQ 70Yg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1789397357; x=1790002157; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=IOO+RpAv5XBBhPyjNlwP8G1zq2cxe8MeaMUh9XKE/dI=; b=AnKpQsRc1Utc+Z8nhzO4tNKrqZcgV5K18E0B04c4y5E9T5qGY3ty0cCP6OSLXktbNZ LNamUAJBCkO4nw+XPQSWK90MhhZzgCk9FuqjN2YD52uP7kPbhscNoX7NXNjvJExsI+79 Djf6wpJ0y/m98m13IyXt/H9Mq5oMqhXZQeHV2r6XdZ54y5dmGqRNMMabqZuTKs2vA/qE jrs+F1u6FH3xqBC3O2RZ8xT2oSkCGKVTDnb5xvSAX83HLmdZtwDuOYp1ZVhIruBHHhr5 ccOgGC6CeyrUxX/mZuI6IlTcaTyu6X50sUgpZdP5YlV89rnzAYaOPhEd1ECejfJ/9pWU swkg== X-Forwarded-Encrypted: i=1; AKwUvBwdOIwvN7JlZVWvjgOg7tVzU0B3QVVb9bLPvus3PqvUUUldWb1ysqB/Z+G3V5/fxx+ICwFV+cB6bSK2Cf4=@vger.kernel.org X-Gm-Message-State: AFuF++lEHXSZXL1AaS7BBuEnx4AjRt0j59b0WIfxFpN9r0rGycEV2ha3 9uWF0U/BCBkBqkY/uKcbGnbUMYc8REHXdO8+/2UMnenLeoboIFjq12WFBKHH/h256Bg1eMswza6 SHTzAF+CHW5Cj6mtqdQYeHQ== X-Received: from plrb7.prod.google.com ([2002:a17:902:a9c7:b0:2db:45f7:9948]) (user=stanleyjhu job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:4b83:b0:39d:f351:8f06 with SMTP id 98e67ed59e1d1-39df351afe2mr3188001a91.14.1789397356254; Mon, 14 Sep 2026 07:49:16 -0700 (PDT) Date: Mon, 14 Sep 2026 22:49:09 +0800 In-Reply-To: <20260914144910.931518-1-stanleyjhu@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260914144910.931518-1-stanleyjhu@google.com> X-Mailer: git-send-email 2.55.0.1007.g17ff1f9808-goog Message-ID: <20260914144910.931518-3-stanleyjhu@google.com> Subject: [PATCH v5 2/3] scsi: ufs: rpmb: Decouple device lifecycle from devres to avoid UAF From: Stanley Jhu To: jenswi@kernel.org, mkp@kernel.org Cc: gregkh@linuxfoundation.org, arnd@arndb.de, bvanassche@acm.org, avri.altman@sandisk.com, alim.akhtar@samsung.com, beanhuo@micron.com, can.guo@oss.qualcomm.com, ulfh@kernel.org, linusw@kernel.org, shyamsaini@linux.microsoft.com, alex.bennee@linaro.org, James.Bottomley@hansenpartnership.com, linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org, Stanley Jhu , stable@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" struct ufs_rpmb_dev embeds a struct device but is allocated with devm_kzalloc() against the host. That makes devres free it when the host detaches, regardless of the device reference count. Probe takes no reference on the RPMB well known LU either, so an in-flight request runs on a freed scsi_device: BUG: KASAN: slab-use-after-free in scsi_execute_cmd+0x998/0xab0 Read of size 8 at addr fff00000c82d4008 by task rpmb_hold/100 Call trace: scsi_execute_cmd+0x998/0xab0 ufs_sec_submit.isra.0+0x110/0x150 ufs_rpmb_route_frames+0x148/0x460 rpmb_route_frames+0x64/0xd0 Freed by task 1: kfree+0x2b8/0x5c4 scsi_device_dev_release+0x6b8/0xb7c __scsi_remove_device+0x1c8/0x318 scsi_remove_host+0xc0/0x258 ufshcd_remove+0x1c0/0x22c The release callback cannot clean this up, because it never runs. rpmb_dev_register() makes the rpmb_dev a child of ufs_rpmb->dev, so the child holds a reference on the parent until rpmb_dev_unregister() runs. The only caller of rpmb_dev_unregister() is the parent's own release callback, ufs_rpmb_device_release(). With commit 36f35b8df697 ("driver core: reject devices with unregistered buses") reverted so that registration succeeds, all four rpmb_devs are still in /sys/class/rpmb after the host is unbound and /sys/class/scsi_device is empty. Tie the memory to the reference count instead: - allocate with kzalloc_obj(), free in ufs_rpmb_device_release() - pin the WLUN with scsi_device_get(), drop it in the same callback - call rpmb_dev_unregister() from ufs_rpmb_remove() and the probe unwind, before device_unregister(), so the cycle is broken - reject requests once the WLUN is offline Since that commit nothing registers on UFS. On current kernels this patch has no observable effect on its own; the trace above was taken with registration restored. Fixes: b06b8c421485 ("scsi: ufs: core: Add OP-TEE based RPMB driver for UFS= devices") Cc: stable@vger.kernel.org Signed-off-by: Stanley Jhu Reviewed-by: Bean Huo --- drivers/ufs/core/ufs-rpmb.c | 80 +++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/drivers/ufs/core/ufs-rpmb.c b/drivers/ufs/core/ufs-rpmb.c index 783ecfc7581d..a3e43902bf08 100644 --- a/drivers/ufs/core/ufs-rpmb.c +++ b/drivers/ufs/core/ufs-rpmb.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -36,13 +37,14 @@ struct ufs_rpmb_dev { u8 region_id; struct device dev; struct rpmb_dev *rdev; - struct ufs_hba *hba; + struct scsi_device *sdev; struct list_head node; }; =20 -static int ufs_sec_submit(struct ufs_hba *hba, u16 spsp, void *buffer, siz= e_t len, bool send) +static int ufs_sec_submit(struct ufs_rpmb_dev *ufs_rpmb, u16 spsp, + void *buffer, size_t len, bool send) { - struct scsi_device *sdev =3D hba->ufs_rpmb_wlun; + struct scsi_device *sdev =3D ufs_rpmb->sdev; struct scsi_failure failure_defs[] =3D { { .sense =3D UNIT_ATTENTION, @@ -61,6 +63,9 @@ static int ufs_sec_submit(struct ufs_hba *hba, u16 spsp, = void *buffer, size_t le }; u8 cdb[12] =3D { }; =20 + if (!sdev || !scsi_device_online(sdev)) + return -ENODEV; + cdb[0] =3D send ? SECURITY_PROTOCOL_OUT : SECURITY_PROTOCOL_IN; cdb[1] =3D UFS_RPMB_SEC_PROTOCOL; put_unaligned_be16(spsp, &cdb[2]); @@ -73,13 +78,12 @@ static int ufs_sec_submit(struct ufs_hba *hba, u16 spsp= , void *buffer, size_t le =20 /* UFS RPMB route frames implementation */ static int ufs_rpmb_route_frames(struct device *dev, u8 *req, unsigned int= req_len, u8 *resp, - unsigned int resp_len) + unsigned int resp_len) { struct ufs_rpmb_dev *ufs_rpmb =3D dev_get_drvdata(dev); struct rpmb_frame *frm_out =3D (struct rpmb_frame *)req; bool need_result_read =3D true; u16 req_type, protocol_id; - struct ufs_hba *hba; int ret; =20 if (!ufs_rpmb) { @@ -87,8 +91,6 @@ static int ufs_rpmb_route_frames(struct device *dev, u8 *= req, unsigned int req_l return -ENODEV; } =20 - hba =3D ufs_rpmb->hba; - /* req_resp is at the end of an RPMB frame. */ if (req_len < sizeof(*frm_out)) return -EINVAL; @@ -121,7 +123,7 @@ static int ufs_rpmb_route_frames(struct device *dev, u8= *req, unsigned int req_l =20 protocol_id =3D ufs_rpmb->region_id << 8 | UFS_RPMB_SEC_PROTOCOL_ID; =20 - ret =3D ufs_sec_submit(hba, protocol_id, req, req_len, true); + ret =3D ufs_sec_submit(ufs_rpmb, protocol_id, req, req_len, true); if (ret) { dev_err(dev, "Command failed with ret=3D%d\n", ret); return ret; @@ -132,7 +134,7 @@ static int ufs_rpmb_route_frames(struct device *dev, u8= *req, unsigned int req_l =20 memset(frm_resp, 0, sizeof(*frm_resp)); put_unaligned_be16(RPMB_RESULT_READ, &frm_resp->req_resp); - ret =3D ufs_sec_submit(hba, protocol_id, resp, resp_len, true); + ret =3D ufs_sec_submit(ufs_rpmb, protocol_id, resp, resp_len, true); if (ret) { dev_err(dev, "Result read request failed with ret=3D%d\n", ret); return ret; @@ -140,7 +142,7 @@ static int ufs_rpmb_route_frames(struct device *dev, u8= *req, unsigned int req_l } =20 if (!ret) { - ret =3D ufs_sec_submit(hba, protocol_id, resp, resp_len, false); + ret =3D ufs_sec_submit(ufs_rpmb, protocol_id, resp, resp_len, false); if (ret) dev_err(dev, "Response read failed with ret=3D%d\n", ret); } @@ -150,23 +152,30 @@ static int ufs_rpmb_route_frames(struct device *dev, = u8 *req, unsigned int req_l =20 static void ufs_rpmb_device_release(struct device *dev) { - struct ufs_rpmb_dev *ufs_rpmb =3D dev_get_drvdata(dev); + struct ufs_rpmb_dev *ufs_rpmb =3D container_of(dev, struct ufs_rpmb_dev, = dev); =20 - rpmb_dev_unregister(ufs_rpmb->rdev); + scsi_device_put(ufs_rpmb->sdev); + kfree(ufs_rpmb); } =20 /* UFS RPMB device registration */ int ufs_rpmb_probe(struct ufs_hba *hba) { + struct rpmb_descr descr =3D { + .type =3D RPMB_TYPE_UFS, + .route_frames =3D ufs_rpmb_route_frames, + .reliable_wr_count =3D hba->dev_info.rpmb_io_size, + }; + struct scsi_device *sdev =3D hba->ufs_rpmb_wlun; struct ufs_rpmb_dev *ufs_rpmb, *it, *tmp; u8 dev_id[UFS_RPMB_ID_LEN]; struct rpmb_dev *rdev; - char *cid =3D NULL; + char *cid; int region; u32 cap; int ret; =20 - if (!hba->ufs_rpmb_wlun || hba->dev_info.b_advanced_rpmb_en) { + if (!sdev || hba->dev_info.b_advanced_rpmb_en) { dev_info(hba->dev, "Skip OP-TEE RPMB registration\n"); return -ENODEV; } @@ -177,25 +186,26 @@ int ufs_rpmb_probe(struct ufs_hba *hba) return -EINVAL; } =20 - struct rpmb_descr descr =3D { - .type =3D RPMB_TYPE_UFS, - .route_frames =3D ufs_rpmb_route_frames, - .reliable_wr_count =3D hba->dev_info.rpmb_io_size, - }; - for (region =3D 0; region < ARRAY_SIZE(hba->dev_info.rpmb_region_size); r= egion++) { cap =3D hba->dev_info.rpmb_region_size[region]; if (!cap) continue; =20 - ufs_rpmb =3D devm_kzalloc(hba->dev, sizeof(*ufs_rpmb), GFP_KERNEL); + ufs_rpmb =3D kzalloc_obj(*ufs_rpmb); if (!ufs_rpmb) { ret =3D -ENOMEM; goto err_out; } =20 - ufs_rpmb->hba =3D hba; - ufs_rpmb->dev.parent =3D &hba->ufs_rpmb_wlun->sdev_gendev; + ret =3D scsi_device_get(sdev); + if (ret) { + kfree(ufs_rpmb); + goto err_out; + } + + ufs_rpmb->sdev =3D sdev; + ufs_rpmb->region_id =3D region; + ufs_rpmb->dev.parent =3D &sdev->sdev_gendev; ufs_rpmb->dev.bus =3D &ufs_rpmb_bus_type; ufs_rpmb->dev.release =3D ufs_rpmb_device_release; dev_set_name(&ufs_rpmb->dev, "ufs_rpmb%d", region); @@ -206,16 +216,14 @@ int ufs_rpmb_probe(struct ufs_hba *hba) ret =3D device_register(&ufs_rpmb->dev); if (ret) { dev_err(hba->dev, "Failed to register UFS RPMB device %d\n", region); - put_device(&ufs_rpmb->dev); - goto err_out; + goto err_put; } =20 /* Create unique ID by appending region number to device_id */ cid =3D kasprintf(GFP_KERNEL, "%s-R%d", hba->dev_info.device_id, region); if (!cid) { - device_unregister(&ufs_rpmb->dev); ret =3D -ENOMEM; - goto err_out; + goto err_unreg; } =20 blake2b(NULL, 0, cid, strlen(cid), dev_id, UFS_RPMB_ID_LEN); @@ -226,29 +234,30 @@ int ufs_rpmb_probe(struct ufs_hba *hba) =20 /* Register RPMB device */ rdev =3D rpmb_dev_register(&ufs_rpmb->dev, &descr); + kfree(cid); if (IS_ERR(rdev)) { dev_err(hba->dev, "Failed to register UFS RPMB device.\n"); - device_unregister(&ufs_rpmb->dev); ret =3D PTR_ERR(rdev); - goto err_out; + goto err_unreg; } =20 - kfree(cid); - cid =3D NULL; - ufs_rpmb->rdev =3D rdev; - ufs_rpmb->region_id =3D region; - list_add_tail(&ufs_rpmb->node, &hba->rpmbs); =20 dev_info(hba->dev, "UFS RPMB region %d registered (capacity=3D%u)\n", re= gion, cap); } =20 return 0; + +err_unreg: + device_unregister(&ufs_rpmb->dev); + goto err_out; +err_put: + put_device(&ufs_rpmb->dev); err_out: - kfree(cid); list_for_each_entry_safe(it, tmp, &hba->rpmbs, node) { list_del(&it->node); + rpmb_dev_unregister(it->rdev); device_unregister(&it->dev); } =20 @@ -268,6 +277,7 @@ void ufs_rpmb_remove(struct ufs_hba *hba) dev_info(hba->dev, "Removing UFS RPMB region %d\n", ufs_rpmb->region_id); /* Remove from list first */ list_del(&ufs_rpmb->node); + rpmb_dev_unregister(ufs_rpmb->rdev); /* Unregister device */ device_unregister(&ufs_rpmb->dev); } --=20 2.55.0.1007.g17ff1f9808-goog From nobody Fri Sep 25 09:20:24 2026 Received: from mail-pl1-f200.google.com (mail-pl1-f200.google.com [209.85.214.200]) (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 8232D481AAD for ; Mon, 14 Sep 2026 14:49:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.200 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789397361; cv=none; b=sPJ2yksiAZ9hoFzi1OBDJ1MIvRNcIyQDy8MJ7xFkuRqzAObMGOz33nUrueUcVuhyKxdFkeRuxnKoDCTUE9pOFCAPu5H1CuTKCAZS38uko2dbcGziRwXSZqlLDINK4kUf2k3ioI9GILf/Lqr9ABrCBkhy95nfdPz5Mt5dnQ5pGGI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789397361; c=relaxed/simple; bh=MOZvIDLp+P4PaYMlBybrB7g2C8901KtST7iPIcuJYX8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=A9Ezz319cS9HLqJUSFohrqGyy8/4gdrQnfWQI4qeZPxeMu7hjfGsV3PJVtY53VytCG0WZ6KPSGCBGs/vaH3dYBJUe/sW0KwJPxy6Jop+IljNDOE+4e3II5xujGTHYQlQe+yOsrHRQ87g1MVP4M5BY9kkklauX004deLS3WmYmFs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--stanleyjhu.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Ef5z76FD; arc=none smtp.client-ip=209.85.214.200 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--stanleyjhu.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Ef5z76FD" Received: by mail-pl1-f200.google.com with SMTP id d9443c01a7336-2d001671a54so64948835ad.2 for ; Mon, 14 Sep 2026 07:49:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1789397359; x=1790002159; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=GLuFMMXFta9UIcczpAvsByGxUUvVheyRObO/swxvTLo=; b=Ef5z76FDVm+xuBXJuMir2RXldcRSQn+UhyZYHeluZ3ANDkgC0BYV4ZYlOxsrkJMtZG XcKgk+9u61fwoL+eaU+qoxGpb+lOPAt1pc5Yckgwb/ogPFdImK9amogGEhNydQ1Abjj2 KVz9arysg+XVR1wObSW+dCa6ori2G/ZdWYlkLvnZtHnXM7wGzZvX9F1XyjnOZuqlOApK WWMe5SaOgTAer9Rk4q7SbX1UCHe1CwBg1AJQt81tixideRSkCYA+9ytnfBirICrqiRhX 4Tc+HiIWv7gMALrYq8VEnv/pbL2uVy2MmQqBi/P2uJtnYz+eiL9ZZrTjd6nYqdspVnjr wjSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1789397359; x=1790002159; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=GLuFMMXFta9UIcczpAvsByGxUUvVheyRObO/swxvTLo=; b=oFrZzhUhZPBbQRcM4BOSenUX+skRg79uK1n18240CcosqTO7KF1rzxCMpk7wXHIdff TWYox0ys0PDqw/A6Tb6UXyMaLlQj9L2QzMj7L+nrLORFu/OGfJpkKMWXfvo/ANe5r4Dh 6B+dvFAQMBLRXeufNaTQrGXP7CTbwiKTztuh72lDbNG9lKm9kJ6noOlo2IIPD9hxeEaa OHkMmZkCduBOLKw/n14ch07ux6FDMJfCBnDeweDVPl4uCf36mBfDNr5WXG9dOIq6/13S 8FCXZbSga+AJT9kcfp+vPxTrMxBIhmoPX8+j09JITkMax10GDvbmUYCwiLlP3OFgZd5F t06A== X-Forwarded-Encrypted: i=1; AKwUvBwFK76hRpyA84b/MBH4KNcl1WIpDhONd7AtqUuDz3BEyJhEftUT+od0l80KFi+4oBmy/DHac90UjQKvchU=@vger.kernel.org X-Gm-Message-State: AFuF++ksDW6sw/mlFZDH4b3eBLJicYH44MsBxqGruhFFfy6Jd1j5ZPUV XV9HXpCiZh57OMLvgVwj6pOUsnLe/5SwVPzKPNKdagc6X/tnrOGiHTHzL8dfCvNMkiDbYL5p0WX tUgYA1kvbH1A8rr5xSPgJlw== X-Received: from pldu13.prod.google.com ([2002:a17:903:108d:b0:2db:4e23:16ee]) (user=stanleyjhu job=prod-delivery.src-stubby-dispatcher) by 2002:a17:902:ebc8:b0:2d8:d4d0:792f with SMTP id d9443c01a7336-2dd6c76cee8mr56584075ad.19.1789397358517; Mon, 14 Sep 2026 07:49:18 -0700 (PDT) Date: Mon, 14 Sep 2026 22:49:10 +0800 In-Reply-To: <20260914144910.931518-1-stanleyjhu@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260914144910.931518-1-stanleyjhu@google.com> X-Mailer: git-send-email 2.55.0.1007.g17ff1f9808-goog Message-ID: <20260914144910.931518-4-stanleyjhu@google.com> Subject: [PATCH v5 3/3] scsi: ufs: rpmb: Drop the unregistered ufs_rpmb bus From: Stanley Jhu To: jenswi@kernel.org, mkp@kernel.org Cc: gregkh@linuxfoundation.org, arnd@arndb.de, bvanassche@acm.org, avri.altman@sandisk.com, alim.akhtar@samsung.com, beanhuo@micron.com, can.guo@oss.qualcomm.com, ulfh@kernel.org, linusw@kernel.org, shyamsaini@linux.microsoft.com, alex.bennee@linaro.org, James.Bottomley@hansenpartnership.com, linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org, Stanley Jhu , stable@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" ufs_rpmb_probe() assigns ufs_rpmb_bus_type to dev.bus, but that bus is never passed to bus_register(). bus_add_device() used to return success and leave such a device off the bus. UFS RPMB therefore registered from v6.19 onwards, with /sys/bus/ufs_rpmb simply absent. Since commit 36f35b8df697 ("driver core: reject devices with unregistered buses") in v7.2-rc1 it returns -EINVAL instead, and device_register() fails: bus_add_device: cannot add device 'ufs_rpmb0' to unregistered bus 'ufs_rpmb' ufshcd 0000:00:02.0: Failed to register UFS RPMB device 0 ufs_rpmb_probe() unwinds on the first failure, so no region registers at all and /sys/class/rpmb stays empty. ufs_rpmb_bus_type declares no .match and no .probe, and no driver binds to it. RPMB devices are exposed to consumers through /sys/class/rpmb/, which rpmb_dev_register() already sets up. Drop the bus rather than register it: device_register() works with dev.bus left NULL given a parent and a release callback, both of which ufs_rpmb_probe() sets. With the bus gone, on a device advertising four RPMB regions: ufshcd 0000:00:02.0: UFS RPMB region 0 registered (capacity=3D32) ufshcd 0000:00:02.0: UFS RPMB region 1 registered (capacity=3D32) ufshcd 0000:00:02.0: UFS RPMB region 2 registered (capacity=3D32) ufshcd 0000:00:02.0: UFS RPMB region 3 registered (capacity=3D32) /sys/class/rpmb then holds rpmb0 to rpmb3, and unbinding the host removes them. Fixes: b06b8c421485 ("scsi: ufs: core: Add OP-TEE based RPMB driver for UFS= devices") Cc: stable@vger.kernel.org Signed-off-by: Stanley Jhu Reviewed-by: Bean Huo --- drivers/ufs/core/ufs-rpmb.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/ufs/core/ufs-rpmb.c b/drivers/ufs/core/ufs-rpmb.c index a3e43902bf08..ad3e8b054dc6 100644 --- a/drivers/ufs/core/ufs-rpmb.c +++ b/drivers/ufs/core/ufs-rpmb.c @@ -28,10 +28,6 @@ #define UFS_RPMB_SEC_PROTOCOL 0xEC /* JEDEC UFS application */ #define UFS_RPMB_SEC_PROTOCOL_ID 0x01 /* JEDEC UFS RPMB protocol ID, CDB b= yte3 */ =20 -static const struct bus_type ufs_rpmb_bus_type =3D { - .name =3D "ufs_rpmb", -}; - /* UFS RPMB device structure */ struct ufs_rpmb_dev { u8 region_id; @@ -206,7 +202,6 @@ int ufs_rpmb_probe(struct ufs_hba *hba) ufs_rpmb->sdev =3D sdev; ufs_rpmb->region_id =3D region; ufs_rpmb->dev.parent =3D &sdev->sdev_gendev; - ufs_rpmb->dev.bus =3D &ufs_rpmb_bus_type; ufs_rpmb->dev.release =3D ufs_rpmb_device_release; dev_set_name(&ufs_rpmb->dev, "ufs_rpmb%d", region); =20 --=20 2.55.0.1007.g17ff1f9808-goog