From nobody Fri Sep 25 11:57:33 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 BC2DE386426 for ; Sun, 13 Sep 2026 03:36:37 +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=1789270599; cv=none; b=UKBbN27OExJbpgR7o0LpyQqUT8WLwup0YUFx/KcFouU+sUTTKhXMRuLlMq2YFZzEZBKT0nLlzfFXalmiU2LGlCoYWZzDh3HNaiqXREpdTjFYXh8bM8XTpLTnklDkbdkiZq3MzYukV+XTYniHvOjGNyPNzYGs+ob4KNpG5e8L23A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789270599; c=relaxed/simple; bh=Q7N55ZKGMhUVafnhQytlmQyt5wlMWqJxtit4S7G1Bmk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=ZbRyrFnGJFQW8Y53FAX+3TnHNEIkD3lDOHmfCSt45Nbw8M7XEeeU0DmMdoNyjUcxA4uUq/M86DewFAhe+EuGphfEC/6FieP730LwCO9UvkEWebNj55rWDuMmirFIHrPshgZFErwBNZ52qprnCv3z7MD9Y01ppt0wVSo3weAKOZY= 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=AVsL3icE; 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="AVsL3icE" Received: by mail-pj1-f69.google.com with SMTP id 98e67ed59e1d1-38dbf293831so4905279a91.3 for ; Sat, 12 Sep 2026 20:36:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1789270597; x=1789875397; 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=Fs6YuwwYNgKZrcAVirPLF9TAZSnieT4vB0v2ARdNeLY=; b=AVsL3icEivUKLI1imZpyNIlnWX/QL2QEz5HFVi6hUo3SKjEuDXFqjUyOU5FKK5NTXq lM/0ysM7cAiMJug8FHxRYsR+5lpAR7EP8kc9DR4prZGO1j2W7M60MAnTVOqp94NHnrPD fe7fRu1/dD6NdPaVAtXpEkkY6iq4l2za4vi1jpsfu1b5vdCpOkCJi1OAPP6ckuhTcJt3 QOs+M/WpQwYScYvCyoZypJYBrL+ix3WcIrBidt/g/uDB6Jq+TP3puxzwoR7qrg55qXBS TJx+/Ts3lHZz0WpuYW5Za2i6kjb5FYy88vHVZA+59ilgfdd8yKIhHeoYdUNNbVirLWkZ dyrg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1789270597; x=1789875397; 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=Fs6YuwwYNgKZrcAVirPLF9TAZSnieT4vB0v2ARdNeLY=; b=Vo3VaiGORjbJWFkBM7vWMWAlJEsShHMV3a/sqdp9fKROG5s9Z9ew5qyESEpwSOkZAF zbLzmHmtrvW5/7gusuIzkORWfRw8Ciq2ep5okIZ8nbv8vCi4xu/FLWnpssW8/v4QdyBf 4OxDzTtEpYAsME5MpFQUnwXmZ7j5XdCswnoWyEqhfnK3+wg0rbk73Ww9juav5+7imfyw GeysnMuTsjYEF5C6cNz+7y8ErmDtePrT4e9G4S6iLkUBpOFyvjX7m1dMRwsCuManKhR2 Rid2fl5+ceYqo9MlINmSLOyyrr8e+6b0dE8mg9Ut205MBcKSXINBCUKVB9q8qDojTB4u daUg== X-Forwarded-Encrypted: i=1; AKwUvBxgzPVtNW8gAhrCHRxjPqBKTwoI4FTE9HP+xFWlrLSe619GVn3BsSs7DbEm4f/F609C+efRY0YSsHUFKtk=@vger.kernel.org X-Gm-Message-State: AFuF++n0G2whzNWrFAjazpMZFhGJH8pQpoVyfO4OaAVkaQIfQDoxDp1d dm5JlhPJNAV09vJWj09LNuakAGy3DTIUxrnYSvowIOtIS6ZWqlsPvh90r/yJWrnSbiojwBBX0WA Iyj6ZiMxjT15untMMwtlnrw== X-Received: from pjsd15.prod.google.com ([2002:a17:90a:bf8f:b0:39d:c24e:697b]) (user=stanleyjhu job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90a:d64c:b0:396:d27b:89b9 with SMTP id 98e67ed59e1d1-39d9bd6197bmr20361369a91.10.1789270596929; Sat, 12 Sep 2026 20:36:36 -0700 (PDT) Date: Sun, 13 Sep 2026 11:36:31 +0800 In-Reply-To: <20260913033633.3159296-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: <20260913033633.3159296-1-stanleyjhu@google.com> X-Mailer: git-send-email 2.55.0.1007.g17ff1f9808-goog Message-ID: <20260913033633.3159296-2-stanleyjhu@google.com> Subject: [PATCH v4 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, tomas.winkler@intel.com, 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 on different CPUs issuing RPMB_GET_WRITE_COUNTER against the same UFS RPMB region, 20000 iterations each: thread 0 done: 20000 iterations, mismatches=3D10889, errors=3D0 thread 1 done: 20000 iterations, mismatches=3D6141, errors=3D0 race complete: MISMATCH=3D17030 ERRORS=3D0 A mismatch is a response whose echoed nonce belongs to the other thread, so 43% of requests returned somebody else's frame. The errors count is transport failures, so nothing failed and the corruption is silent to the caller. An authenticated RPMB operation is not one command. The UFS provider issues SECURITY PROTOCOL OUT carrying the request, then SECURITY PROTOCOL IN to collect the response, with a result read request in between for write-type operations. JESD220F 12.4.7 states that any request other than a result read overwrites the result register of the region, so a request landing in the middle of another initiator's sequence destroys its response. The same chapter states that a region processes one authenticated operation at a time, so the rpmb_dev is the granularity the device itself assumes. A request can also still be in flight when the provider tears down. The core reaches the provider through rdev->dev.parent, and the provider is free to release that device as soon as rpmb_dev_unregister() returns. Reference counting on the rpmb_dev does not prevent this: rpmb_dev_unregister() calls device_del(), which drops the reference that device_add() took on the parent, so the parent can be freed while the rpmb_dev is still alive and still routable. Unbinding a UFS host while a consumer holds an rpmb_dev reference and 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 Both measurements needed patches 2/3 and 3/3 of this series applied, because UFS RPMB registration fails on mainline. The stable tag is for eMMC, which registers today. mmc_route_rpmb_frames() packs the whole sequence into one block request, so eMMC is not exposed to the interleaving above, but it does have the teardown window: mmc_blk_remove() reaches rpmb_dev_unregister() through mmc_blk_remove_parts() near its start, while the queue that mmc_route_rpmb_frames() submits to is only torn down at the end by mmc_blk_remove_req(), whose comment notes that it is freeing the queue that stops new requests being accepted. The eMMC window is from source reading; I have not reproduced it. The kerneldoc change is part of the fix. Calling rpmb_dev_unregister() from a release callback cannot work, because the child rpmb_dev holds a reference on its parent, so the parent's release callback never runs. The UFS provider does exactly that today, inert only because its registration fails; patch 2/3 moves the call to the remove path. Add a mutex and a dead flag to struct rpmb_dev. rpmb_route_frames() holds the mutex across the whole sequence and returns -ENODEV once the flag is set. rpmb_dev_unregister() sets the flag under the mutex before device_del(), so it cannot return while a request is inside the provider. Closing the teardown window requires excluding unregistration for the whole duration of a request, which is the same exclusion that serialises two requests, so one mutex covers both. On the same test with this patch applied, MISMATCH=3D0 and the unbind is clean. 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 --- drivers/misc/rpmb-core.c | 34 +++++++++++++++++++++++++++++----- include/linux/rpmb.h | 6 ++++++ 2 files changed, 35 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..814ac3e69337 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,20 @@ struct rpmb_descr { * struct rpmb_dev - device which can support RPMB partition * * @dev : device + * @lock : protects in-flight operations against teardown * @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; + /* Protects in-flight operations against teardown */ + struct mutex lock; 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 11:57:33 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 D3A59384CE9 for ; Sun, 13 Sep 2026 03:36:39 +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=1789270602; cv=none; b=gu0Pb4ul7py+LZ841MIC0Ost3/wlwLcwPMCY8xlVEO/4mDLhHSQtIv6cK2Hj2Wk5w1B4OADbOwi5L3141VtSWiPIRQku9M7bmolGdSkjExcGqI8xMUOVoDwb6QK98VzjuLLBgsNOoy/p2HuTpZxS5NdbsaY+BW1WkQejNka+Ens= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789270602; c=relaxed/simple; bh=zsX6NYnNsejgjNazlrChC+W6g+2YM7MKSFREvyxN8NA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=nBUdtooU0ka5FQN9kFDsueSsZ2c+HG8mmsnkNxDGC5CYbaJLo3hLHivT5mwNQveHN6pYSm1BlekqthTmpRvjiUCyCmJaF4zGdfmCTh7SOENd9JNaHS97PKs5ISrZtzrUEwe/OSYonYXPEYAHdEFDGqaPZGDce7+QEMZeCPPKRos= 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=uVu4OEIP; 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="uVu4OEIP" Received: by mail-pj1-f69.google.com with SMTP id 98e67ed59e1d1-38ea32e57e2so4414357a91.1 for ; Sat, 12 Sep 2026 20:36:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1789270599; x=1789875399; 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=3+n+gxC6c8qCaIycTzSiuzlL3MF13bppr3mewDj0veo=; b=uVu4OEIPoMmCWywAwsMZEoj6TeJxyPS2ulx3G5KKbmJwMFy7xm19sXVY/xyLSWwMi+ Iimv1fxJnLOVnEaKcJ9rW6XJoskvRHOXSBMlrNMxxeZbUbDwbgc/A5K2dXKeSxrKkq18 gip4Z//WUxghYQCuPKWw9cwwH/4Vj45VGldgY0sw9OQGJHDiRwTwwM3hha1ACV3cVs0G fHT+/GKXiDZ8TS1teXM/V8zzrASO681hUcl3x3A9KHSqVczqJIKW/gBqrvvFpN5pGY6z Q6zGgUetKCFN+oZP7IjBKYehAIjr8VO3uIB5+epnvYsCnM4UhuIOmrXamCgNzz4H9b/O CpQg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1789270599; x=1789875399; 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=3+n+gxC6c8qCaIycTzSiuzlL3MF13bppr3mewDj0veo=; b=MLy/WngkT/lcWd6ZQD+n5irSujZVlwn5SPuMbFD/yATidJLrtLM4cRLibaf0Bbcudi wQ9riMGBNm+TWuXhAKeVFHe3ZlAqAX7zQBdlrNW4b0lje1Pni2st48MoAop0zT79pFC4 /BjjKn+u5RigG/Ic3jeuJxOKRLkwZTp+sGLw5cWxVZ+F3kvUDvB7gMEqAtLayapk7NUG mQ3DOwAXojKXkpV/Xzl+QBxmqcf4+yY2xYNvULYQMa9V3FlI+d1NDt0gT12vQAeh2yzY PO3dlGFpuUTLW+HeHiPoVkHZ49UPPOUvp6tLmLz5SKTl2cwI0QJm+OaV3JZ5tM553yLt jdbw== X-Forwarded-Encrypted: i=1; AKwUvBzVf6FX211gGI1kp8IDU9aJDqKfGBMDmsFZAMWyeMaMUXqyRFbvv83myqFvQck2Ko0iVG0M0MgR8mT8EsI=@vger.kernel.org X-Gm-Message-State: AFuF++kiq74whzA1OoecwDjM3W89tB7J6uVq72Dynn6uFvQYlPLTKQUS xBH0Ku70uxPBVTGH614PP6aTyqG1r1xQJ5kqfoJ0Sb7omO4fSrrUvw8hJCZKyJKspPPDxzYZFiB ForiUy+1xPUwgQhZyp3fPpg== X-Received: from pjbgb3.prod.google.com ([2002:a17:90b:603:b0:39d:a358:fc00]) (user=stanleyjhu job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:2588:b0:36a:5d1f:7b6 with SMTP id 98e67ed59e1d1-39dbbe87b09mr9428532a91.2.1789270598806; Sat, 12 Sep 2026 20:36:38 -0700 (PDT) Date: Sun, 13 Sep 2026 11:36:32 +0800 In-Reply-To: <20260913033633.3159296-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: <20260913033633.3159296-1-stanleyjhu@google.com> X-Mailer: git-send-email 2.55.0.1007.g17ff1f9808-goog Message-ID: <20260913033633.3159296-3-stanleyjhu@google.com> Subject: [PATCH v4 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, tomas.winkler@intel.com, shyamsaini@linux.microsoft.com, alex.bennee@linaro.org, James.Bottomley@HansenPartnership.com, linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org, Stanley Jhu 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 controller. devres frees that memory when the host driver detaches, regardless of the device reference count, and probe takes no reference on the RPMB well known LU either. An in-flight request then 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 device_add() holds a reference on the parent. ufs_rpmb_remove() only calls device_unregister() on that parent, whose count therefore never reaches zero, and ufs_rpmb_device_release() is the only caller of rpmb_dev_unregister(). Tie the memory to the reference count instead: - allocate with kzalloc_obj() and free with kfree() in ufs_rpmb_device_release() - pin the SCSI WLUN with scsi_device_get() in probe and release it with scsi_device_put() in the release callback - call rpmb_dev_unregister() from ufs_rpmb_remove() and from the probe error unwind, before device_unregister(), so the cycle is broken - reject requests once the WLUN is offline, rather than submitting to a device that SCSI has already removed On its own this patch changes nothing observable: device_register() still fails because the ufs_rpmb bus is never registered, so no RPMB device exists. The next patch removes that bus, and the trace above was taken with both applied. The ordering is deliberate: no commit in this series enables RPMB registration before the lifetime handling is correct. Fixes: b06b8c421485 ("scsi: ufs: core: Add OP-TEE based RPMB driver for UFS= devices") Signed-off-by: Stanley Jhu Reviewed-by: Bean Huo --- drivers/ufs/core/ufs-rpmb.c | 97 +++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/drivers/ufs/core/ufs-rpmb.c b/drivers/ufs/core/ufs-rpmb.c index 783ecfc7581d..373b60aba916 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,28 @@ 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; + INIT_LIST_HEAD(&ufs_rpmb->node); + + 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 +218,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 +236,33 @@ 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); + list_del_init(&it->node); + if (it->rdev) { + rpmb_dev_unregister(it->rdev); + it->rdev =3D NULL; + } device_unregister(&it->dev); } =20 @@ -265,14 +279,13 @@ void ufs_rpmb_remove(struct ufs_hba *hba) =20 /* Remove all registered RPMB devices */ list_for_each_entry_safe(ufs_rpmb, tmp, &hba->rpmbs, node) { - dev_info(hba->dev, "Removing UFS RPMB region %d\n", ufs_rpmb->region_id); - /* Remove from list first */ - list_del(&ufs_rpmb->node); - /* Unregister device */ + list_del_init(&ufs_rpmb->node); + if (ufs_rpmb->rdev) { + rpmb_dev_unregister(ufs_rpmb->rdev); + ufs_rpmb->rdev =3D NULL; + } device_unregister(&ufs_rpmb->dev); } - - dev_info(hba->dev, "All UFS RPMB devices unregistered\n"); } =20 MODULE_LICENSE("GPL v2"); --=20 2.55.0.1007.g17ff1f9808-goog From nobody Fri Sep 25 11:57:33 2026 Received: from mail-pj1-f71.google.com (mail-pj1-f71.google.com [209.85.216.71]) (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 1423D3793A2 for ; Sun, 13 Sep 2026 03:36:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.71 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789270604; cv=none; b=RoA3AySdHUGL4N5YjrCTx8klcvJTexoifv050E1xi08smSRWqF6dV7Hx0Ty1aYw7f30dd8P6fvOxPTBtYqaA6BigxGeYhg1g1WbZT2rxbbFIoZa5oqyz4TBT1Qbh/MKpgegnGL1ZuKVquBziKf+EtVesRF+d9JFtYf0vlzNImu8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789270604; c=relaxed/simple; bh=y5nlk2rbktcB0mr9bhig5aE1DSOnUCWGPb9Zv50URaM=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=sTMfRbr6DzqE/7ozj1Yv8OrS1DaGtfPth7atgtdYn2KNzg8CY3FZEz0FjtcsruQOvzFVIH2cdIfiS2H+wCDsF4t4WyycpJ/bq6Kfz1L7H4aI6JyynL4J5uycFDAvXZFOErV1A9UEjs7DU8Ad4UmOp1Vd+cE5hpAWZ7Xsxgia1iE= 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=nmGOYYym; arc=none smtp.client-ip=209.85.216.71 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="nmGOYYym" Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-381250979d5so2439131a91.0 for ; Sat, 12 Sep 2026 20:36:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1789270601; x=1789875401; 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=BpeuUSLBGH+HVGEYbdNREfMzEQGOS789hsIrwdg90ro=; b=nmGOYYymJu0BbBMa+PLeVdTRcZX6FCFCsHG3+9ElpkokEsdsZfhPoGh/bSb7fn/oRJ bI/X1f7d4vr3VZhfDD4GoF8JtS/mugTw0QCgpTrNw5Ko9A1jF63j1xGMFB6BzeVCFYoB A+qGFHF/SmMCPvqrBqmWyr01K3RnU1dD6weRpNwqBfXfTS8zmmamgwS6SDrKgxuYDdBe s0Vo2X0DXv5q0X8sB28kdOFatFvGWls9o/ec3W+Bt7ncr5oiuT7UQezk41DMfna3sVMY kJBueUbTsb7b6WwxO+R8DTDMCy4oWdP5pi8rgDrU5UKetwyg490W8jCZjHaJVCssPJuk VObw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1789270601; x=1789875401; 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=BpeuUSLBGH+HVGEYbdNREfMzEQGOS789hsIrwdg90ro=; b=nxMrn5mT+NQaI64u9ryfpO/uTuH22cuW8ZyLjATw746UVm57bP6Y8Kl/0Az1thdRUh sPnFXY6lAnjm2ECHO2ImY0mTBp+RFXaqIQpgSr4qXmzREYuph/84bYYpOddlEEHu2skg Q8lH5KE4HUi0RcUz3aHIHPGf70PUKS8LJUkRkRi+62gb3SaJcD8Stk1jE+FQOF0BxtXD FQzpNH8lcBsg12vHGc4u1y0QaFWc9VK5hq4v+HMxztwRwTsbDnOdTjuhQKhYvTEYi1UU 6EEYdXLk6dmTAoScdRCAQYqWl35Yzasce9OuNYfX4h9y+k+o0rCmPVgtU1hqsU9PtPIC rNUA== X-Forwarded-Encrypted: i=1; AKwUvBzRe4ZOGuuP6JsvEeWVbzYM3gkOc0Ua7A4+e8rcC+gpWOiW3VXZ8fbvWNgxZolZHbth1rq4ORfvnY1OtHU=@vger.kernel.org X-Gm-Message-State: AFuF++mAml+Lj4apF5ZAgH1lfPeM5bkWtNj6C+oQm1mjsTS+MpIHje91 JM9JrxVUA3FjZX73tncUaNOyX6oEPD2A23nGyleNC3TrIUD3ieyKHhghdTBnkX2B7EKqiIMyU5S A/NJYZSLLV15vho2syEGyfw== X-Received: from pjst9.prod.google.com ([2002:a17:90b:189:b0:39d:915e:403]) (user=stanleyjhu job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:440e:b0:38f:efed:5445 with SMTP id 98e67ed59e1d1-39d9bc0ff30mr19633535a91.4.1789270600695; Sat, 12 Sep 2026 20:36:40 -0700 (PDT) Date: Sun, 13 Sep 2026 11:36:33 +0800 In-Reply-To: <20260913033633.3159296-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: <20260913033633.3159296-1-stanleyjhu@google.com> X-Mailer: git-send-email 2.55.0.1007.g17ff1f9808-goog Message-ID: <20260913033633.3159296-4-stanleyjhu@google.com> Subject: [PATCH v4 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, tomas.winkler@intel.com, shyamsaini@linux.microsoft.com, alex.bennee@linaro.org, James.Bottomley@HansenPartnership.com, linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org, Stanley Jhu 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() rejects devices on an unregistered bus, so device_register() has always failed: 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 RPMB region has ever been registered and /sys/bus/ufs_rpmb/devices/ has never been populated. 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") 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 373b60aba916..684fb37705c7 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; @@ -208,7 +204,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