Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / sbus / char / openprom.c
index c140f63..239e108 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/miscdevice.h>
+#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <asm/oplib.h>
@@ -67,7 +68,7 @@ static int options_node = 0;
  * structure will be placed in "*opp_p". Return value is the length
  * of the user supplied buffer.
  */
-static int copyin(struct openpromio *info, struct openpromio **opp_p)
+static int copyin(struct openpromio __user *info, struct openpromio **opp_p)
 {
        unsigned int bufsize;
 
@@ -98,7 +99,7 @@ static int copyin(struct openpromio *info, struct openpromio **opp_p)
        return bufsize;
 }
 
-static int getstrings(struct openpromio *info, struct openpromio **opp_p)
+static int getstrings(struct openpromio __user *info, struct openpromio **opp_p)
 {
        int n, bufsize;
        char c;
@@ -132,7 +133,7 @@ static int getstrings(struct openpromio *info, struct openpromio **opp_p)
 /*
  * Copy an openpromio structure in kernel space back to user space.
  */
-static int copyout(void *info, struct openpromio *opp, int len)
+static int copyout(void __user *info, struct openpromio *opp, int len)
 {
        if (copy_to_user(info, opp, len))
                return -EFAULT;
@@ -149,13 +150,13 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
        char buffer[OPROMMAXPARAM+1], *buf;
        struct openpromio *opp;
        int bufsize, len, error = 0;
-       extern char saved_command_line[];
        static int cnt;
+       void __user *argp = (void __user *)arg;
 
        if (cmd == OPROMSETOPT)
-               bufsize = getstrings((void *)arg, &opp);
+               bufsize = getstrings(argp, &opp);
        else
-               bufsize = copyin((void *)arg, &opp);
+               bufsize = copyin(argp, &opp);
 
        if (bufsize < 0)
                return bufsize;
@@ -166,7 +167,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
                len = prom_getproplen(node, opp->oprom_array);
 
                if (len <= 0 || len > bufsize) {
-                       error = copyout((void *)arg, opp, sizeof(int));
+                       error = copyout(argp, opp, sizeof(int));
                        break;
                }
 
@@ -176,7 +177,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
                opp->oprom_array[len] = '\0';
                opp->oprom_size = len;
 
-               error = copyout((void *)arg, opp, sizeof(int) + bufsize);
+               error = copyout(argp, opp, sizeof(int) + bufsize);
                break;
 
        case OPROMNXTOPT:
@@ -185,7 +186,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
 
                len = strlen(buf);
                if (len == 0 || len + 1 > bufsize) {
-                       error = copyout((void *)arg, opp, sizeof(int));
+                       error = copyout(argp, opp, sizeof(int));
                        break;
                }
 
@@ -193,7 +194,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
                opp->oprom_array[len] = '\0';
                opp->oprom_size = ++len;
 
-               error = copyout((void *)arg, opp, sizeof(int) + bufsize);
+               error = copyout(argp, opp, sizeof(int) + bufsize);
                break;
 
        case OPROMSETOPT:
@@ -228,7 +229,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
                *((int *)opp->oprom_array) = node;
                opp->oprom_size = sizeof(int);
 
-               error = copyout((void *)arg, opp, bufsize + sizeof(int));
+               error = copyout(argp, opp, bufsize + sizeof(int));
                break;
 
        case OPROMPCI2NODE:
@@ -247,7 +248,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
                                data->current_node = node;
                                *((int *)opp->oprom_array) = node;
                                opp->oprom_size = sizeof(int);
-                               error = copyout((void *)arg, opp, bufsize + sizeof(int));
+                               error = copyout(argp, opp, bufsize + sizeof(int));
                        }
 #endif
                }
@@ -259,7 +260,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
                *((int *)opp->oprom_array) = node;
                opp->oprom_size = sizeof(int);
 
-               error = copyout((void *)arg, opp, bufsize + sizeof(int));
+               error = copyout(argp, opp, bufsize + sizeof(int));
                break;
 
        case OPROMGETBOOTARGS:
@@ -275,7 +276,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
                strcpy(opp->oprom_array, buf);
                opp->oprom_size = len;
 
-               error = copyout((void *)arg, opp, bufsize + sizeof(int));
+               error = copyout(argp, opp, bufsize + sizeof(int));
                break;
 
        case OPROMU2P:
@@ -318,7 +319,7 @@ static int goodnode(int n, DATA *data)
 }
 
 /* Copy in a whole string from userspace into kernelspace. */
