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: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ef87979c27
commit
582b0b6113
|
@ -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)
|
||||||
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)
|
||||||
|
|
||||||
/* 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 = {
|
||||||
};
|
};
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue