scsi: ufs: fix buffer overflow when access descriptor

The descriptor access function has a potential issue. It makes a
buffer overflow bug and trigger a kernel panic. Fix the boundary check
and return EINVAL when it has an invalid input.

log:
Kernel panic - not syncing: stack-protector: Kernel stack is corrupted
    in: ufs_sysfs_read_desc_param+0x1a4/0x1a4
Call trace:
 dump_backtrace+0x0/0x1a0
 dump_stack+0xbc/0xf8
 panic+0x150/0x2d4
 clear_warn_once_fops_open+0x0/0x30
 lun_write_protect_show+0x0/0x74

Bug: 153344835
Test: adb shell cat /sys/devices/platform/soc/1d84000.ufshc/*_descriptor*/*
Change-Id: Ie57cfacc6f7b32f68e1b54bb1cf059d60e6d17c6
Signed-off-by: Leo Liou <leoliou@google.com>
[dereference23: Apply to msm-4.14]
Signed-off-by: Alexander Winkowski <dereference23@outlook.com>
fourteen
Leo Liou 5 years ago committed by Jenna
parent e1e659c34b
commit 219229e831
  1. 28
      drivers/scsi/ufs/ufshcd.c

@ -5107,7 +5107,6 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba,
int ret;
u8 *desc_buf;
int buff_len;
bool is_kmalloc = true;
/* Safety check */
if (desc_id >= QUERY_DESC_IDN_MAX || !param_size)
@ -5125,16 +5124,17 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba,
return ret;
}
/* Check whether we need temp memory */
if (param_offset != 0 || param_size < buff_len) {
desc_buf = kmalloc(buff_len, GFP_KERNEL);
if (!desc_buf)
return -ENOMEM;
} else {
desc_buf = param_read_buf;
is_kmalloc = false;
/* Boundary check */
if (param_size == 0 || (param_offset + param_size) > buff_len) {
dev_err(hba->dev, "%s: Out of desc boundary or null size",
__func__);
return -EINVAL;
}
desc_buf = kmalloc(buff_len, GFP_KERNEL);
if (!desc_buf)
return -ENOMEM;
/* Request for full descriptor */
ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC,
desc_id, desc_index, 0,
@ -5154,15 +5154,9 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba,
goto out;
}
/* Check wherher we will not copy more data, than available */
if (is_kmalloc && param_offset + param_size > buff_len)
param_size = buff_len - param_offset;
if (is_kmalloc)
memcpy(param_read_buf, &desc_buf[param_offset], param_size);
memcpy(param_read_buf, &desc_buf[param_offset], param_size);
out:
if (is_kmalloc)
kfree(desc_buf);
kfree(desc_buf);
return ret;
}

Loading…
Cancel
Save