diff mbox series

[v1] scsi: ufs: scsi_get_lba error fix by check cmd opcode

Message ID 20220307111752.10465-1-peter.wang@mediatek.com
State New
Headers show
Series [v1] scsi: ufs: scsi_get_lba error fix by check cmd opcode | expand

Commit Message

Peter Wang March 7, 2022, 11:17 a.m. UTC
From: Peter Wang <peter.wang@mediatek.com>

When ufs init without scmd->device->sector_size set,
scsi_get_lba will get a wrong shift number and ubsan error.
shift exponent 4294967286 is too large for 64-bit type
'sector_t' (aka 'unsigned long long')
Call scsi_get_lba only when opcode is READ_10/WRITE_10/UNMAP.

Signed-off-by: Peter Wang <peter.wang@mediatek.com>
---
 drivers/scsi/ufs/ufshcd.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

Comments

Peter Wang March 8, 2022, 11:24 a.m. UTC | #1
Hi Bart,


When scsi scan in scsi_probe_lun function, there have much INQUIRY(0x12) 
command
with sector_size is 0.
unsigned int shift will get 4294967286 (signed -10) and an sector_t type 
is 64 bit.
Shift 64bit right 4294967286 will have ubsan error because ubsan think
shift number should be wrong and return 0 always.
BTW, we only need the lba information when read/write/unmap. Other 
command such
as INQUIRY is useless.

static inline sector_t scsi_get_lba(struct scsi_cmnd *scmd)
{
     unsigned int shift = ilog2(scmd->device->sector_size) - 
SECTOR_SHIFT; <=  shift is 4294967286 (-1-9=-10)

     return blk_rq_pos(scsi_cmd_to_rq(scmd)) >> shift;  <= sector_t type 
 >> 4294967286 will always get 0.
}


On 3/8/22 1:52 AM, Bart Van Assche wrote:
>
> Hmm ... how can it happen that sector_size has not been set? I think 
> that can only happen for LUNs of type SCSI DISK if sd_read_capacity() 
> fails? If sd_read_capacity() fails I think the sd driver is expected 
> to set the capacity to zero?
>
> rq->__sector == -1 for flush requests and the type of that member 
> (sector_t) is unsigned. I think that it is allowed for a shift left of 
> an unsigned type to overflow. From the C standard: "The result of E1 
> << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with
> zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2 
> , reduced modulo one more than the maximum value representable in the 
> result type."
>
> Thanks,
>
> Bart.
Bart Van Assche March 8, 2022, 10:11 p.m. UTC | #2
On 3/7/22 03:17, peter.wang@mediatek.com wrote:
> When ufs init without scmd->device->sector_size set,
> scsi_get_lba will get a wrong shift number and ubsan error.
> shift exponent 4294967286 is too large for 64-bit type
> 'sector_t' (aka 'unsigned long long')
> Call scsi_get_lba only when opcode is READ_10/WRITE_10/UNMAP.

Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Martin K. Petersen March 9, 2022, 3:52 a.m. UTC | #3
> When ufs init without scmd->device->sector_size set, scsi_get_lba will
> get a wrong shift number and ubsan error.  shift exponent 4294967286
> is too large for 64-bit type 'sector_t' (aka 'unsigned long long')
> Call scsi_get_lba only when opcode is READ_10/WRITE_10/UNMAP.

Applied to 5.18/scsi-staging, thanks!
Martin K. Petersen March 15, 2022, 5:02 a.m. UTC | #4
On Mon, 7 Mar 2022 19:17:52 +0800, peter.wang@mediatek.com wrote:

> From: Peter Wang <peter.wang@mediatek.com>
> 
> When ufs init without scmd->device->sector_size set,
> scsi_get_lba will get a wrong shift number and ubsan error.
> shift exponent 4294967286 is too large for 64-bit type
> 'sector_t' (aka 'unsigned long long')
> Call scsi_get_lba only when opcode is READ_10/WRITE_10/UNMAP.
> 
> [...]

Applied to 5.18/scsi-queue, thanks!

[1/1] scsi: ufs: scsi_get_lba error fix by check cmd opcode
      https://git.kernel.org/mkp/scsi/c/2bd3b6b75946
diff mbox series

Patch

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9349557b8a01..3c4caee8fb93 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -367,7 +367,7 @@  static void ufshcd_add_uic_command_trace(struct ufs_hba *hba,
 static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag,
 				     enum ufs_trace_str_t str_t)
 {
-	u64 lba;
+	u64 lba = 0;
 	u8 opcode = 0, group_id = 0;
 	u32 intr, doorbell;
 	struct ufshcd_lrb *lrbp = &hba->lrb[tag];
@@ -384,7 +384,6 @@  static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag,
 		return;
 
 	opcode = cmd->cmnd[0];
-	lba = scsi_get_lba(cmd);
 
 	if (opcode == READ_10 || opcode == WRITE_10) {
 		/*
@@ -392,6 +391,7 @@  static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag,
 		 */
 		transfer_len =
 		       be32_to_cpu(lrbp->ucd_req_ptr->sc.exp_data_transfer_len);
+		lba = scsi_get_lba(cmd);
 		if (opcode == WRITE_10)
 			group_id = lrbp->cmd->cmnd[6];
 	} else if (opcode == UNMAP) {
@@ -399,6 +399,7 @@  static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag,
 		 * The number of Bytes to be unmapped beginning with the lba.
 		 */
 		transfer_len = blk_rq_bytes(rq);
+		lba = scsi_get_lba(cmd);
 	}
 
 	intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS);