Skip to content

Commit e17d634

Browse files
scsi: core: Pick suitable allocation length in scsi_report_opcode()
Some devices hang when a buffer size larger than expected is passed in the ALLOCATION LENGTH field. For REPORT SUPPORTED OPERATION CODES we currently only request a single command descriptor at a time and therefore the actual size of the command is known ahead of time. Limit the ALLOCATION LENGTH to the header size plus the command length of the opcode we are asking about. Link: https://lore.kernel.org/r/20220302053559.32147-5-martin.petersen@oracle.com Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Reviewed-by: Bart Van Assche <bvanassche@acm.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent c92a6b5 commit e17d634

File tree

1 file changed

+13
-4
lines changed

1 file changed

+13
-4
lines changed

drivers/scsi/scsi.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -503,21 +503,30 @@ int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
503503
{
504504
unsigned char cmd[16];
505505
struct scsi_sense_hdr sshdr;
506-
int result;
506+
int result, request_len;
507507

508508
if (sdev->no_report_opcodes || sdev->scsi_level < SCSI_SPC_3)
509509
return -EINVAL;
510510

511+
/* RSOC header + size of command we are asking about */
512+
request_len = 4 + COMMAND_SIZE(opcode);
513+
if (request_len > len) {
514+
dev_warn_once(&sdev->sdev_gendev,
515+
"%s: len %u bytes, opcode 0x%02x needs %u\n",
516+
__func__, len, opcode, request_len);
517+
return -EINVAL;
518+
}
519+
511520
memset(cmd, 0, 16);
512521
cmd[0] = MAINTENANCE_IN;
513522
cmd[1] = MI_REPORT_SUPPORTED_OPERATION_CODES;
514523
cmd[2] = 1; /* One command format */
515524
cmd[3] = opcode;
516-
put_unaligned_be32(len, &cmd[6]);
525+
put_unaligned_be32(request_len, &cmd[6]);
517526
memset(buffer, 0, len);
518527

519-
result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
520-
&sshdr, 30 * HZ, 3, NULL);
528+
result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer,
529+
request_len, &sshdr, 30 * HZ, 3, NULL);
521530

522531
if (result < 0)
523532
return result;

0 commit comments

Comments
 (0)