diff options
author | Ishai Rabinovitz <ishai@mellanox.co.il> | 2006-06-29 16:39:54 +0300 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-06-30 21:28:35 -0500 |
commit | 454e8957eb60841016deb319dbbf83042fb32a39 (patch) | |
tree | 0b638af6bd2ac0083e244d228adfd12a8f6b4585 /drivers | |
parent | 0f13fc09db68de92585558984bff1c51b87db72f (diff) | |
download | linux-454e8957eb60841016deb319dbbf83042fb32a39.tar.gz linux-454e8957eb60841016deb319dbbf83042fb32a39.tar.bz2 linux-454e8957eb60841016deb319dbbf83042fb32a39.zip |
[SCSI] sg.c: Fix bad error handling in
I got a NULL derefrence in cdev_del+1 when called from sg_remove. By looking at
the code of sg_add, sg_alloc and sg_remove (all in drivers/scsi/sg.c) I found
out that sg_add is calling sg_alloc but if it fails afterwards it does not
deallocate the space that was allocated in sg_alloc and the redundant entry has
NULL in cdev. When sg_remove is being called, it tries to perform cdev_del to
this NULL cdev and fails.
Signed-off-by: Ishai Rabinovitz <ishai@mellanox.co.il>
Acked-by: Douglas Gilbert <dougg@torque.net>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/sg.c | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 98b9312ba8da..d5bbb97bb74b 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1402,6 +1402,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) Sg_device *sdp = NULL; struct cdev * cdev = NULL; int error, k; + unsigned long iflags; disk = alloc_disk(1); if (!disk) { @@ -1429,7 +1430,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1); if (error) - goto out; + goto cdev_add_err; sdp->cdev = cdev; if (sg_sysfs_valid) { @@ -1456,6 +1457,13 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) return 0; +cdev_add_err: + write_lock_irqsave(&sg_dev_arr_lock, iflags); + kfree(sg_dev_arr[k]); + sg_dev_arr[k] = NULL; + sg_nr_dev--; + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); + out: put_disk(disk); if (cdev) |