Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ksmbd: fix use-after-free in __smb2_lease_break_noti()

Move tcp_transport free to ksmbd_conn_free. If ksmbd connection is
referenced when ksmbd server thread terminates, It will not be freed,
but conn->tcp_transport is freed. __smb2_lease_break_noti can be performed
asynchronously when the connection is disconnected. __smb2_lease_break_noti
calls ksmbd_conn_write, which can cause use-after-free
when conn->ksmbd_transport is already freed.

Cc: stable@vger.kernel.org
Reported-by: Norbert Szetei <norbert@doyensec.com>
Tested-by: Norbert Szetei <norbert@doyensec.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by

Namjae Jeon and committed by
Steve French
21a4e475 1df0d4c6

+13 -6
+3 -1
fs/smb/server/connection.c
··· 39 39 xa_destroy(&conn->sessions); 40 40 kvfree(conn->request_buf); 41 41 kfree(conn->preauth_info); 42 - if (atomic_dec_and_test(&conn->refcnt)) 42 + if (atomic_dec_and_test(&conn->refcnt)) { 43 + ksmbd_free_transport(conn->transport); 43 44 kfree(conn); 45 + } 44 46 } 45 47 46 48 /**
+9 -5
fs/smb/server/transport_tcp.c
··· 93 93 return t; 94 94 } 95 95 96 + void ksmbd_free_transport(struct ksmbd_transport *kt) 97 + { 98 + struct tcp_transport *t = TCP_TRANS(kt); 99 + 100 + sock_release(t->sock); 101 + kfree(t->iov); 102 + kfree(t); 103 + } 104 + 96 105 static void free_transport(struct tcp_transport *t) 97 106 { 98 107 kernel_sock_shutdown(t->sock, SHUT_RDWR); 99 - sock_release(t->sock); 100 - t->sock = NULL; 101 - 102 108 ksmbd_conn_free(KSMBD_TRANS(t)->conn); 103 - kfree(t->iov); 104 - kfree(t); 105 109 } 106 110 107 111 /**
+1
fs/smb/server/transport_tcp.h
··· 8 8 9 9 int ksmbd_tcp_set_interfaces(char *ifc_list, int ifc_list_sz); 10 10 struct interface *ksmbd_find_netdev_name_iface_list(char *netdev_name); 11 + void ksmbd_free_transport(struct ksmbd_transport *kt); 11 12 int ksmbd_tcp_init(void); 12 13 void ksmbd_tcp_destroy(void); 13 14