aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRémi Denis-Courmont <remi.denis-courmont@nokia.com>2009-09-22 23:17:10 -0400
committerDavid S. Miller <davem@davemloft.net>2009-09-24 18:38:54 -0400
commit582b0b611345fc8d9ab8a0605d2f14c468902719 (patch)
tree3e051d3777171b7f708f5fd89c910d7a62eedfad
parentef87979c273a2348430648ad1d5c2a5e5df50b6e (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>
-rw-r--r--net/phonet/socket.c16
1 files changed, 8 insertions, 8 deletions
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 7a4ee397d2f7..07aa9f08d5fb 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -113,6 +113,8 @@ void pn_sock_unhash(struct sock *sk)
113} 113}
114EXPORT_SYMBOL(pn_sock_unhash); 114EXPORT_SYMBOL(pn_sock_unhash);
115 115
116static DEFINE_MUTEX(port_mutex);
117
116static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len) 118static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
117{ 119{
118 struct sock *sk = sock->sk; 120 struct sock *sk = sock->sk;
@@ -140,9 +142,11 @@ static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
140 err = -EINVAL; /* attempt to rebind */ 142 err = -EINVAL; /* attempt to rebind */
141 goto out; 143 goto out;
142 } 144 }
145 WARN_ON(sk_hashed(sk));
146 mutex_lock(&port_mutex);
143 err = sk->sk_prot->get_port(sk, pn_port(handle)); 147 err = sk->sk_prot->get_port(sk, pn_port(handle));
144 if (err) 148 if (err)
145 goto out; 149 goto out_port;
146 150
147 /* get_port() sets the port, bind() sets the address if applicable */ 151 /* get_port() sets the port, bind() sets the address if applicable */
148 pn->sobject = pn_object(saddr, pn_port(pn->sobject)); 152 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 154
151 /* Enable RX on the socket */ 155 /* Enable RX on the socket */
152 sk->sk_prot->hash(sk); 156 sk->sk_prot->hash(sk);
157out_port:
158 mutex_unlock(&port_mutex);
153out: 159out:
154 release_sock(sk); 160 release_sock(sk);
155 return err; 161 return err;
@@ -357,8 +363,6 @@ const struct proto_ops phonet_stream_ops = {
357}; 363};
358EXPORT_SYMBOL(phonet_stream_ops); 364EXPORT_SYMBOL(phonet_stream_ops);
359 365
360static DEFINE_MUTEX(port_mutex);
361
362/* allocate port for a socket */ 366/* allocate port for a socket */
363int pn_sock_get_port(struct sock *sk, unsigned short sport) 367int pn_sock_get_port(struct sock *sk, unsigned short sport)
364{ 368{
@@ -370,9 +374,7 @@ int pn_sock_get_port(struct sock *sk, unsigned short sport)
370 374
371 memset(&try_sa, 0, sizeof(struct sockaddr_pn)); 375 memset(&try_sa, 0, sizeof(struct sockaddr_pn));
372 try_sa.spn_family = AF_PHONET; 376 try_sa.spn_family = AF_PHONET;
373 377 WARN_ON(!mutex_is_locked(&port_mutex));
374 mutex_lock(&port_mutex);
375
376 if (!sport) { 378 if (!sport) {
377 /* search free port */ 379 /* search free port */
378 int port, pmin, pmax; 380 int port, pmin, pmax;
@@ -401,8 +403,6 @@ int pn_sock_get_port(struct sock *sk, unsigned short sport)
401 else 403 else
402 sock_put(tmpsk); 404 sock_put(tmpsk);
403 } 405 }
404 mutex_unlock(&port_mutex);
405
406 /* the port must be in use already */ 406 /* the port must be in use already */
407 return -EADDRINUSE; 407 return -EADDRINUSE;
408 408