-static int copyin_string(char *user, size_t len, char **ptr)
+static int copyin_string(char __user *user, size_t len, char **ptr)
 {
        char *tmp;
 
@@ -348,6 +349,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
                              unsigned int cmd, unsigned long arg)
 {
        DATA *data = (DATA *) file->private_data;
+       void __user *argp = (void __user *)arg;
        struct opiocdesc op;
        int error, node, len;
        char *str, *tmp;
@@ -356,7 +358,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
 
        switch (cmd) {
        case OPIOCGET:
-               if (copy_from_user(&op, (void *)arg, sizeof(op)))
+               if (copy_from_user(&op, argp, sizeof(op)))
                        return -EFAULT;
 
                if (!goodnode(op.op_nodeid,data))
@@ -378,7 +380,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
                if (len <= 0) {
                        kfree(str);
                        /* Verified by the above copy_from_user */
-                       if (__copy_to_user((void *)arg, &op,
+                       if (__copy_to_user(argp, &op,
                                       sizeof(op)))
                                return -EFAULT;
                        return 0;
@@ -390,13 +392,16 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
                        return -ENOMEM;
                }
 
-               prom_getproperty(op.op_nodeid, str, tmp, len);
-
-               tmp[len] = '\0';
+               cnt = prom_getproperty(op.op_nodeid, str, tmp, len);
+               if (cnt <= 0) {
+                       error = -EINVAL;
+               } else {
+                       tmp[len] = '\0';
 
-               if (__copy_to_user((void *)arg, &op, sizeof(op)) != 0
-                   || copy_to_user(op.op_buf, tmp, len) != 0)
-                       error = -EFAULT;
+                       if (__copy_to_user(argp, &op, sizeof(op)) != 0 ||
+                           copy_to_user(op.op_buf, tmp, len) != 0)
+                               error = -EFAULT;
+               }
 
                kfree(tmp);
                kfree(str);
@@ -404,7 +409,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
                return error;
 
        case OPIOCNEXTPROP:
-               if (copy_from_user(&op, (void *)arg, sizeof(op)))
+               if (copy_from_user(&op, argp, sizeof(op)))
                        return -EFAULT;
 
                if (!goodnode(op.op_nodeid,data))
@@ -426,19 +431,17 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
                        len = op.op_buflen = 0;
                }
 
-               error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(op));
-               if (error) {
+               if (!access_ok(VERIFY_WRITE, argp, sizeof(op))) {
                        kfree(str);
-                       return error;
+                       return -EFAULT;
                }
 
-               error = verify_area(VERIFY_WRITE, op.op_buf, len);
-               if (error) {
+               if (!access_ok(VERIFY_WRITE, op.op_buf, len)) {
                        kfree(str);
-                       return error;
+                       return -EFAULT;
                }
 
-               error = __copy_to_user((void *)arg, &op, sizeof(op));
+               error = __copy_to_user(argp, &op, sizeof(op));
                if (!error) error = __copy_to_user(op.op_buf, tmp, len);
 
                kfree(str);
@@ -446,7 +449,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
                return error;
 
        case OPIOCSET:
-               if (copy_from_user(&op, (void *)arg, sizeof(op)))
+               if (copy_from_user(&op, argp, sizeof(op)))
                        return -EFAULT;
 
                if (!goodnode(op.op_nodeid,data))
@@ -473,13 +476,13 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
                return 0;
 
        case OPIOCGETOPTNODE:
-               if (copy_to_user((void *)arg, &options_node, sizeof(int)))
+               if (copy_to_user(argp, &options_node, sizeof(int)))
                        return -EFAULT;
                return 0;
 
        case OPIOCGETNEXT:
        case OPIOCGETCHILD:
-               if (copy_from_user(&node, (void *)arg, sizeof(int)))
+               if (copy_from_user(&node, argp, sizeof(int)))
                        return -EFAULT;
 
                if (cmd == OPIOCGETNEXT)
@@ -487,7 +490,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
                else
                        node = __prom_getchild(node);
 
-               if (__copy_to_user((void *)arg, &node, sizeof(int)))
+               if (__copy_to_user(argp, &node, sizeof(int)))
                        return -EFAULT;
 
                return 0;
@@ -566,6 +569,40 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
        }
 }
 
+static long openprom_compat_ioctl(struct file *file, unsigned int cmd,
+               unsigned long arg)
+{
+       long rval = -ENOTTY;
+
+       /*
+        * SunOS/Solaris only, the NetBSD one's have embedded pointers in
+        * the arg which we'd need to clean up...
+        */
+       switch (cmd) {
+       case OPROMGETOPT:
+       case OPROMSETOPT:
+       case OPROMNXTOPT:
+       case OPROMSETOPT2:
+       case OPROMNEXT:
+       case OPROMCHILD:
+       case OPROMGETPROP:
+       case OPROMNXTPROP:
+       case OPROMU2P:
+       case OPROMGETCONS:
+       case OPROMGETFBNAME:
+       case OPROMGETBOOTARGS:
+       case OPROMSETCUR:
+       case OPROMPCI2NODE:
+       case OPROMPATH2NODE:
+               lock_kernel();
+               rval = openprom_ioctl(file->f_dentry->d_inode, file, cmd, arg);
+               lock_kernel();
+               break;
+       }
+
+       return rval;
+}
+
 static int openprom_open(struct inode * inode, struct file * file)
 {
        DATA *data;
@@ -591,6 +628,7 @@ static struct file_operations openprom_fops = {
        .owner =        THIS_MODULE,
        .llseek =       no_llseek,
        .ioctl =        openprom_ioctl,
+       .compat_ioctl = openprom_compat_ioctl,
        .open =         openprom_open,
        .release =      openprom_release,
 };