Merge tag '6.17-rc2-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - fix refcount issue that can cause memory leak

 - rate limit repeated connections from IPv6, not just IPv4 addresses

 - fix potential null pointer access of smb direct work queue

* tag '6.17-rc2-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: fix refcount leak causing resource not released
  ksmbd: extend the connection limiting mechanism to support IPv6
  smb: server: split ksmbd_rdma_stop_listening() out of ksmbd_rdma_destroy()
This commit is contained in:
Linus Torvalds
2025-08-21 04:48:41 -07:00
6 changed files with 48 additions and 10 deletions

View File

@@ -504,7 +504,8 @@ void ksmbd_conn_transport_destroy(void)
{
mutex_lock(&init_lock);
ksmbd_tcp_destroy();
ksmbd_rdma_destroy();
ksmbd_rdma_stop_listening();
stop_sessions();
ksmbd_rdma_destroy();
mutex_unlock(&init_lock);
}

View File

@@ -46,7 +46,12 @@ struct ksmbd_conn {
struct mutex srv_mutex;
int status;
unsigned int cli_cap;
__be32 inet_addr;
union {
__be32 inet_addr;
#if IS_ENABLED(CONFIG_IPV6)
u8 inet6_addr[16];
#endif
};
char *request_buf;
struct ksmbd_transport *transport;
struct nls_table *local_nls;

View File

@@ -1102,8 +1102,10 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
if (!atomic_inc_not_zero(&opinfo->refcount))
continue;
if (ksmbd_conn_releasing(opinfo->conn))
if (ksmbd_conn_releasing(opinfo->conn)) {
opinfo_put(opinfo);
continue;
}
oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE, NULL);
opinfo_put(opinfo);
@@ -1139,8 +1141,11 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
if (!atomic_inc_not_zero(&opinfo->refcount))
continue;
if (ksmbd_conn_releasing(opinfo->conn))
if (ksmbd_conn_releasing(opinfo->conn)) {
opinfo_put(opinfo);
continue;
}
oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE, NULL);
opinfo_put(opinfo);
}
@@ -1343,8 +1348,10 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
if (!atomic_inc_not_zero(&brk_op->refcount))
continue;
if (ksmbd_conn_releasing(brk_op->conn))
if (ksmbd_conn_releasing(brk_op->conn)) {
opinfo_put(brk_op);
continue;
}
if (brk_op->is_lease && (brk_op->o_lease->state &
(~(SMB2_LEASE_READ_CACHING_LE |

View File

@@ -2194,7 +2194,7 @@ int ksmbd_rdma_init(void)
return 0;
}
void ksmbd_rdma_destroy(void)
void ksmbd_rdma_stop_listening(void)
{
if (!smb_direct_listener.cm_id)
return;
@@ -2203,7 +2203,10 @@ void ksmbd_rdma_destroy(void)
rdma_destroy_id(smb_direct_listener.cm_id);
smb_direct_listener.cm_id = NULL;
}
void ksmbd_rdma_destroy(void)
{
if (smb_direct_wq) {
destroy_workqueue(smb_direct_wq);
smb_direct_wq = NULL;

View File

@@ -54,13 +54,15 @@ struct smb_direct_data_transfer {
#ifdef CONFIG_SMB_SERVER_SMBDIRECT
int ksmbd_rdma_init(void);
void ksmbd_rdma_stop_listening(void);
void ksmbd_rdma_destroy(void);
bool ksmbd_rdma_capable_netdev(struct net_device *netdev);
void init_smbd_max_io_size(unsigned int sz);
unsigned int get_smbd_max_read_write_size(void);
#else
static inline int ksmbd_rdma_init(void) { return 0; }
static inline int ksmbd_rdma_destroy(void) { return 0; }
static inline void ksmbd_rdma_stop_listening(void) { }
static inline void ksmbd_rdma_destroy(void) { }
static inline bool ksmbd_rdma_capable_netdev(struct net_device *netdev) { return false; }
static inline void init_smbd_max_io_size(unsigned int sz) { }
static inline unsigned int get_smbd_max_read_write_size(void) { return 0; }

View File

@@ -85,7 +85,14 @@ static struct tcp_transport *alloc_transport(struct socket *client_sk)
return NULL;
}
#if IS_ENABLED(CONFIG_IPV6)
if (client_sk->sk->sk_family == AF_INET6)
memcpy(&conn->inet6_addr, &client_sk->sk->sk_v6_daddr, 16);
else
conn->inet_addr = inet_sk(client_sk->sk)->inet_daddr;
#else
conn->inet_addr = inet_sk(client_sk->sk)->inet_daddr;
#endif
conn->transport = KSMBD_TRANS(t);
KSMBD_TRANS(t)->conn = conn;
KSMBD_TRANS(t)->ops = &ksmbd_tcp_transport_ops;
@@ -229,7 +236,6 @@ static int ksmbd_kthread_fn(void *p)
{
struct socket *client_sk = NULL;
struct interface *iface = (struct interface *)p;
struct inet_sock *csk_inet;
struct ksmbd_conn *conn;
int ret;
@@ -252,13 +258,27 @@ static int ksmbd_kthread_fn(void *p)
/*
* Limits repeated connections from clients with the same IP.
*/
csk_inet = inet_sk(client_sk->sk);
down_read(&conn_list_lock);
list_for_each_entry(conn, &conn_list, conns_list)
if (csk_inet->inet_daddr == conn->inet_addr) {
#if IS_ENABLED(CONFIG_IPV6)
if (client_sk->sk->sk_family == AF_INET6) {
if (memcmp(&client_sk->sk->sk_v6_daddr,
&conn->inet6_addr, 16) == 0) {
ret = -EAGAIN;
break;
}
} else if (inet_sk(client_sk->sk)->inet_daddr ==
conn->inet_addr) {
ret = -EAGAIN;
break;
}
#else
if (inet_sk(client_sk->sk)->inet_daddr ==
conn->inet_addr) {
ret = -EAGAIN;
break;
}
#endif
up_read(&conn_list_lock);
if (ret == -EAGAIN)
continue;