Commit 582b0b61 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont Committed by David S. Miller

Phonet: fix race for port number in concurrent bind()

Allocating a port number to a socket and hashing that socket shall be
an atomic operation with regards to other port allocation. Otherwise,
we could allocate a port that is already being allocated to another
socket.
Signed-off-by: default avatarRémi Denis-Courmont <remi.denis-courmont@nokia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ef87979c
...@@ -113,6 +113,8 @@ void pn_sock_unhash(struct sock *sk) ...@@ -113,6 +113,8 @@ void pn_sock_unhash(struct sock *sk)
} }
EXPORT_SYMBOL(pn_sock_unhash); EXPORT_SYMBOL(pn_sock_unhash);
static DEFINE_MUTEX(port_mutex);
static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len) static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
...@@ -140,9 +142,11 @@ static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len) ...@@ -140,9 +142,11 @@ static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
err = -EINVAL; /* attempt to rebind */ err = -EINVAL; /* attempt to rebind */
goto out; goto out;
} }
WARN_ON(sk_hashed(sk));
mutex_lock(&port_mutex);
err = sk->sk_prot->get_port(sk, pn_port(handle)); err = sk->sk_prot->get_port(sk, pn_port(handle));
if (err) if (err)
goto out; goto out_port;
/* get_port() sets the port, bind() sets the address if applicable */ /* get_port() sets the port, bind() sets the address if applicable */
pn->sobject = pn_object(saddr, pn_port(pn->sobject)); pn->sobject = pn_object(saddr, pn_port(pn->sobject));
...@@ -150,6 +154,8 @@ static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len) ...@@ -150,6 +154,8 @@ static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
/* Enable RX on the socket */ /* Enable RX on the socket */
sk->sk_prot->hash(sk); sk->sk_prot->hash(sk);
out_port:
mutex_unlock(&port_mutex);
out: out:
release_sock(sk); release_sock(sk);
return err; return err;
...@@ -357,8 +363,6 @@ const struct proto_ops phonet_stream_ops = { ...@@ -357,8 +363,6 @@ const struct proto_ops phonet_stream_ops = {
}; };
EXPORT_SYMBOL(phonet_stream_ops); EXPORT_SYMBOL(phonet_stream_ops);
static DEFINE_MUTEX(port_mutex);
/* allocate port for a socket */ /* allocate port for a socket */
int pn_sock_get_port(struct sock *sk, unsigned short sport) int pn_sock_get_port(struct sock *sk, unsigned short sport)
{ {
...@@ -370,9 +374,7 @@ int pn_sock_get_port(struct sock *sk, unsigned short sport) ...@@ -370,9 +374,7 @@ int pn_sock_get_port(struct sock *sk, unsigned short sport)
memset(&try_sa, 0, sizeof(struct sockaddr_pn)); memset(&try_sa, 0, sizeof(struct sockaddr_pn));
try_sa.spn_family = AF_PHONET; try_sa.spn_family = AF_PHONET;
WARN_ON(!mutex_is_locked(&port_mutex));
mutex_lock(&port_mutex);
if (!sport) { if (!sport) {
/* search free port */ /* search free port */
int port, pmin, pmax; int port, pmin, pmax;
...@@ -401,8 +403,6 @@ int pn_sock_get_port(struct sock *sk, unsigned short sport) ...@@ -401,8 +403,6 @@ int pn_sock_get_port(struct sock *sk, unsigned short sport)
else else
sock_put(tmpsk); sock_put(tmpsk);
} }
mutex_unlock(&port_mutex);
/* the port must be in use already */ /* the port must be in use already */
return -EADDRINUSE; return -EADDRINUSE;
......
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