ppp: ensure file->private_data can't be overridden
[pandora-kernel.git] / drivers / net / ppp / ppp_generic.c
index 82d4421..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,7 +587,6 @@ 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)
@@ -594,15 +598,13 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                } 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:
@@ -781,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;
 }
 
@@ -794,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 */
@@ -845,7 +848,7 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
        default:
                err = -ENOTTY;
        }
-       mutex_unlock(&ppp_mutex);
+
        return err;
 }