Merge patch series "scsi: ufs: Fix UIC result byte and BSG request handling"

Stanley Jhu <stanleyjhu@google.com> says:

ufs-bsg fixes for issues found by fuzzing /dev/bsg/ufs-bsg* with
syzkaller on QEMU's emulated UFS host controller and in review of v1,
plus a fix for peer DME retries.

Patch 1 completes failed BSG requests via bsg_job_done() so error paths
do not leak the job's device reference and mapped scatterlists.
Patch 2 clears the reused reply buffer so replies do not carry bytes
from an earlier request.
Patch 3 rejects requests shorter than the UFS BSG request structures.
Patch 4 rejects UIC commands with a non-zero result byte from userspace.
Patch 5 clears the stale UIC result byte and restores argument3 before
peer DME retries.

Patches 1-2 also address the sashiko review of the bsg reply_len patch:
https://lore.kernel.org/all/sashiko-outbox-169843@kernel.org/

Tested on QEMU arm64: the reproducers no longer trigger.

Link: https://patch.msgid.link/20261015001855.3450573-1-stanleyjhu@google.com
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
Martin K. Petersen (Oracle) 2026-10-23 22:36:54 -04:00
commit 1b39bd7b82
2 changed files with 24 additions and 8 deletions

View File

@ -73,6 +73,9 @@ static int ufs_bsg_exec_advanced_rpmb_req(struct ufs_hba *hba, struct bsg_job *j
if (hba->ufs_version < ufshci_version(4, 0) || !hba->dev_info.b_advanced_rpmb_en)
return -EINVAL;
if (job->request_len < sizeof(*rpmb_request))
return -EINVAL;
if (rpmb_request->ehs_req.length != 2 || rpmb_request->ehs_req.ehs_type != 1)
return -EINVAL;
@ -140,7 +143,12 @@ static int ufs_bsg_request(struct bsg_job *job)
int ret;
bool rpmb = false;
bsg_reply->reply_payload_rcv_len = 0;
memset(job->reply, 0, job->reply_len);
if (job->request_len < sizeof(*bsg_request)) {
ret = -EINVAL;
goto out_complete;
}
ufshcd_rpm_get_sync(hba);
@ -171,6 +179,10 @@ static int ufs_bsg_request(struct bsg_job *job)
break;
case UPIU_TRANSACTION_UIC_CMD:
memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE);
if (uc.argument2 & MASK_UIC_COMMAND_RESULT) {
ret = -EINVAL;
break;
}
ret = ufshcd_send_bsg_uic_cmd(hba, &uc);
if (ret)
dev_err(hba->dev, "send uic cmd: error code %d\n", ret);
@ -194,15 +206,14 @@ static int ufs_bsg_request(struct bsg_job *job)
out:
ufshcd_rpm_put_sync(hba);
kfree(buff);
out_complete:
bsg_reply->result = ret;
/* complete the job here only if no error */
if (ret == 0) {
if (ret == 0)
job->reply_len = rpmb ? sizeof(struct ufs_rpmb_reply) :
sizeof(struct ufs_bsg_reply);
bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len);
}
bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len);
return ret;
return 0;
}
/**

View File

@ -4400,9 +4400,12 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
do {
/* for peer attributes we retry upon failure */
ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
if (ret)
if (ret) {
dev_dbg(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n",
set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret);
uic_cmd.argument2 &= ~MASK_UIC_COMMAND_RESULT;
uic_cmd.argument3 = mib_val;
}
} while (ret && peer && --retries);
if (ret)
@ -4467,9 +4470,11 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
do {
/* for peer attributes we retry upon failure */
ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
if (ret)
if (ret) {
dev_dbg(hba->dev, "%s: attr-id 0x%x error code %d\n",
get, UIC_GET_ATTR_ID(attr_sel), ret);
uic_cmd.argument2 &= ~MASK_UIC_COMMAND_RESULT;
}
} while (ret && peer && --retries);
if (ret)