From 7f74a5165a3229802c88f08c7dce14de6a14e794 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 19 Jul 2021 15:20:40 -0700 Subject: [PATCH] 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 --- drivers/scsi/ufs/ufshcd.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 16eefa61f574..a25cdf46a18a 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -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)