aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2016-09-29 17:37:15 -0400
committerDavid Howells <dhowells@redhat.com>2016-09-29 17:57:47 -0400
commit1e9e5c9521d3667664a6e3c97075f71afec23720 (patch)
treefb2447d0038b67d5ee980ab075047db2311ee308
parent2629c7fa7c0adfdf023051b404cd538951bd0354 (diff)
rxrpc: Reduce the rxrpc_local::services list to a pointer
Reduce the rxrpc_local::services list to just a pointer as we don't permit multiple service endpoints to bind to a single transport endpoints (this is excluded by rxrpc_lookup_local()). The reason we don't allow this is that if you send a request to an AFS filesystem service, it will try to talk back to your cache manager on the port you sent from (this is how file change notifications are handled). To prevent someone from stealing your CM callbacks, we don't let AF_RXRPC sockets share a UDP socket if at least one of them has a service bound. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--net/rxrpc/af_rxrpc.c21
-rw-r--r--net/rxrpc/ar-internal.h3
-rw-r--r--net/rxrpc/call_accept.c8
-rw-r--r--net/rxrpc/local_object.c3
-rw-r--r--net/rxrpc/security.c8
5 files changed, 18 insertions, 25 deletions
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 8dbf7bed2cc4..44c9c2b0b190 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -136,7 +136,8 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
136 struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *)saddr; 136 struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *)saddr;
137 struct sock *sk = sock->sk; 137 struct sock *sk = sock->sk;
138 struct rxrpc_local *local; 138 struct rxrpc_local *local;
139 struct rxrpc_sock *rx = rxrpc_sk(sk), *prx; 139 struct rxrpc_sock *rx = rxrpc_sk(sk);
140 u16 service_id = srx->srx_service;
140 int ret; 141 int ret;
141 142
142 _enter("%p,%p,%d", rx, saddr, len); 143 _enter("%p,%p,%d", rx, saddr, len);
@@ -160,15 +161,12 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
160 goto error_unlock; 161 goto error_unlock;
161 } 162 }
162 163
163 if (rx->srx.srx_service) { 164 if (service_id) {
164 write_lock(&local->services_lock); 165 write_lock(&local->services_lock);
165 hlist_for_each_entry(prx, &local->services, listen_link) { 166 if (rcu_access_pointer(local->service))
166 if (prx->srx.srx_service == rx->srx.srx_service) 167 goto service_in_use;
167 goto service_in_use;
168 }
169
170 rx->local = local; 168 rx->local = local;
171 hlist_add_head_rcu(&rx->listen_link, &local->services); 169 rcu_assign_pointer(local->service, rx);
172 write_unlock(&local->services_lock); 170 write_unlock(&local->services_lock);
173 171
174 rx->sk.sk_state = RXRPC_SERVER_BOUND; 172 rx->sk.sk_state = RXRPC_SERVER_BOUND;
@@ -599,7 +597,6 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
599 rx->family = protocol; 597 rx->family = protocol;
600 rx->calls = RB_ROOT; 598 rx->calls = RB_ROOT;
601 599
602 INIT_HLIST_NODE(&rx->listen_link);
603 spin_lock_init(&rx->incoming_lock); 600 spin_lock_init(&rx->incoming_lock);
604 INIT_LIST_HEAD(&rx->sock_calls); 601 INIT_LIST_HEAD(&rx->sock_calls);
605 INIT_LIST_HEAD(&rx->to_be_accepted); 602 INIT_LIST_HEAD(&rx->to_be_accepted);
@@ -681,11 +678,9 @@ static int rxrpc_release_sock(struct sock *sk)
681 sk->sk_state = RXRPC_CLOSE; 678 sk->sk_state = RXRPC_CLOSE;
682 spin_unlock_bh(&sk->sk_receive_queue.lock); 679 spin_unlock_bh(&sk->sk_receive_queue.lock);
683 680
684 ASSERTCMP(rx->listen_link.next, !=, LIST_POISON1); 681 if (rx->local && rx->local->service == rx) {
685
686 if (!hlist_unhashed(&rx->listen_link)) {
687 write_lock(&rx->local->services_lock); 682 write_lock(&rx->local->services_lock);
688 hlist_del_rcu(&rx->listen_link); 683 rx->local->service = NULL;
689 write_unlock(&rx->local->services_lock); 684 write_unlock(&rx->local->services_lock);
690 } 685 }
691 686
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 6aadaa7d8b43..539db54697f9 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -93,7 +93,6 @@ struct rxrpc_sock {
93 rxrpc_notify_new_call_t notify_new_call; /* Func to notify of new call */ 93 rxrpc_notify_new_call_t notify_new_call; /* Func to notify of new call */
94 rxrpc_discard_new_call_t discard_new_call; /* Func to discard a new call */ 94 rxrpc_discard_new_call_t discard_new_call; /* Func to discard a new call */
95 struct rxrpc_local *local; /* local endpoint */ 95 struct rxrpc_local *local; /* local endpoint */
96 struct hlist_node listen_link; /* link in the local endpoint's listen list */
97 struct rxrpc_backlog *backlog; /* Preallocation for services */ 96 struct rxrpc_backlog *backlog; /* Preallocation for services */
98 spinlock_t incoming_lock; /* Incoming call vs service shutdown lock */ 97 spinlock_t incoming_lock; /* Incoming call vs service shutdown lock */
99 struct list_head sock_calls; /* List of calls owned by this socket */ 98 struct list_head sock_calls; /* List of calls owned by this socket */
@@ -216,7 +215,7 @@ struct rxrpc_local {
216 struct list_head link; 215 struct list_head link;
217 struct socket *socket; /* my UDP socket */ 216 struct socket *socket; /* my UDP socket */
218 struct work_struct processor; 217 struct work_struct processor;
219 struct hlist_head services; /* services listening on this endpoint */ 218 struct rxrpc_sock __rcu *service; /* Service(s) listening on this endpoint */
220 struct rw_semaphore defrag_sem; /* control re-enablement of IP DF bit */ 219 struct rw_semaphore defrag_sem; /* control re-enablement of IP DF bit */
221 struct sk_buff_head reject_queue; /* packets awaiting rejection */ 220 struct sk_buff_head reject_queue; /* packets awaiting rejection */
222 struct sk_buff_head event_queue; /* endpoint event packets awaiting processing */ 221 struct sk_buff_head event_queue; /* endpoint event packets awaiting processing */
diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c
index a8d39d7cf42c..3cac231d8405 100644
--- a/net/rxrpc/call_accept.c
+++ b/net/rxrpc/call_accept.c
@@ -331,14 +331,14 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
331 struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 331 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
332 struct rxrpc_sock *rx; 332 struct rxrpc_sock *rx;
333 struct rxrpc_call *call; 333 struct rxrpc_call *call;
334 u16 service_id = sp->hdr.serviceId;
334 335
335 _enter(""); 336 _enter("");
336 337
337 /* Get the socket providing the service */ 338 /* Get the socket providing the service */
338 hlist_for_each_entry_rcu_bh(rx, &local->services, listen_link) { 339 rx = rcu_dereference(local->service);
339 if (rx->srx.srx_service == sp->hdr.serviceId) 340 if (service_id == rx->srx.srx_service)
340 goto found_service; 341 goto found_service;
341 }
342 342
343 trace_rxrpc_abort("INV", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq, 343 trace_rxrpc_abort("INV", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
344 RX_INVALID_OPERATION, EOPNOTSUPP); 344 RX_INVALID_OPERATION, EOPNOTSUPP);
diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c
index e3fad80b0795..ff4864d550b8 100644
--- a/net/rxrpc/local_object.c
+++ b/net/rxrpc/local_object.c
@@ -86,7 +86,6 @@ static struct rxrpc_local *rxrpc_alloc_local(const struct sockaddr_rxrpc *srx)
86 atomic_set(&local->usage, 1); 86 atomic_set(&local->usage, 1);
87 INIT_LIST_HEAD(&local->link); 87 INIT_LIST_HEAD(&local->link);
88 INIT_WORK(&local->processor, rxrpc_local_processor); 88 INIT_WORK(&local->processor, rxrpc_local_processor);
89 INIT_HLIST_HEAD(&local->services);
90 init_rwsem(&local->defrag_sem); 89 init_rwsem(&local->defrag_sem);
91 skb_queue_head_init(&local->reject_queue); 90 skb_queue_head_init(&local->reject_queue);
92 skb_queue_head_init(&local->event_queue); 91 skb_queue_head_init(&local->event_queue);
@@ -292,7 +291,7 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local)
292 mutex_unlock(&rxrpc_local_mutex); 291 mutex_unlock(&rxrpc_local_mutex);
293 292
294 ASSERT(RB_EMPTY_ROOT(&local->client_conns)); 293 ASSERT(RB_EMPTY_ROOT(&local->client_conns));
295 ASSERT(hlist_empty(&local->services)); 294 ASSERT(!local->service);
296 295
297 if (socket) { 296 if (socket) {
298 local->socket = NULL; 297 local->socket = NULL;
diff --git a/net/rxrpc/security.c b/net/rxrpc/security.c
index 82d8134e9287..7d921e56e715 100644
--- a/net/rxrpc/security.c
+++ b/net/rxrpc/security.c
@@ -131,10 +131,10 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
131 131
132 /* find the service */ 132 /* find the service */
133 read_lock(&local->services_lock); 133 read_lock(&local->services_lock);
134 hlist_for_each_entry(rx, &local->services, listen_link) { 134 rx = rcu_dereference_protected(local->service,
135 if (rx->srx.srx_service == conn->params.service_id) 135 lockdep_is_held(&local->services_lock));
136 goto found_service; 136 if (rx && rx->srx.srx_service == conn->params.service_id)
137 } 137 goto found_service;
138 138
139 /* the service appears to have died */ 139 /* the service appears to have died */
140 read_unlock(&local->services_lock); 140 read_unlock(&local->services_lock);