* [PATCH v3 0/2] ufs: rpmb: make RPMB usable with OP-TEE key derivation
@ 2026-08-21 15:06 Jorge Ramirez-Ortiz
2026-08-21 15:06 ` [PATCH v3 1/2] ufs: rpmb: retry power-on UNIT ATTENTION on the RPMB WLUN Jorge Ramirez-Ortiz
2026-08-21 15:06 ` [PATCH v3 2/2] ufs: rpmb: use a fixed-length RPMB dev_id Jorge Ramirez-Ortiz
0 siblings, 2 replies; 4+ messages in thread
From: Jorge Ramirez-Ortiz @ 2026-08-21 15:06 UTC (permalink / raw)
To: jorge.ramirez, James.Bottomley, martin.petersen, alim.akhtar,
avri.altman, bvanassche, beanhuo, beanhuo, can.guo
Cc: linux-scsi, linux-kernel, op-tee, jenswi, sumit.garg
This series makes UFS RPMB work out of the box with an OP-TEE that
implements the standard eMMC RPMB key-derivation flow, without requiring
any fundamental changes on the OP-TEE side.
RPMB provides an authenticated, replay-protected storage area whose
security relies on a secret authentication key. In our setup that key is
never exposed to the kernel: OP-TEE derives it in the secure world from
its hardware-unique key and a device identifier (dev_id) that the RPMB
core hands down. OP-TEE's implementation targets eMMC, where dev_id is
the 16-byte eMMC CID, and both the fixed length and the raw-CID layout
are baked into its key derivation.
Two things stand in the way of reusing that same, unmodified OP-TEE flow
for UFS RPMB:
1. On a cold boot the very first frame sent to the RPMB well-known LU
comes back with a power-on UNIT ATTENTION (ASC 0x29), which the SCSI
core reports rather than retries. RPMB has no earlier guaranteed
access that could clear the condition first, so RPMB fails on every
power cycle. Patch 1 asks the SCSI core to retry the power-on UNIT
ATTENTION on the RPMB WLUN.
2. The UFS RPMB id is "<device_id>-R<region>", which is variable length
and longer than 16 bytes. Passing it verbatim would tie the derived
key to a length OP-TEE does not expect and diverge from the fixed
eMMC CID ABI. Patch 2 hashes it into a fixed 16-byte dev_id with
blake2b, keeping the key stable and unique per region while matching
the eMMC CID layout OP-TEE relies on. The hash algorithm and input
string are thus part of the key-derivation ABI and must stay stable.
With both patches, UFS RPMB is functional from the first access after a
cold boot and derives keys through the existing eMMC-style OP-TEE flow,
(requires minimal OP-TEE changes pending on the CID proposal done here).
Tested on IQ-9075 with Open Firmware [1], pending OP-TEE changes
[1]https://ldts.github.io/qcom-buildroot
Dependencies:
U-boot:
https://lore.kernel.org/u-boot/20260720085202.537019-1-jorge.ramirez@oss.qualcomm.com/T/#mc423eb4dcf8a15849077029e4f7c1913bb7d8873
OP-TEE:
https://github.com/OP-TEE/optee_os/pull/7881
v3:
* ufs: rpmb: use a fixed-length RPMB dev_id: hash into a stack buffer
instead of a kzalloc'd one; rpmb_dev_register() copies dev_id, so the
heap allocation and its cleanup were unnecessary.
v2:
* ufs: rpmb: replace blake2s with blake2b so that the same support
can be added to u-boot (CRYPTO_LIB_BLAKE2B)
* added links to U-boot and OP-TEE changes.
v1:
* ufs: rpmb: retry power-on UNIT ATTENTION on the RPMB WLUN:
- fix using uses SCMD_FAILURE_ASC_ANY to retry any Unit Attention
- fix unused variable
* ufs: rpmb: use a fixed-length RPMB dev_id
- fix selecting a non-existent Kconfig symbol
Jorge Ramirez-Ortiz (2):
ufs: rpmb: retry power-on UNIT ATTENTION on the RPMB WLUN
ufs: rpmb: use a fixed-length RPMB dev_id
drivers/ufs/Kconfig | 1 +
drivers/ufs/core/ufs-rpmb.c | 29 ++++++++++++++++++++++++++---
2 files changed, 27 insertions(+), 3 deletions(-)
--
2.54.0
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH v3 1/2] ufs: rpmb: retry power-on UNIT ATTENTION on the RPMB WLUN 2026-08-21 15:06 [PATCH v3 0/2] ufs: rpmb: make RPMB usable with OP-TEE key derivation Jorge Ramirez-Ortiz @ 2026-08-21 15:06 ` Jorge Ramirez-Ortiz 2026-08-21 15:06 ` [PATCH v3 2/2] ufs: rpmb: use a fixed-length RPMB dev_id Jorge Ramirez-Ortiz 1 sibling, 0 replies; 4+ messages in thread From: Jorge Ramirez-Ortiz @ 2026-08-21 15:06 UTC (permalink / raw) To: jorge.ramirez, James.Bottomley, martin.petersen, alim.akhtar, avri.altman, bvanassche, beanhuo, beanhuo, can.guo Cc: linux-scsi, linux-kernel, op-tee, jenswi, sumit.garg After a power cycle, the first command sent to a UFS logical unit completes with CHECK CONDITION and a power-on UNIT ATTENTION (ASC 0x29). The SCSI core reports this to the caller instead of retrying it. For the RPMB well-known LU, that first command is the first RPMB frame sent after boot, so the frame fails. RPMB has no earlier, guaranteed access that could clear the condition beforehand, so this breaks RPMB on every cold boot. Ask the SCSI core to retry the power-on UNIT ATTENTION on the RPMB WLUN so that RPMB works from the very first access after a power cycle. Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com> --- drivers/ufs/core/ufs-rpmb.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufs-rpmb.c b/drivers/ufs/core/ufs-rpmb.c index ffad049872b9..d0c7ea7a36f4 100644 --- a/drivers/ufs/core/ufs-rpmb.c +++ b/drivers/ufs/core/ufs-rpmb.c @@ -40,6 +40,23 @@ struct ufs_rpmb_dev { static int ufs_sec_submit(struct ufs_hba *hba, u16 spsp, void *buffer, size_t len, bool send) { struct scsi_device *sdev = hba->ufs_rpmb_wlun; + /* Retry the power-on UNIT ATTENTION (ASC 0x29); the SCSI core does not. */ + struct scsi_failure failure_defs[] = { + { + .sense = UNIT_ATTENTION, + .asc = 0x29, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .allowed = 3, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; + const struct scsi_exec_args exec_args = { + .failures = &failures, + }; u8 cdb[12] = { }; cdb[0] = send ? SECURITY_PROTOCOL_OUT : SECURITY_PROTOCOL_IN; @@ -48,7 +65,8 @@ static int ufs_sec_submit(struct ufs_hba *hba, u16 spsp, void *buffer, size_t le put_unaligned_be32(len, &cdb[6]); return scsi_execute_cmd(sdev, cdb, send ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, - buffer, len, /*timeout=*/30 * HZ, 0, NULL); + buffer, len, /*timeout=*/30 * HZ, /*retries=*/0, + &exec_args); } /* UFS RPMB route frames implementation */ -- 2.54.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v3 2/2] ufs: rpmb: use a fixed-length RPMB dev_id 2026-08-21 15:06 [PATCH v3 0/2] ufs: rpmb: make RPMB usable with OP-TEE key derivation Jorge Ramirez-Ortiz 2026-08-21 15:06 ` [PATCH v3 1/2] ufs: rpmb: retry power-on UNIT ATTENTION on the RPMB WLUN Jorge Ramirez-Ortiz @ 2026-08-21 15:06 ` Jorge Ramirez-Ortiz 2026-08-21 15:24 ` sashiko-bot 1 sibling, 1 reply; 4+ messages in thread From: Jorge Ramirez-Ortiz @ 2026-08-21 15:06 UTC (permalink / raw) To: jorge.ramirez, James.Bottomley, martin.petersen, alim.akhtar, avri.altman, bvanassche, beanhuo, beanhuo, can.guo Cc: linux-scsi, linux-kernel, op-tee, jenswi, sumit.garg The RPMB authentication key is derived from the dev_id handed to the RPMB subsystem. OP-TEE implements the eMMC RPMB flow, where the dev_id is the eMMC CID, a fixed 16-byte value, and it derives the key on that assumption. The UFS RPMB id built here is "<device_id>-R<region>", which is variable length and longer than 16 bytes. Passing it verbatim would tie the derived key to a length OP-TEE does not expect and diverge from the fixed-CID eMMC ABI, requiring OP-TEE to be taught about variable-length UFS ids. Hash the UFS id into a fixed 16-byte dev_id with blake2b instead. This keeps the derived key stable and unique per region while matching the eMMC CID layout OP-TEE relies on, so the key-derivation ABI stays identical and no OP-TEE change is needed. blake2b is used because it is already available in bootloaders such as U-Boot that must derive the same dev_id, avoiding the need to add a blake2s implementation there. Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com> --- drivers/ufs/Kconfig | 1 + drivers/ufs/core/ufs-rpmb.c | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig index f662e7ce71f1..b62c00e7ff06 100644 --- a/drivers/ufs/Kconfig +++ b/drivers/ufs/Kconfig @@ -7,6 +7,7 @@ menuconfig SCSI_UFSHCD tristate "Universal Flash Storage Controller" depends on SCSI && SCSI_DMA depends on RPMB || !RPMB + select CRYPTO_LIB_BLAKE2B if RPMB select PM_DEVFREQ select DEVFREQ_GOV_SIMPLE_ONDEMAND select NLS diff --git a/drivers/ufs/core/ufs-rpmb.c b/drivers/ufs/core/ufs-rpmb.c index d0c7ea7a36f4..a1e169ad3096 100644 --- a/drivers/ufs/core/ufs-rpmb.c +++ b/drivers/ufs/core/ufs-rpmb.c @@ -10,6 +10,7 @@ * Can Guo <can.guo@oss.qualcomm.com> */ +#include <crypto/blake2b.h> #include <linux/module.h> #include <linux/device.h> #include <linux/kernel.h> @@ -21,6 +22,7 @@ #include <linux/unaligned.h> #include "ufshcd-priv.h" +#define UFS_RPMB_ID_LEN 16 /* Match eMMC CID Length */ #define UFS_RPMB_SEC_PROTOCOL 0xEC /* JEDEC UFS application */ #define UFS_RPMB_SEC_PROTOCOL_ID 0x01 /* JEDEC UFS RPMB protocol ID, CDB byte3 */ @@ -153,6 +155,7 @@ static void ufs_rpmb_device_release(struct device *dev) int ufs_rpmb_probe(struct ufs_hba *hba) { struct ufs_rpmb_dev *ufs_rpmb, *it, *tmp; + u8 dev_id[UFS_RPMB_ID_LEN]; struct rpmb_dev *rdev; char *cid = NULL; int region; @@ -213,8 +216,10 @@ int ufs_rpmb_probe(struct ufs_hba *hba) goto err_out; } - descr.dev_id = cid; - descr.dev_id_len = strlen(cid); + blake2b(NULL, 0, cid, strlen(cid), dev_id, UFS_RPMB_ID_LEN); + + descr.dev_id = dev_id; + descr.dev_id_len = UFS_RPMB_ID_LEN; descr.capacity = cap; /* Register RPMB device */ -- 2.54.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v3 2/2] ufs: rpmb: use a fixed-length RPMB dev_id 2026-08-21 15:06 ` [PATCH v3 2/2] ufs: rpmb: use a fixed-length RPMB dev_id Jorge Ramirez-Ortiz @ 2026-08-21 15:24 ` sashiko-bot 0 siblings, 0 replies; 4+ messages in thread From: sashiko-bot @ 2026-08-21 15:24 UTC (permalink / raw) To: Jorge Ramirez-Ortiz; +Cc: linux-scsi Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: Pre-existing issues: - [High] Use-after-free due to improper devm_kzalloc allocation of a structure containing an embedded struct device. - [High] Permanent resource leak of parent and child devices due to a circular reference dependency in the teardown path. -- --- Patch [2]: [PATCH v3 2/2] ufs: rpmb: use a fixed-length RPMB dev_id --- commit 9b16b5ee089ea3c3bc7689863d98de4a3af82dfa Author: Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com> ufs: rpmb: use a fixed-length RPMB dev_id The RPMB authentication key is derived from the dev_id handed to the RPMB subsystem. OP-TEE expects a fixed 16-byte eMMC CID. This patch hashes the variable-length UFS id into a fixed 16-byte dev_id using blake2b. > diff --git a/drivers/ufs/core/ufs-rpmb.c b/drivers/ufs/core/ufs-rpmb.c > index 5f98472369d00..90dd7fd64ff1f 100644 > --- a/drivers/ufs/core/ufs-rpmb.c > +++ b/drivers/ufs/core/ufs-rpmb.c [ ... ] > @@ -157,6 +159,7 @@ static void ufs_rpmb_device_release(struct device *dev) > int ufs_rpmb_probe(struct ufs_hba *hba) > { > struct ufs_rpmb_dev *ufs_rpmb, *it, *tmp; [Severity: High] This is a pre-existing issue, but does using devm_kzalloc for a structure that embeds a struct device lead to a use-after-free? If a process holds an active reference to the embedded device by keeping a sysfs attribute open during unbind, devres will automatically free the memory when the remove function returns. When the process later closes the file, the device's release callback will operate on the already freed memory: ufs_rpmb_probe() { ... ufs_rpmb = devm_kzalloc(hba->dev, sizeof(*ufs_rpmb), GFP_KERNEL); ... ufs_rpmb->dev.release = ufs_rpmb_device_release; ... } Should this structure be allocated with a standard kzalloc and explicitly freed inside ufs_rpmb_device_release() to tie its lifetime to the device's reference count? > u8 dev_id[UFS_RPMB_ID_LEN]; > struct rpmb_dev *rdev; > char *cid = NULL; [ ... ] > @@ -215,8 +218,10 @@ int ufs_rpmb_probe(struct ufs_hba *hba) > goto err_out; > } > > - descr.dev_id = cid; > - descr.dev_id_len = strlen(cid); > + blake2b(NULL, 0, cid, strlen(cid), dev_id, UFS_RPMB_ID_LEN); > + > + descr.dev_id = dev_id; > + descr.dev_id_len = UFS_RPMB_ID_LEN; > descr.capacity = cap; > > /* Register RPMB device */ [Severity: High] This isn't a bug introduced by this patch, but is there a permanent resource leak here due to a circular reference? In ufs_rpmb_probe(), the child device is registered under the parent: ufs_rpmb_probe() { ... rdev = rpmb_dev_register(&ufs_rpmb->dev, &descr); ... } Registering the child takes a reference on the parent. During teardown, if only the parent is unregistered, the child still holds a reference, meaning the parent's refcount never reaches zero. As a result, the parent's release callback is never invoked: ufs_rpmb_device_release() { ... rpmb_dev_unregister(ufs_rpmb->rdev); } Since the child is only unregistered in the parent's release callback, both devices will be leaked permanently. Should the child be unregistered explicitly during the removal path before unregistering the parent? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260821150612.3944782-1-jorge.ramirez@oss.qualcomm.com?part=2 ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-08-21 15:24 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-21 15:06 [PATCH v3 0/2] ufs: rpmb: make RPMB usable with OP-TEE key derivation Jorge Ramirez-Ortiz 2026-08-21 15:06 ` [PATCH v3 1/2] ufs: rpmb: retry power-on UNIT ATTENTION on the RPMB WLUN Jorge Ramirez-Ortiz 2026-08-21 15:06 ` [PATCH v3 2/2] ufs: rpmb: use a fixed-length RPMB dev_id Jorge Ramirez-Ortiz 2026-08-21 15:24 ` sashiko-bot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox