summaryrefslogtreecommitdiffstats
path: root/net/rds/tcp.c
diff options
context:
space:
mode:
authorSowmini Varadhan <sowmini.varadhan@oracle.com>2018-02-03 07:26:51 -0500
committerDavid S. Miller <davem@davemloft.net>2018-02-08 15:23:52 -0500
commitebeeb1ad9b8adcc37c2ec21a96f39e9d35199b46 (patch)
tree25c1f3a044ab1c8f8e15031f606b00ae35db2ed0 /net/rds/tcp.c
parent79a8a642bf05cd0dced20621f6fef9d884124abd (diff)
rds: tcp: use rds_destroy_pending() to synchronize netns/module teardown and rds connection/workq management
An rds_connection can get added during netns deletion between lines 528 and 529 of 506 static void rds_tcp_kill_sock(struct net *net) : /* code to pull out all the rds_connections that should be destroyed */ : 528 spin_unlock_irq(&rds_tcp_conn_lock); 529 list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node) 530 rds_conn_destroy(tc->t_cpath->cp_conn); Such an rds_connection would miss out the rds_conn_destroy() loop (that cancels all pending work) and (if it was scheduled after netns deletion) could trigger the use-after-free. A similar race-window exists for the module unload path in rds_tcp_exit -> rds_tcp_destroy_conns Concurrency with netns deletion (rds_tcp_kill_sock()) must be handled by checking check_net() before enqueuing new work or adding new connections. Concurrency with module-unload is handled by maintaining a module specific flag that is set at the start of the module exit function, and must be checked before enqueuing new work or adding new connections. This commit refactors existing RDS_DESTROY_PENDING checks added by commit 3db6e0d172c9 ("rds: use RCU to synchronize work-enqueue with connection teardown") and consolidates all the concurrency checks listed above into the function rds_destroy_pending(). Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com> Acked-by: Santosh Shilimkar <santosh.shilimkar@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/rds/tcp.c')
-rw-r--r--net/rds/tcp.c42
1 files changed, 30 insertions, 12 deletions
diff --git a/net/rds/tcp.c b/net/rds/tcp.c
index 9920d2f84eff..44c4652721af 100644
--- a/net/rds/tcp.c
+++ b/net/rds/tcp.c
@@ -49,6 +49,7 @@ static unsigned int rds_tcp_tc_count;
49/* Track rds_tcp_connection structs so they can be cleaned up */ 49/* Track rds_tcp_connection structs so they can be cleaned up */
50static DEFINE_SPINLOCK(rds_tcp_conn_lock); 50static DEFINE_SPINLOCK(rds_tcp_conn_lock);
51static LIST_HEAD(rds_tcp_conn_list); 51static LIST_HEAD(rds_tcp_conn_list);
52static atomic_t rds_tcp_unloading = ATOMIC_INIT(0);
52 53
53static struct kmem_cache *rds_tcp_conn_slab; 54static struct kmem_cache *rds_tcp_conn_slab;
54 55
@@ -274,14 +275,13 @@ static int rds_tcp_laddr_check(struct net *net, __be32 addr)
274static void rds_tcp_conn_free(void *arg) 275static void rds_tcp_conn_free(void *arg)
275{ 276{
276 struct rds_tcp_connection *tc = arg; 277 struct rds_tcp_connection *tc = arg;
277 unsigned long flags;
278 278
279 rdsdebug("freeing tc %p\n", tc); 279 rdsdebug("freeing tc %p\n", tc);
280 280
281 spin_lock_irqsave(&rds_tcp_conn_lock, flags); 281 spin_lock_bh(&rds_tcp_conn_lock);
282 if (!tc->t_tcp_node_detached) 282 if (!tc->t_tcp_node_detached)
283 list_del(&tc->t_tcp_node); 283 list_del(&tc->t_tcp_node);
284 spin_unlock_irqrestore(&rds_tcp_conn_lock, flags); 284 spin_unlock_bh(&rds_tcp_conn_lock);
285 285
286 kmem_cache_free(rds_tcp_conn_slab, tc); 286 kmem_cache_free(rds_tcp_conn_slab, tc);
287} 287}
@@ -296,7 +296,7 @@ static int rds_tcp_conn_alloc(struct rds_connection *conn, gfp_t gfp)
296 tc = kmem_cache_alloc(rds_tcp_conn_slab, gfp); 296 tc = kmem_cache_alloc(rds_tcp_conn_slab, gfp);
297 if (!tc) { 297 if (!tc) {
298 ret = -ENOMEM; 298 ret = -ENOMEM;
299 break; 299 goto fail;
300 } 300 }
301 mutex_init(&tc->t_conn_path_lock); 301 mutex_init(&tc->t_conn_path_lock);
302 tc->t_sock = NULL; 302 tc->t_sock = NULL;
@@ -306,14 +306,19 @@ static int rds_tcp_conn_alloc(struct rds_connection *conn, gfp_t gfp)
306 306
307 conn->c_path[i].cp_transport_data = tc; 307 conn->c_path[i].cp_transport_data = tc;
308 tc->t_cpath = &conn->c_path[i]; 308 tc->t_cpath = &conn->c_path[i];
309 tc->t_tcp_node_detached = true;
309 310
310 spin_lock_irq(&rds_tcp_conn_lock);
311 tc->t_tcp_node_detached = false;
312 list_add_tail(&tc->t_tcp_node, &rds_tcp_conn_list);
313 spin_unlock_irq(&rds_tcp_conn_lock);
314 rdsdebug("rds_conn_path [%d] tc %p\n", i, 311 rdsdebug("rds_conn_path [%d] tc %p\n", i,
315 conn->c_path[i].cp_transport_data); 312 conn->c_path[i].cp_transport_data);
316 } 313 }
314 spin_lock_bh(&rds_tcp_conn_lock);
315 for (i = 0; i < RDS_MPATH_WORKERS; i++) {
316 tc = conn->c_path[i].cp_transport_data;
317 tc->t_tcp_node_detached = false;
318 list_add_tail(&tc->t_tcp_node, &rds_tcp_conn_list);
319 }
320 spin_unlock_bh(&rds_tcp_conn_lock);
321fail:
317 if (ret) { 322 if (ret) {
318 for (j = 0; j < i; j++) 323 for (j = 0; j < i; j++)
319 rds_tcp_conn_free(conn->c_path[j].cp_transport_data); 324 rds_tcp_conn_free(conn->c_path[j].cp_transport_data);
@@ -332,6 +337,16 @@ static bool list_has_conn(struct list_head *list, struct rds_connection *conn)
332 return false; 337 return false;
333} 338}
334 339
340static void rds_tcp_set_unloading(void)
341{
342 atomic_set(&rds_tcp_unloading, 1);
343}
344
345static bool rds_tcp_is_unloading(struct rds_connection *conn)
346{
347 return atomic_read(&rds_tcp_unloading) != 0;
348}
349
335static void rds_tcp_destroy_conns(void) 350static void rds_tcp_destroy_conns(void)
336{ 351{
337 struct rds_tcp_connection *tc, *_tc; 352 struct rds_tcp_connection *tc, *_tc;
@@ -370,6 +385,7 @@ struct rds_transport rds_tcp_transport = {
370 .t_type = RDS_TRANS_TCP, 385 .t_type = RDS_TRANS_TCP,
371 .t_prefer_loopback = 1, 386 .t_prefer_loopback = 1,
372 .t_mp_capable = 1, 387 .t_mp_capable = 1,
388 .t_unloading = rds_tcp_is_unloading,
373}; 389};
374 390
375static unsigned int rds_tcp_netid; 391static unsigned int rds_tcp_netid;
@@ -513,7 +529,7 @@ static void rds_tcp_kill_sock(struct net *net)
513 529
514 rtn->rds_tcp_listen_sock = NULL; 530 rtn->rds_tcp_listen_sock = NULL;
515 rds_tcp_listen_stop(lsock, &rtn->rds_tcp_accept_w); 531 rds_tcp_listen_stop(lsock, &rtn->rds_tcp_accept_w);
516 spin_lock_irq(&rds_tcp_conn_lock); 532 spin_lock_bh(&rds_tcp_conn_lock);
517 list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) { 533 list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) {
518 struct net *c_net = read_pnet(&tc->t_cpath->cp_conn->c_net); 534 struct net *c_net = read_pnet(&tc->t_cpath->cp_conn->c_net);
519 535
@@ -526,7 +542,7 @@ static void rds_tcp_kill_sock(struct net *net)
526 tc->t_tcp_node_detached = true; 542 tc->t_tcp_node_detached = true;
527 } 543 }
528 } 544 }
529 spin_unlock_irq(&rds_tcp_conn_lock); 545 spin_unlock_bh(&rds_tcp_conn_lock);
530 list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node) 546 list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node)
531 rds_conn_destroy(tc->t_cpath->cp_conn); 547 rds_conn_destroy(tc->t_cpath->cp_conn);
532} 548}
@@ -574,7 +590,7 @@ static void rds_tcp_sysctl_reset(struct net *net)
574{ 590{
575 struct rds_tcp_connection *tc, *_tc; 591 struct rds_tcp_connection *tc, *_tc;
576 592
577 spin_lock_irq(&rds_tcp_conn_lock); 593 spin_lock_bh(&rds_tcp_conn_lock);
578 list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) { 594 list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) {
579 struct net *c_net = read_pnet(&tc->t_cpath->cp_conn->c_net); 595 struct net *c_net = read_pnet(&tc->t_cpath->cp_conn->c_net);
580 596
@@ -584,7 +600,7 @@ static void rds_tcp_sysctl_reset(struct net *net)
584 /* reconnect with new parameters */ 600 /* reconnect with new parameters */
585 rds_conn_path_drop(tc->t_cpath, false); 601 rds_conn_path_drop(tc->t_cpath, false);
586 } 602 }
587 spin_unlock_irq(&rds_tcp_conn_lock); 603 spin_unlock_bh(&rds_tcp_conn_lock);
588} 604}
589 605
590static int rds_tcp_skbuf_handler(struct ctl_table *ctl, int write, 606static int rds_tcp_skbuf_handler(struct ctl_table *ctl, int write,
@@ -607,6 +623,8 @@ static int rds_tcp_skbuf_handler(struct ctl_table *ctl, int write,
607 623
608static void rds_tcp_exit(void) 624static void rds_tcp_exit(void)
609{ 625{
626 rds_tcp_set_unloading();
627 synchronize_rcu();
610 rds_info_deregister_func(RDS_INFO_TCP_SOCKETS, rds_tcp_tc_info); 628 rds_info_deregister_func(RDS_INFO_TCP_SOCKETS, rds_tcp_tc_info);
611 unregister_pernet_subsys(&rds_tcp_net_ops); 629 unregister_pernet_subsys(&rds_tcp_net_ops);
612 if (unregister_netdevice_notifier(&rds_tcp_dev_notifier)) 630 if (unregister_netdevice_notifier(&rds_tcp_dev_notifier))