Commit 029464a3 authored by Guillaume Nault's avatar Guillaume Nault Committed by Greg Kroah-Hartman

ppp: ensure file->private_data can't be overridden

[ Upstream commit e8e56ffd ]

Locking ppp_mutex must be done before dereferencing file->private_data,
otherwise it could be modified before ppp_unattached_ioctl() takes the
lock. This could lead ppp_unattached_ioctl() to override ->private_data,
thus leaking reference to the ppp_file previously pointed to.

v2: lock all ppp_ioctl() instead of just checking private_data in
    ppp_unattached_ioctl(), to avoid ambiguous behaviour.

Fixes: f3ff8a4d ("ppp: push BKL down into the driver")
Signed-off-by: default avatarGuillaume Nault <g.nault@alphalink.fr>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a317579b
...@@ -567,7 +567,7 @@ static int get_filter(void __user *arg, struct sock_filter **p) ...@@ -567,7 +567,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) 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; struct ppp *ppp;
int err = -EFAULT, val, val2, i; int err = -EFAULT, val, val2, i;
struct ppp_idle idle; struct ppp_idle idle;
...@@ -577,9 +577,14 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -577,9 +577,14 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
if (!pf) mutex_lock(&ppp_mutex);
return ppp_unattached_ioctl(current->nsproxy->net_ns,
pf, file, cmd, arg); pf = file->private_data;
if (!pf) {
err = ppp_unattached_ioctl(current->nsproxy->net_ns,
pf, file, cmd, arg);
goto out;
}
if (cmd == PPPIOCDETACH) { if (cmd == PPPIOCDETACH) {
/* /*
...@@ -594,7 +599,6 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -594,7 +599,6 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
* this fd and reopening /dev/ppp. * this fd and reopening /dev/ppp.
*/ */
err = -EINVAL; err = -EINVAL;
mutex_lock(&ppp_mutex);
if (pf->kind == INTERFACE) { if (pf->kind == INTERFACE) {
ppp = PF_TO_PPP(pf); ppp = PF_TO_PPP(pf);
rtnl_lock(); rtnl_lock();
...@@ -608,15 +612,13 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -608,15 +612,13 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
} else } else
pr_warn("PPPIOCDETACH file->f_count=%ld\n", pr_warn("PPPIOCDETACH file->f_count=%ld\n",
atomic_long_read(&file->f_count)); atomic_long_read(&file->f_count));
mutex_unlock(&ppp_mutex); goto out;
return err;
} }
if (pf->kind == CHANNEL) { if (pf->kind == CHANNEL) {
struct channel *pch; struct channel *pch;
struct ppp_channel *chan; struct ppp_channel *chan;
mutex_lock(&ppp_mutex);
pch = PF_TO_CHANNEL(pf); pch = PF_TO_CHANNEL(pf);
switch (cmd) { switch (cmd) {
...@@ -638,17 +640,16 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -638,17 +640,16 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
err = chan->ops->ioctl(chan, cmd, arg); err = chan->ops->ioctl(chan, cmd, arg);
up_read(&pch->chan_sem); up_read(&pch->chan_sem);
} }
mutex_unlock(&ppp_mutex); goto out;
return err;
} }
if (pf->kind != INTERFACE) { if (pf->kind != INTERFACE) {
/* can't happen */ /* can't happen */
pr_err("PPP: not interface or channel??\n"); pr_err("PPP: not interface or channel??\n");
return -EINVAL; err = -EINVAL;
goto out;
} }
mutex_lock(&ppp_mutex);
ppp = PF_TO_PPP(pf); ppp = PF_TO_PPP(pf);
switch (cmd) { switch (cmd) {
case PPPIOCSMRU: case PPPIOCSMRU:
...@@ -823,7 +824,10 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -823,7 +824,10 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
default: default:
err = -ENOTTY; err = -ENOTTY;
} }
out:
mutex_unlock(&ppp_mutex); mutex_unlock(&ppp_mutex);
return err; return err;
} }
...@@ -836,7 +840,6 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, ...@@ -836,7 +840,6 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
struct ppp_net *pn; struct ppp_net *pn;
int __user *p = (int __user *)arg; int __user *p = (int __user *)arg;
mutex_lock(&ppp_mutex);
switch (cmd) { switch (cmd) {
case PPPIOCNEWUNIT: case PPPIOCNEWUNIT:
/* Create a new ppp unit */ /* Create a new ppp unit */
...@@ -886,7 +889,7 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, ...@@ -886,7 +889,7 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
default: default:
err = -ENOTTY; err = -ENOTTY;
} }
mutex_unlock(&ppp_mutex);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment