mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 20:54:03 +02:00
Merge patch series "scsi: ufs: Fix descriptor parsing and invalid input handling"
Li Qiang <liqiang01@kylinos.cn> says: The first patch validates string descriptor payload sizes and avoids raw descriptor overreads. The remaining patches protect invalid completion diagnostics, validate connected lane counts, validate RPMB frame sizes, use unaligned RPMB frame accesses, and retain a NUL terminator for debugfs input. Link: https://patch.msgid.link/20260717153914.26321-1-liqiang01@kylinos.cn Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
commit
b854c2e6b9
|
|
@ -165,7 +165,7 @@ static ssize_t ufs_saved_err_write(struct file *file, const char __user *buf,
|
|||
char val_str[16] = { };
|
||||
int val, ret;
|
||||
|
||||
if (count > sizeof(val_str))
|
||||
if (count >= sizeof(val_str))
|
||||
return -EINVAL;
|
||||
if (copy_from_user(val_str, buf, count))
|
||||
return -EFAULT;
|
||||
|
|
|
|||
|
|
@ -69,7 +69,11 @@ static int ufs_rpmb_route_frames(struct device *dev, u8 *req, unsigned int req_l
|
|||
|
||||
hba = ufs_rpmb->hba;
|
||||
|
||||
req_type = be16_to_cpu(frm_out->req_resp);
|
||||
/* req_resp is at the end of an RPMB frame. */
|
||||
if (req_len < sizeof(*frm_out))
|
||||
return -EINVAL;
|
||||
|
||||
req_type = get_unaligned_be16(&frm_out->req_resp);
|
||||
|
||||
switch (req_type) {
|
||||
case RPMB_PROGRAM_KEY:
|
||||
|
|
@ -107,7 +111,7 @@ static int ufs_rpmb_route_frames(struct device *dev, u8 *req, unsigned int req_l
|
|||
struct rpmb_frame *frm_resp = (struct rpmb_frame *)resp;
|
||||
|
||||
memset(frm_resp, 0, sizeof(*frm_resp));
|
||||
frm_resp->req_resp = cpu_to_be16(RPMB_RESULT_READ);
|
||||
put_unaligned_be16(RPMB_RESULT_READ, &frm_resp->req_resp);
|
||||
ret = ufs_sec_submit(hba, protocol_id, resp, resp_len, true);
|
||||
if (ret) {
|
||||
dev_err(dev, "Result read request failed with ret=%d\n", ret);
|
||||
|
|
|
|||
|
|
@ -3868,7 +3868,7 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, u8 **buf, enum u
|
|||
{
|
||||
struct uc_string_id *uc_str;
|
||||
u8 *str;
|
||||
int ret;
|
||||
int ret, uc_len;
|
||||
|
||||
if (!buf)
|
||||
return -EINVAL;
|
||||
|
|
@ -3893,11 +3893,19 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, u8 **buf, enum u
|
|||
goto out;
|
||||
}
|
||||
|
||||
uc_len = uc_str->len - QUERY_DESC_HDR_SIZE;
|
||||
if (uc_len % sizeof(*uc_str->uc)) {
|
||||
dev_err(hba->dev, "String Desc has an odd UTF-16 payload length\n");
|
||||
str = NULL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fmt == SD_ASCII_STD) {
|
||||
ssize_t ascii_len;
|
||||
int i;
|
||||
/* remove header and divide by 2 to move from UTF16 to UTF8 */
|
||||
ascii_len = (uc_str->len - QUERY_DESC_HDR_SIZE) / 2 + 1;
|
||||
/* Allow up to three UTF-8 bytes per UTF-16 code unit plus a NUL. */
|
||||
ascii_len = uc_len / sizeof(*uc_str->uc) * 3 + 1;
|
||||
str = kzalloc(ascii_len, GFP_KERNEL);
|
||||
if (!str) {
|
||||
ret = -ENOMEM;
|
||||
|
|
@ -3909,7 +3917,7 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, u8 **buf, enum u
|
|||
* we need to convert to utf-8 so it can be displayed
|
||||
*/
|
||||
ret = utf16s_to_utf8s(uc_str->uc,
|
||||
uc_str->len - QUERY_DESC_HDR_SIZE,
|
||||
uc_len / sizeof(*uc_str->uc),
|
||||
UTF16_BIG_ENDIAN, str, ascii_len - 1);
|
||||
|
||||
/* replace non-printable or non-ASCII characters with spaces */
|
||||
|
|
@ -3919,11 +3927,17 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, u8 **buf, enum u
|
|||
str[ret++] = '\0';
|
||||
|
||||
} else {
|
||||
str = kmemdup(uc_str->uc, uc_str->len, GFP_KERNEL);
|
||||
/*
|
||||
* Keep the bLength-sized raw output for the RPMB device ID ABI.
|
||||
* The two bytes beyond the UTF-16 payload are explicitly zeroed
|
||||
* instead of being read past the descriptor buffer.
|
||||
*/
|
||||
str = kzalloc(uc_str->len, GFP_KERNEL);
|
||||
if (!str) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
memcpy(str, uc_str->uc, uc_len);
|
||||
ret = uc_str->len;
|
||||
}
|
||||
out:
|
||||
|
|
@ -4718,7 +4732,9 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
|
|||
ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
|
||||
&pwr_info->lane_tx);
|
||||
|
||||
if (!pwr_info->lane_rx || !pwr_info->lane_tx) {
|
||||
if (!pwr_info->lane_rx || !pwr_info->lane_tx ||
|
||||
pwr_info->lane_rx > UFS_MAX_LANES ||
|
||||
pwr_info->lane_tx > UFS_MAX_LANES) {
|
||||
dev_err(hba->dev, "%s: invalid connected lanes value. rx=%d, tx=%d\n",
|
||||
__func__,
|
||||
pwr_info->lane_rx,
|
||||
|
|
@ -5849,8 +5865,8 @@ void ufshcd_compl_one_cqe(struct ufs_hba *hba, int task_tag,
|
|||
struct ufshcd_lrb *lrbp = scsi_cmd_priv(cmd);
|
||||
enum utp_ocs ocs;
|
||||
|
||||
if (WARN_ONCE(!cmd, "cqe->command_desc_base_addr = %#llx\n",
|
||||
le64_to_cpu(cqe->command_desc_base_addr)))
|
||||
if (WARN_ONCE(!cmd, "invalid completion tag %d, cqe->command_desc_base_addr = %#llx\n",
|
||||
task_tag, cqe ? le64_to_cpu(cqe->command_desc_base_addr) : 0ULL))
|
||||
return;
|
||||
|
||||
if (hba->monitor.enabled) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user