Commit 5f99bd9a authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Christoph Hellwig

[PATCH] fix possible NULL pointer dereference in scsi_scan.c

If the sdev allocation fails and q is non-null we could dereference
sdev->request_queue.  While at it reformat the function to use
goto-based cleanup - that's much easier to parse.
parent 306fda03
...@@ -385,8 +385,10 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -385,8 +385,10 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
struct scsi_device *sdev, *device; struct scsi_device *sdev, *device;
sdev = kmalloc(sizeof(*sdev), GFP_ATOMIC); sdev = kmalloc(sizeof(*sdev), GFP_ATOMIC);
if (sdev != NULL) { if (!sdev)
memset(sdev, 0, sizeof(Scsi_Device)); goto out;
memset(sdev, 0, sizeof(*sdev));
sdev->vendor = scsi_null_device_strs; sdev->vendor = scsi_null_device_strs;
sdev->model = scsi_null_device_strs; sdev->model = scsi_null_device_strs;
sdev->rev = scsi_null_device_strs; sdev->rev = scsi_null_device_strs;
...@@ -399,10 +401,12 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -399,10 +401,12 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
INIT_LIST_HEAD(&sdev->same_target_siblings); INIT_LIST_HEAD(&sdev->same_target_siblings);
INIT_LIST_HEAD(&sdev->cmd_list); INIT_LIST_HEAD(&sdev->cmd_list);
spin_lock_init(&sdev->list_lock); spin_lock_init(&sdev->list_lock);
/* /*
* Some low level driver could use device->type * Some low level driver could use device->type
*/ */
sdev->type = -1; sdev->type = -1;
/* /*
* Assume that the device will have handshaking problems, * Assume that the device will have handshaking problems,
* and then fix this field later if it turns out it * and then fix this field later if it turns out it
...@@ -413,7 +417,7 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -413,7 +417,7 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
if (!q || *q == NULL) { if (!q || *q == NULL) {
sdev->request_queue = scsi_alloc_queue(shost); sdev->request_queue = scsi_alloc_queue(shost);
if (!sdev->request_queue) if (!sdev->request_queue)
goto out_bail; goto out_free_dev;
} else { } else {
sdev->request_queue = *q; sdev->request_queue = *q;
*q = NULL; *q = NULL;
...@@ -423,16 +427,17 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -423,16 +427,17 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
init_waitqueue_head(&sdev->scpnt_wait); init_waitqueue_head(&sdev->scpnt_wait);
if (shost->hostt->slave_alloc) if (shost->hostt->slave_alloc) {
if (shost->hostt->slave_alloc(sdev)) { if (shost->hostt->slave_alloc(sdev))
goto out_bail; goto out_free_queue;
} }
/* /*
* If there are any same target siblings, add this to the * If there are any same target siblings, add this to the
* sibling list * sibling list
*/ */
list_for_each_entry(device, &shost->my_devices, siblings) { list_for_each_entry(device, &shost->my_devices, siblings) {
if(device->id == sdev->id && if (device->id == sdev->id &&
device->channel == sdev->channel) { device->channel == sdev->channel) {
list_add_tail(&sdev->same_target_siblings, list_add_tail(&sdev->same_target_siblings,
&device->same_target_siblings); &device->same_target_siblings);
...@@ -440,28 +445,32 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -440,28 +445,32 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
break; break;
} }
} }
/* /*
* If there wasn't another lun already configured at this * If there wasn't another lun already configured at this
* target, then default this device to SCSI_2 until we * target, then default this device to SCSI_2 until we
* know better * know better
*/ */
if(!sdev->scsi_level) if (!sdev->scsi_level)
sdev->scsi_level = SCSI_2; sdev->scsi_level = SCSI_2;
/* /*
* Add it to the end of the shost->my_devices list. * Add it to the end of the shost->my_devices list.
*/ */
list_add_tail(&sdev->siblings, &shost->my_devices); list_add_tail(&sdev->siblings, &shost->my_devices);
return (sdev); return sdev;
}
out_bail: out_free_queue:
printk(ALLOC_FAILURE_MSG, __FUNCTION__);
if (q && sdev->request_queue) { if (q && sdev->request_queue) {
*q = sdev->request_queue; *q = sdev->request_queue;
sdev->request_queue = NULL; sdev->request_queue = NULL;
} else if (sdev->request_queue) } else if (sdev->request_queue)
scsi_free_queue(sdev->request_queue); scsi_free_queue(sdev->request_queue);
out_free_dev:
kfree(sdev); kfree(sdev);
out:
printk(ALLOC_FAILURE_MSG, __FUNCTION__);
return NULL; return NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment