diff options
author | Rémi Denis-Courmont <remi.denis-courmont@nokia.com> | 2009-09-23 03:17:10 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-09-24 15:38:54 -0700 |
commit | 582b0b611345fc8d9ab8a0605d2f14c468902719 (patch) | |
tree | 3e051d3777171b7f708f5fd89c910d7a62eedfad /net | |
parent | ef87979c273a2348430648ad1d5c2a5e5df50b6e (diff) |
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>
Diffstat (limited to 'net')
-rw-r--r-- | net/phonet/socket.c | 16 |
1 files changed, 8 insertions, 8 deletions
diff --git a/net/phonet/socket.c b/net/phonet/socket.c index 7a4ee397d2f..07aa9f08d5f 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -113,6 +113,8 @@ void pn_sock_unhash(struct sock *sk) } EXPORT_SYMBOL(pn_sock_unhash); +static DEFINE_MUTEX(port_mutex); + static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len) { 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 */ goto out; } + WARN_ON(sk_hashed(sk)); + mutex_lock(&port_mutex); err = sk->sk_prot->get_port(sk, pn_port(handle)); if (err) - goto out; + goto out_port; /* get_port() sets the port, bind() sets the address if applicable */ 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 */ sk->sk_prot->hash(sk); +out_port: + mutex_unlock(&port_mutex); out: release_sock(sk); return err; @@ -357,8 +363,6 @@ const struct proto_ops phonet_stream_ops = { }; EXPORT_SYMBOL(phonet_stream_ops); -static DEFINE_MUTEX(port_mutex); - /* allocate port for a socket */ 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)); try_sa.spn_family = AF_PHONET; - - mutex_lock(&port_mutex); - + WARN_ON(!mutex_is_locked(&port_mutex)); if (!sport) { /* search free port */ int port, pmin, pmax; @@ -401,8 +403,6 @@ int pn_sock_get_port(struct sock *sk, unsigned short sport) else sock_put(tmpsk); } - mutex_unlock(&port_mutex); - /* the port must be in use already */ return -EADDRINUSE; |