diff options
| author | Jens Axboe <axboe@suse.de> | 2003-12-16 16:12:29 -0800 |
|---|---|---|
| committer | Jens Axboe <axboe@suse.de> | 2003-12-16 16:12:29 -0800 |
| commit | f75da5af1c0b41783c8bb078d0ce7a03cc9be826 (patch) | |
| tree | b4c5ac457d69db469d740b5ff50141c06934ed3f | |
| parent | 314dc1544cc8f810bbe7afe5fcc61260d5ae46cb (diff) | |
[PATCH] CDROM_SEND_PACKET bug
I just found Yet Another Bug in scsi_ioctl - CDROM_SEND_PACKET puts a
kernel pointer in hdr->cmdp, where sg_io() expects to find user address.
This worked up until recently because of the memcpy bug, but now it
doesn't because we do the proper copy_from_user().
This fix undoes the user copy code from sg_io, and instead makes the
SG_IO ioctl copy it locally. This makes SG_IO and CDROM_SEND_PACKET
agree on the calling convention, and everybody is happy.
I've tested that both
cdrecord -dev=/dev/hdc -inq
and
cdrecord -dev=ATAPI:/dev/hdc -inq
works now. The former will use SG_IO, the latter CDROM_SEND_PACKET (and
incidentally would work in both 2.4 and 2.6, if it wasn't for
CDROM_SEND_PACKET sucking badly in 2.4).
| -rw-r--r-- | drivers/block/scsi_ioctl.c | 23 |
1 files changed, 15 insertions, 8 deletions
diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c index 098425adddf0..0c02c5ab3eeb 100644 --- a/drivers/block/scsi_ioctl.c +++ b/drivers/block/scsi_ioctl.c @@ -150,7 +150,6 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, struct request *rq; struct bio *bio; char sense[SCSI_SENSE_BUFFERSIZE]; - unsigned char cdb[BLK_MAX_CDB]; void *buffer; if (hdr->interface_id != 'S') @@ -167,9 +166,6 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, if (hdr->dxfer_len > (q->max_sectors << 9)) return -EIO; - if (copy_from_user(cdb, hdr->cmdp, hdr->cmd_len)) - return -EFAULT; - reading = writing = 0; buffer = NULL; bio = NULL; @@ -220,7 +216,7 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, * fill in request structure */ rq->cmd_len = hdr->cmd_len; - memcpy(rq->cmd, cdb, hdr->cmd_len); + memcpy(rq->cmd, hdr->cmdp, hdr->cmd_len); if (sizeof(rq->cmd) != hdr->cmd_len) memset(rq->cmd + hdr->cmd_len, 0, sizeof(rq->cmd) - hdr->cmd_len); @@ -436,12 +432,23 @@ int scsi_cmd_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long ar break; case SG_IO: { struct sg_io_hdr hdr; + unsigned char cdb[BLK_MAX_CDB], *old_cdb; - if (copy_from_user(&hdr, (struct sg_io_hdr *) arg, sizeof(hdr))) { - err = -EFAULT; + err = -EFAULT; + if (copy_from_user(&hdr, (struct sg_io_hdr *) arg, sizeof(hdr))) break; - } + err = -EINVAL; + if (hdr.cmd_len > sizeof(rq->cmd)) + break; + err = -EFAULT; + if (copy_from_user(cdb, hdr.cmdp, hdr.cmd_len)) + break; + + old_cdb = hdr.cmdp; + hdr.cmdp = cdb; err = sg_io(q, bdev, &hdr); + + hdr.cmdp = old_cdb; if (copy_to_user((struct sg_io_hdr *) arg, &hdr, sizeof(hdr))) err = -EFAULT; break; |
