Skip to content

Commit 68bf33f

Browse files
committed
Merge branch 'rds-tcp-netns-delete-related-fixes'
Sowmini Varadhan says: ==================== rds-tcp netns delete related fixes Patchset contains cleanup and bug fixes. Patch 1 is the removal of some redundant code/functions. Patch 2 and 3 are fixes for corner cases identified by syzkaller. I've not been able to reproduce the actual use-after-free race flagged in the syzkaller reports, thus these fixes are based on code inspection plus manual testing to make sure the modified code paths are executed without problems in the commonly encountered timing cases. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 4c94cc2 + f10b4cf commit 68bf33f

File tree

4 files changed

+16
-32
lines changed

4 files changed

+16
-32
lines changed

net/rds/connection.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,8 @@ void rds_conn_shutdown(struct rds_conn_path *cp)
366366
* to the conn hash, so we never trigger a reconnect on this
367367
* conn - the reconnect is always triggered by the active peer. */
368368
cancel_delayed_work_sync(&cp->cp_conn_w);
369+
if (conn->c_destroy_in_prog)
370+
return;
369371
rcu_read_lock();
370372
if (!hlist_unhashed(&conn->c_hash_node)) {
371373
rcu_read_unlock();
@@ -445,7 +447,6 @@ void rds_conn_destroy(struct rds_connection *conn)
445447
*/
446448
rds_cong_remove_conn(conn);
447449

448-
put_net(conn->c_net);
449450
kfree(conn->c_path);
450451
kmem_cache_free(rds_conn_slab, conn);
451452

net/rds/rds.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ struct rds_connection {
150150

151151
/* Protocol version */
152152
unsigned int c_version;
153-
struct net *c_net;
153+
possible_net_t c_net;
154154

155155
struct list_head c_map_item;
156156
unsigned long c_map_queued;
@@ -165,13 +165,13 @@ struct rds_connection {
165165
static inline
166166
struct net *rds_conn_net(struct rds_connection *conn)
167167
{
168-
return conn->c_net;
168+
return read_pnet(&conn->c_net);
169169
}
170170

171171
static inline
172172
void rds_conn_net_set(struct rds_connection *conn, struct net *net)
173173
{
174-
conn->c_net = get_net(net);
174+
write_pnet(&conn->c_net, net);
175175
}
176176

177177
#define RDS_FLAG_CONG_BITMAP 0x01

net/rds/tcp.c

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,8 @@ static void rds_tcp_conn_free(void *arg)
306306
rdsdebug("freeing tc %p\n", tc);
307307

308308
spin_lock_irqsave(&rds_tcp_conn_lock, flags);
309-
list_del(&tc->t_tcp_node);
309+
if (!tc->t_tcp_node_detached)
310+
list_del(&tc->t_tcp_node);
310311
spin_unlock_irqrestore(&rds_tcp_conn_lock, flags);
311312

312313
kmem_cache_free(rds_tcp_conn_slab, tc);
@@ -495,27 +496,6 @@ static struct pernet_operations rds_tcp_net_ops = {
495496
.size = sizeof(struct rds_tcp_net),
496497
};
497498

498-
/* explicitly send a RST on each socket, thereby releasing any socket refcnts
499-
* that may otherwise hold up netns deletion.
500-
*/
501-
static void rds_tcp_conn_paths_destroy(struct rds_connection *conn)
502-
{
503-
struct rds_conn_path *cp;
504-
struct rds_tcp_connection *tc;
505-
int i;
506-
struct sock *sk;
507-
508-
for (i = 0; i < RDS_MPATH_WORKERS; i++) {
509-
cp = &conn->c_path[i];
510-
tc = cp->cp_transport_data;
511-
if (!tc->t_sock)
512-
continue;
513-
sk = tc->t_sock->sk;
514-
sk->sk_prot->disconnect(sk, 0);
515-
tcp_done(sk);
516-
}
517-
}
518-
519499
static void rds_tcp_kill_sock(struct net *net)
520500
{
521501
struct rds_tcp_connection *tc, *_tc;
@@ -527,18 +507,20 @@ static void rds_tcp_kill_sock(struct net *net)
527507
rds_tcp_listen_stop(lsock, &rtn->rds_tcp_accept_w);
528508
spin_lock_irq(&rds_tcp_conn_lock);
529509
list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) {
530-
struct net *c_net = tc->t_cpath->cp_conn->c_net;
510+
struct net *c_net = read_pnet(&tc->t_cpath->cp_conn->c_net);
531511

532512
if (net != c_net || !tc->t_sock)
533513
continue;
534-
if (!list_has_conn(&tmp_list, tc->t_cpath->cp_conn))
514+
if (!list_has_conn(&tmp_list, tc->t_cpath->cp_conn)) {
535515
list_move_tail(&tc->t_tcp_node, &tmp_list);
516+
} else {
517+
list_del(&tc->t_tcp_node);
518+
tc->t_tcp_node_detached = true;
519+
}
536520
}
537521
spin_unlock_irq(&rds_tcp_conn_lock);
538-
list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node) {
539-
rds_tcp_conn_paths_destroy(tc->t_cpath->cp_conn);
522+
list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node)
540523
rds_conn_destroy(tc->t_cpath->cp_conn);
541-
}
542524
}
543525

544526
void *rds_tcp_listen_sock_def_readable(struct net *net)
@@ -586,7 +568,7 @@ static void rds_tcp_sysctl_reset(struct net *net)
586568

587569
spin_lock_irq(&rds_tcp_conn_lock);
588570
list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) {
589-
struct net *c_net = tc->t_cpath->cp_conn->c_net;
571+
struct net *c_net = read_pnet(&tc->t_cpath->cp_conn->c_net);
590572

591573
if (net != c_net || !tc->t_sock)
592574
continue;

net/rds/tcp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ struct rds_tcp_incoming {
1212
struct rds_tcp_connection {
1313

1414
struct list_head t_tcp_node;
15+
bool t_tcp_node_detached;
1516
struct rds_conn_path *t_cpath;
1617
/* t_conn_path_lock synchronizes the connection establishment between
1718
* rds_tcp_accept_one and rds_tcp_conn_path_connect

0 commit comments

Comments
 (0)