Commit a0649e6d authored by Al Viro's avatar Al Viro Committed by Luis Henriques

fix misuses of f_count() in ppp and netlink

commit 24dff96a upstream.

we used to check for "nobody else could start doing anything with
that opened file" by checking that refcount was 2 or less - one
for descriptor table and one we'd acquired in fget() on the way to
wherever we are.  That was race-prone (somebody else might have
had a reference to descriptor table and do fget() just as we'd
been checking) and it had become flat-out incorrect back when
we switched to fget_light() on those codepaths - unlike fget(),
it doesn't grab an extra reference unless the descriptor table
is shared.  The same change allowed a race-free check, though -
we are safe exactly when refcount is less than 2.

It was a long time ago; pre-2.6.12 for ioctl() (the codepath leading
to ppp one) and 2.6.17 for sendmsg() (netlink one).  OTOH,
netlink hadn't grown that check until 3.9 and ppp used to live
in drivers/net, not drivers/net/ppp until 3.1.  The bug existed
well before that, though, and the same fix used to apply in old
location of file.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent e61cf85b
...@@ -594,7 +594,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -594,7 +594,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (file == ppp->owner) if (file == ppp->owner)
ppp_shutdown_interface(ppp); ppp_shutdown_interface(ppp);
} }
if (atomic_long_read(&file->f_count) <= 2) { if (atomic_long_read(&file->f_count) < 2) {
ppp_release(NULL, file); ppp_release(NULL, file);
err = 0; err = 0;
} else } else
......
...@@ -707,7 +707,7 @@ static int netlink_mmap_sendmsg(struct sock *sk, struct msghdr *msg, ...@@ -707,7 +707,7 @@ static int netlink_mmap_sendmsg(struct sock *sk, struct msghdr *msg,
* after validation, the socket and the ring may only be used by a * after validation, the socket and the ring may only be used by a
* single process, otherwise we fall back to copying. * single process, otherwise we fall back to copying.
*/ */
if (atomic_long_read(&sk->sk_socket->file->f_count) > 2 || if (atomic_long_read(&sk->sk_socket->file->f_count) > 1 ||
atomic_read(&nlk->mapped) > 1) atomic_read(&nlk->mapped) > 1)
excl = false; excl = false;
......
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