FROMLIST: scsi: ufs: Fix memory corruption by ufshcd_read_desc_param()

Running the following commands on my test setup triggers stack corruption:

  cd /sys/devices/platform/14700000.ufs/host0/target0:0:0 &&
  for f in $(ls */unit_descriptor/hpb_pinned_region_start_offset | sort); do
    grep -aH . $f
  done

The above commands trigger stack corruption because these commands
assign the value 37 to the variable 'param_offset' and the value 35 to
'buff_len'. The following code changes param_size from 2 into 254 since
'param_size' has type u8:

        if (param_offset + param_size > buff_len)
                param_size = buff_len - param_offset;

The next statement triggers stack corruption since 'param_read_buf'
points at a two-byte stack array:

        memcpy(param_read_buf, &desc_buf[param_offset], param_size);

With this patch applied, the output of the above command on my test
setup is as follows:

0:0:0:0/unit_descriptor/hpb_pinned_region_start_offset:0x0000
0:0:0:1/unit_descriptor/hpb_pinned_region_start_offset:0x0000
0:0:0:2/unit_descriptor/hpb_pinned_region_start_offset:0x0000
0:0:0:3/unit_descriptor/hpb_pinned_region_start_offset:0x0000
grep: 0:0:0:49456/unit_descriptor/hpb_pinned_region_start_offset: Invalid argument
grep: 0:0:0:49476/unit_descriptor/hpb_pinned_region_start_offset: Invalid argument
grep: 0:0:0:49488/unit_descriptor/hpb_pinned_region_start_offset: Invalid argument

Link: https://lore.kernel.org/linux-scsi/20210719231127.869088-1-bvanassche@acm.org/T/#u
Bug: 194045295
Change-Id: I305c15b20f3ac3d6e3e97592566fcc51058195bb
Signed-off-by: Bart Van Assche <bvanassche@google.com>
This commit is contained in:
Bart Van Assche
2021-07-19 15:20:40 -07:00
parent 06e12b3d0a
commit 7f74a5165a

View File

@@ -3393,9 +3393,11 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
if (is_kmalloc) {
/* Make sure we don't copy more data than available */
if (param_offset + param_size > buff_len)
param_size = buff_len - param_offset;
memcpy(param_read_buf, &desc_buf[param_offset], param_size);
if (param_offset >= buff_len)
ret = -EINVAL;
else
memcpy(param_read_buf, &desc_buf[param_offset],
min_t(u32, param_size, buff_len - param_offset));
}
out:
if (is_kmalloc)