Skip to content

Commit e9f2517

Browse files
ematsumiyaSteve French
authored andcommitted
smb: client: fix TCP timers deadlock after rmmod
Commit ef7134c ("smb: client: Fix use-after-free of network namespace.") fixed a netns UAF by manually enabled socket refcounting (sk->sk_net_refcnt=1 and sock_inuse_add(net, 1)). The reason the patch worked for that bug was because we now hold references to the netns (get_net_track() gets a ref internally) and they're properly released (internally, on __sk_destruct()), but only because sk->sk_net_refcnt was set. Problem: (this happens regardless of CONFIG_NET_NS_REFCNT_TRACKER and regardless if init_net or other) Setting sk->sk_net_refcnt=1 *manually* and *after* socket creation is not only out of cifs scope, but also technically wrong -- it's set conditionally based on user (=1) vs kernel (=0) sockets. And net/ implementations seem to base their user vs kernel space operations on it. e.g. upon TCP socket close, the TCP timers are not cleared because sk->sk_net_refcnt=1: (cf. commit 151c9c7 ("tcp: properly terminate timers for kernel sockets")) net/ipv4/tcp.c: void tcp_close(struct sock *sk, long timeout) { lock_sock(sk); __tcp_close(sk, timeout); release_sock(sk); if (!sk->sk_net_refcnt) inet_csk_clear_xmit_timers_sync(sk); sock_put(sk); } Which will throw a lockdep warning and then, as expected, deadlock on tcp_write_timer(). A way to reproduce this is by running the reproducer from ef7134c and then 'rmmod cifs'. A few seconds later, the deadlock/lockdep warning shows up. Fix: We shouldn't mess with socket internals ourselves, so do not set sk_net_refcnt manually. Also change __sock_create() to sock_create_kern() for explicitness. As for non-init_net network namespaces, we deal with it the best way we can -- hold an extra netns reference for server->ssocket and drop it when it's released. This ensures that the netns still exists whenever we need to create/destroy server->ssocket, but is not directly tied to it. Fixes: ef7134c ("smb: client: Fix use-after-free of network namespace.") Cc: stable@vger.kernel.org Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent ee1c8e6 commit e9f2517

File tree

1 file changed

+26
-10
lines changed

1 file changed

+26
-10
lines changed

fs/smb/client/connect.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -987,9 +987,13 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
987987
msleep(125);
988988
if (cifs_rdma_enabled(server))
989989
smbd_destroy(server);
990+
990991
if (server->ssocket) {
991992
sock_release(server->ssocket);
992993
server->ssocket = NULL;
994+
995+
/* Release netns reference for the socket. */
996+
put_net(cifs_net_ns(server));
993997
}
994998

995999
if (!list_empty(&server->pending_mid_q)) {
@@ -1037,6 +1041,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
10371041
*/
10381042
}
10391043

1044+
/* Release netns reference for this server. */
10401045
put_net(cifs_net_ns(server));
10411046
kfree(server->leaf_fullpath);
10421047
kfree(server);
@@ -1713,6 +1718,8 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
17131718

17141719
tcp_ses->ops = ctx->ops;
17151720
tcp_ses->vals = ctx->vals;
1721+
1722+
/* Grab netns reference for this server. */
17161723
cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
17171724

17181725
tcp_ses->conn_id = atomic_inc_return(&tcpSesNextId);
@@ -1844,6 +1851,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
18441851
out_err_crypto_release:
18451852
cifs_crypto_secmech_release(tcp_ses);
18461853

1854+
/* Release netns reference for this server. */
18471855
put_net(cifs_net_ns(tcp_ses));
18481856

18491857
out_err:
@@ -1852,8 +1860,10 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
18521860
cifs_put_tcp_session(tcp_ses->primary_server, false);
18531861
kfree(tcp_ses->hostname);
18541862
kfree(tcp_ses->leaf_fullpath);
1855-
if (tcp_ses->ssocket)
1863+
if (tcp_ses->ssocket) {
18561864
sock_release(tcp_ses->ssocket);
1865+
put_net(cifs_net_ns(tcp_ses));
1866+
}
18571867
kfree(tcp_ses);
18581868
}
18591869
return ERR_PTR(rc);
@@ -3131,20 +3141,20 @@ generic_ip_connect(struct TCP_Server_Info *server)
31313141
socket = server->ssocket;
31323142
} else {
31333143
struct net *net = cifs_net_ns(server);
3134-
struct sock *sk;
31353144

3136-
rc = __sock_create(net, sfamily, SOCK_STREAM,
3137-
IPPROTO_TCP, &server->ssocket, 1);
3145+
rc = sock_create_kern(net, sfamily, SOCK_STREAM, IPPROTO_TCP, &server->ssocket);
31383146
if (rc < 0) {
31393147
cifs_server_dbg(VFS, "Error %d creating socket\n", rc);
31403148
return rc;
31413149
}
31423150

3143-
sk = server->ssocket->sk;
3144-
__netns_tracker_free(net, &sk->ns_tracker, false);
3145-
sk->sk_net_refcnt = 1;
3146-
get_net_track(net, &sk->ns_tracker, GFP_KERNEL);
3147-
sock_inuse_add(net, 1);
3151+
/*
3152+
* Grab netns reference for the socket.
3153+
*
3154+
* It'll be released here, on error, or in clean_demultiplex_info() upon server
3155+
* teardown.
3156+
*/
3157+
get_net(net);
31483158

31493159
/* BB other socket options to set KEEPALIVE, NODELAY? */
31503160
cifs_dbg(FYI, "Socket created\n");
@@ -3158,8 +3168,10 @@ generic_ip_connect(struct TCP_Server_Info *server)
31583168
}
31593169

31603170
rc = bind_socket(server);
3161-
if (rc < 0)
3171+
if (rc < 0) {
3172+
put_net(cifs_net_ns(server));
31623173
return rc;
3174+
}
31633175

31643176
/*
31653177
* Eventually check for other socket options to change from
@@ -3196,6 +3208,7 @@ generic_ip_connect(struct TCP_Server_Info *server)
31963208
if (rc < 0) {
31973209
cifs_dbg(FYI, "Error %d connecting to server\n", rc);
31983210
trace_smb3_connect_err(server->hostname, server->conn_id, &server->dstaddr, rc);
3211+
put_net(cifs_net_ns(server));
31993212
sock_release(socket);
32003213
server->ssocket = NULL;
32013214
return rc;
@@ -3204,6 +3217,9 @@ generic_ip_connect(struct TCP_Server_Info *server)
32043217
if (sport == htons(RFC1001_PORT))
32053218
rc = ip_rfc1001_connect(server);
32063219

3220+
if (rc < 0)
3221+
put_net(cifs_net_ns(server));
3222+
32073223
return rc;
32083224
}
32093225

0 commit comments

Comments
 (0)