patch-1.3.9 linux/drivers/scsi/scsi_ioctl.c
Next file: linux/drivers/scsi/scsi_proc.c
Previous file: linux/drivers/scsi/scsi_debug.c
Back to the patch index
Back to the overall index
- Lines: 176
- Date:
Tue Jul 11 07:56:04 1995
- Orig file:
v1.3.8/linux/drivers/scsi/scsi_ioctl.c
- Orig date:
Fri Jul 7 08:54:50 1995
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
@@ -42,11 +42,14 @@
static int ioctl_probe(struct Scsi_Host * host, void *buffer)
{
- int temp;
+ int temp, result;
unsigned int len,slen;
const char * string;
if ((temp = host->hostt->present) && buffer) {
+ result = verify_area(VERIFY_READ, buffer, sizeof(long));
+ if (result) return result;
+
len = get_user ((unsigned int *) buffer);
if(host->hostt->info)
string = host->hostt->info(host);
@@ -56,7 +59,9 @@
slen = strlen(string);
if (len > slen)
len = slen + 1;
- verify_area(VERIFY_WRITE, buffer, len);
+ result = verify_area(VERIFY_WRITE, buffer, len);
+ if (result) return result;
+
memcpy_tofs (buffer, string, len);
}
}
@@ -139,7 +144,7 @@
break;
};
default: /* Fall through for non-removable media */
- printk("SCSI CD error: host %d id %d lun %d return code = %x\n",
+ printk("SCSI error: host %d id %d lun %d return code = %x\n",
dev->host->host_no,
dev->id,
dev->lun,
@@ -157,6 +162,11 @@
return result;
}
+/*
+ * This interface is depreciated - users should use the scsi generics
+ * interface instead, as this is a more flexible approach to performing
+ * generic SCSI commands on a device.
+ */
static int ioctl_command(Scsi_Device *dev, void *buffer)
{
char * buf;
@@ -171,11 +181,35 @@
if (!buffer)
return -EINVAL;
- inlen = get_user((unsigned int *) buffer);
- outlen = get_user( ((unsigned int *) buffer) + 1);
-
- cmd_in = (char *) ( ((int *)buffer) + 2);
- opcode = get_user(cmd_in);
+
+ /*
+ * Verify that we can read at least this much.
+ */
+ result = verify_area(VERIFY_READ, buffer, 2*sizeof(long) + 1);
+ if (result) return result;
+
+ /*
+ * The structure that we are passed should look like:
+ *
+ * struct sdata{
+ * int inlen;
+ * int outlen;
+ * char cmd[]; # However many bytes are used for cmd.
+ * char data[];
+ */
+ inlen = get_user((unsigned int *) buffer);
+ outlen = get_user( ((unsigned int *) buffer) + 1);
+
+ /*
+ * We do not transfer more than MAX_BUF with this interface.
+ * If the user needs to transfer more data than this, they
+ * should use scsi_generics instead.
+ */
+ if( inlen > MAX_BUF ) inlen = MAX_BUF;
+ if( outlen > MAX_BUF ) outlen = MAX_BUF;
+
+ cmd_in = (char *) ( ((int *)buffer) + 2);
+ opcode = get_user(cmd_in);
needed = buf_needed = (inlen > outlen ? inlen : outlen);
if(buf_needed){
@@ -187,9 +221,27 @@
} else
buf = NULL;
- memcpy_fromfs ((void *) cmd, cmd_in, cmdlen = COMMAND_SIZE (opcode));
- memcpy_fromfs ((void *) buf, (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen);
+ /*
+ * Obtain the command from the user's address space.
+ */
+ cmdlen = COMMAND_SIZE(opcode);
+
+ result = verify_area(VERIFY_READ, cmd_in,
+ cmdlen + inlen > MAX_BUF ? MAX_BUF : inlen);
+ if (result) return result;
+
+ memcpy_fromfs ((void *) cmd, cmd_in, cmdlen);
+ /*
+ * Obtain the data to be sent to the device (if any).
+ */
+ memcpy_fromfs ((void *) buf,
+ (void *) (cmd_in + cmdlen),
+ inlen);
+
+ /*
+ * Set the lun field to the correct value.
+ */
cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
#ifndef DEBUG_NO_CMD
@@ -205,22 +257,25 @@
down(&sem);
/* Hmm.. Have to ask about this one */
while (SCpnt->request.dev != 0xfffe) schedule();
- };
+ }
- /* If there was an error condition, pass the info back to the user. */
+ /*
+ * If there was an error condition, pass the info back to the user.
+ */
if(SCpnt->result) {
- result = verify_area(VERIFY_WRITE, cmd_in, sizeof(SCpnt->sense_buffer));
- if (result)
- return result;
- memcpy_tofs((void *) cmd_in, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
+ result = verify_area(VERIFY_WRITE,
+ cmd_in,
+ sizeof(SCpnt->sense_buffer));
+ if (result) return result;
+ memcpy_tofs((void *) cmd_in,
+ SCpnt->sense_buffer,
+ sizeof(SCpnt->sense_buffer));
} else {
-
- result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF : outlen);
- if (result)
- return result;
- memcpy_tofs ((void *) cmd_in, buf, (outlen > MAX_BUF) ? MAX_BUF : outlen);
- };
+ result = verify_area(VERIFY_WRITE, cmd_in, outlen);
+ if (result) return result;
+ memcpy_tofs ((void *) cmd_in, buf, outlen);
+ }
result = SCpnt->result;
SCpnt->request.dev = -1; /* Mark as not busy */
if (buf) scsi_free(buf, buf_needed);
@@ -255,6 +310,7 @@
*/
int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
{
+ int result;
char scsi_cmd[12];
/* No idea how this happens.... */
@@ -262,7 +318,9 @@
switch (cmd) {
case SCSI_IOCTL_GET_IDLUN:
- verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
+ result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
+ if (result) return result;
+
put_user(dev->id + (dev->lun << 8) + (dev->host->host_no << 16) +
/* This has been added to support
* multichannel HBAs, it might cause
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this