ppp: ensure file->private_data can't be overridden
[pandora-kernel.git] / drivers / net / ppp / ppp_generic.c
index 3ed983c..e948e53 100644 (file)
@@ -555,7 +555,7 @@ static int get_filter(void __user *arg, struct sock_filter **p)
 
 static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct ppp_file *pf = file->private_data;
+       struct ppp_file *pf;
        struct ppp *ppp;
        int err = -EFAULT, val, val2, i;
        struct ppp_idle idle;
@@ -565,9 +565,14 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
 
-       if (!pf)
-               return ppp_unattached_ioctl(current->nsproxy->net_ns,
-                                       pf, file, cmd, arg);
+       mutex_lock(&ppp_mutex);
+
+       pf = file->private_data;
+       if (!pf) {
+               err = ppp_unattached_ioctl(current->nsproxy->net_ns,
+                                          pf, file, cmd, arg);
+               goto out;
+       }
 
        if (cmd == PPPIOCDETACH) {
                /*
@@ -582,27 +587,24 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                 * this fd and reopening /dev/ppp.
                 */
                err = -EINVAL;
-               mutex_lock(&ppp_mutex);
                if (pf->kind == INTERFACE) {
                        ppp = PF_TO_PPP(pf);
                        if (file == ppp->owner)
                                ppp_shutdown_interface(ppp);
                }
-               if (atomic_long_read(&file->f_count) <= 2) {
+               if (atomic_long_read(&file->f_count) < 2) {
                        ppp_release(NULL, file);
                        err = 0;
                } else
                        pr_warn("PPPIOCDETACH file->f_count=%ld\n",
                                atomic_long_read(&file->f_count));
-               mutex_unlock(&ppp_mutex);
-               return err;
+               goto out;
        }
 
        if (pf->kind == CHANNEL) {
                struct channel *pch;
                struct ppp_channel *chan;
 
-               mutex_lock(&ppp_mutex);
                pch = PF_TO_CHANNEL(pf);
 
                switch (cmd) {
@@ -624,17 +626,16 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                err = chan->ops->ioctl(chan, cmd, arg);
                        up_read(&pch->chan_sem);
                }
-               mutex_unlock(&ppp_mutex);
-               return err;
+               goto out;
        }
 
        if (pf->kind != INTERFACE) {
                /* can't happen */
                pr_err("PPP: not interface or channel??\n");
-               return -EINVAL;
+               err = -EINVAL;
+               goto out;
        }
 
-       mutex_lock(&ppp_mutex);
        ppp = PF_TO_PPP(pf);
        switch (cmd) {
        case PPPIOCSMRU:
@@ -703,10 +704,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        val &= 0xffff;
                }
                vj = slhc_init(val2+1, val+1);
-               if (!vj) {
-                       netdev_err(ppp->dev,
-                                  "PPP: no memory (VJ compressor)\n");
-                       err = -ENOMEM;
+               if (IS_ERR(vj)) {
+                       err = PTR_ERR(vj);
                        break;
                }
                ppp_lock(ppp);
@@ -783,7 +782,10 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        default:
                err = -ENOTTY;
        }
+
+out:
        mutex_unlock(&ppp_mutex);
+
        return err;
 }
 
@@ -796,7 +798,6 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
        struct ppp_net *pn;
        int __user *p = (int __user *)arg;
 
-       mutex_lock(&ppp_mutex);
        switch (cmd) {
        case PPPIOCNEWUNIT:
                /* Create a new ppp unit */
@@ -847,7 +848,7 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
        default:
                err = -ENOTTY;
        }
-       mutex_unlock(&ppp_mutex);
+
        return err;
 }