diff options
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r-- | drivers/scsi/scsi_scan.c | 18 |
1 files changed, 14 insertions, 4 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 148e24cc3222..aa1b1e0e9d22 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -700,12 +700,22 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, | |||
700 | * scanning run at their own risk, or supply a user level program | 700 | * scanning run at their own risk, or supply a user level program |
701 | * that can correctly scan. | 701 | * that can correctly scan. |
702 | */ | 702 | */ |
703 | sdev->inquiry = kmalloc(sdev->inquiry_len, GFP_ATOMIC); | 703 | |
704 | if (sdev->inquiry == NULL) { | 704 | /* |
705 | * Copy at least 36 bytes of INQUIRY data, so that we don't | ||
706 | * dereference unallocated memory when accessing the Vendor, | ||
707 | * Product, and Revision strings. Badly behaved devices may set | ||
708 | * the INQUIRY Additional Length byte to a small value, indicating | ||
709 | * these strings are invalid, but often they contain plausible data | ||
710 | * nonetheless. It doesn't matter if the device sent < 36 bytes | ||
711 | * total, since scsi_probe_lun() initializes inq_result with 0s. | ||
712 | */ | ||
713 | sdev->inquiry = kmemdup(inq_result, | ||
714 | max_t(size_t, sdev->inquiry_len, 36), | ||
715 | GFP_ATOMIC); | ||
716 | if (sdev->inquiry == NULL) | ||
705 | return SCSI_SCAN_NO_RESPONSE; | 717 | return SCSI_SCAN_NO_RESPONSE; |
706 | } | ||
707 | 718 | ||
708 | memcpy(sdev->inquiry, inq_result, sdev->inquiry_len); | ||
709 | sdev->vendor = (char *) (sdev->inquiry + 8); | 719 | sdev->vendor = (char *) (sdev->inquiry + 8); |
710 | sdev->model = (char *) (sdev->inquiry + 16); | 720 | sdev->model = (char *) (sdev->inquiry + 16); |
711 | sdev->rev = (char *) (sdev->inquiry + 32); | 721 | sdev->rev = (char *) (sdev->inquiry + 32); |