Skip to content

Commit b3fee71

Browse files
committed
Merge tag 'v6.18rc1-part1-ksmbd-server-fixes' of git://git.samba.org/ksmbd
Pull smb server fixes from Steve French: - Fix potential UAFs and corruptions in rpc open and close - Fix copy_file_range when ranges overlap - Improve session, share, connection lookup performance - Fix potential hash collisions in share and session lists - Debugging improvement - making per-connection threads easier to identify - Improve socket creation - Fix return code mapping for posix query fs info - Add support for limiting the maximum number of connections per IP address, extending the existing connection limiting mechanism to enforce per-IP connection limits alongside the global connection limit * tag 'v6.18rc1-part1-ksmbd-server-fixes' of git://git.samba.org/ksmbd: ksmbd: increase session and share hash table bits ksmbd: replace connection list with hash table ksmbd: add an error print when maximum IP connections limit is reached ksmbd: add max ip connections parameter ksmbd: fix error code overwriting in smb2_get_info_filesystem() ksmbd: copy overlapped range within the same file ksmbd: use sock_create_kern interface to create kernel socket ksmbd: make ksmbd thread names distinct by client IP ksmbd: Fix race condition in RPC handle list access
2 parents 86d563a + e28c5bc commit b3fee71

File tree

11 files changed

+119
-75
lines changed

11 files changed

+119
-75
lines changed

fs/smb/server/connection.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ static DEFINE_MUTEX(init_lock);
1919

2020
static struct ksmbd_conn_ops default_conn_ops;
2121

22-
LIST_HEAD(conn_list);
22+
DEFINE_HASHTABLE(conn_list, CONN_HASH_BITS);
2323
DECLARE_RWSEM(conn_list_lock);
2424

2525
/**
@@ -33,7 +33,7 @@ DECLARE_RWSEM(conn_list_lock);
3333
void ksmbd_conn_free(struct ksmbd_conn *conn)
3434
{
3535
down_write(&conn_list_lock);
36-
list_del(&conn->conns_list);
36+
hash_del(&conn->hlist);
3737
up_write(&conn_list_lock);
3838

3939
xa_destroy(&conn->sessions);
@@ -77,7 +77,6 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
7777

7878
init_waitqueue_head(&conn->req_running_q);
7979
init_waitqueue_head(&conn->r_count_q);
80-
INIT_LIST_HEAD(&conn->conns_list);
8180
INIT_LIST_HEAD(&conn->requests);
8281
INIT_LIST_HEAD(&conn->async_requests);
8382
spin_lock_init(&conn->request_lock);
@@ -90,19 +89,17 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
9089

9190
init_rwsem(&conn->session_lock);
9291

93-
down_write(&conn_list_lock);
94-
list_add(&conn->conns_list, &conn_list);
95-
up_write(&conn_list_lock);
9692
return conn;
9793
}
9894

9995
bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c)
10096
{
10197
struct ksmbd_conn *t;
98+
int bkt;
10299
bool ret = false;
103100

104101
down_read(&conn_list_lock);
105-
list_for_each_entry(t, &conn_list, conns_list) {
102+
hash_for_each(conn_list, bkt, t, hlist) {
106103
if (memcmp(t->ClientGUID, c->ClientGUID, SMB2_CLIENT_GUID_SIZE))
107104
continue;
108105

@@ -163,9 +160,10 @@ void ksmbd_conn_unlock(struct ksmbd_conn *conn)
163160
void ksmbd_all_conn_set_status(u64 sess_id, u32 status)
164161
{
165162
struct ksmbd_conn *conn;
163+
int bkt;
166164

167165
down_read(&conn_list_lock);
168-
list_for_each_entry(conn, &conn_list, conns_list) {
166+
hash_for_each(conn_list, bkt, conn, hlist) {
169167
if (conn->binding || xa_load(&conn->sessions, sess_id))
170168
WRITE_ONCE(conn->status, status);
171169
}
@@ -181,14 +179,14 @@ int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id)
181179
{
182180
struct ksmbd_conn *conn;
183181
int rc, retry_count = 0, max_timeout = 120;
184-
int rcount = 1;
182+
int rcount = 1, bkt;
185183

186184
retry_idle:
187185
if (retry_count >= max_timeout)
188186
return -EIO;
189187

190188
down_read(&conn_list_lock);
191-
list_for_each_entry(conn, &conn_list, conns_list) {
189+
hash_for_each(conn_list, bkt, conn, hlist) {
192190
if (conn->binding || xa_load(&conn->sessions, sess_id)) {
193191
if (conn == curr_conn)
194192
rcount = 2;
@@ -480,10 +478,11 @@ static void stop_sessions(void)
480478
{
481479
struct ksmbd_conn *conn;
482480
struct ksmbd_transport *t;
481+
int bkt;
483482

484483
again:
485484
down_read(&conn_list_lock);
486-
list_for_each_entry(conn, &conn_list, conns_list) {
485+
hash_for_each(conn_list, bkt, conn, hlist) {
487486
t = conn->transport;
488487
ksmbd_conn_set_exiting(conn);
489488
if (t->ops->shutdown) {
@@ -494,7 +493,7 @@ static void stop_sessions(void)
494493
}
495494
up_read(&conn_list_lock);
496495

497-
if (!list_empty(&conn_list)) {
496+
if (!hash_empty(conn_list)) {
498497
msleep(100);
499498
goto again;
500499
}

fs/smb/server/connection.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,12 @@ struct ksmbd_conn {
5454
u8 inet6_addr[16];
5555
#endif
5656
};
57+
unsigned int inet_hash;
5758
char *request_buf;
5859
struct ksmbd_transport *transport;
5960
struct nls_table *local_nls;
6061
struct unicode_map *um;
61-
struct list_head conns_list;
62+
struct hlist_node hlist;
6263
struct rw_semaphore session_lock;
6364
/* smb session 1 per user */
6465
struct xarray sessions;
@@ -153,7 +154,8 @@ struct ksmbd_transport {
153154
#define KSMBD_TCP_SEND_TIMEOUT (5 * HZ)
154155
#define KSMBD_TCP_PEER_SOCKADDR(c) ((struct sockaddr *)&((c)->peer_addr))
155156

156-
extern struct list_head conn_list;
157+
#define CONN_HASH_BITS 12
158+
extern DECLARE_HASHTABLE(conn_list, CONN_HASH_BITS);
157159
extern struct rw_semaphore conn_list_lock;
158160

159161
bool ksmbd_conn_alive(struct ksmbd_conn *conn);

fs/smb/server/ksmbd_netlink.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,11 @@ struct ksmbd_startup_request {
112112
__u32 smbd_max_io_size; /* smbd read write size */
113113
__u32 max_connections; /* Number of maximum simultaneous connections */
114114
__s8 bind_interfaces_only;
115-
__s8 reserved[503]; /* Reserved room */
115+
__u32 max_ip_connections; /* Number of maximum connection per ip address */
116+
__s8 reserved[499]; /* Reserved room */
116117
__u32 ifc_list_sz; /* interfaces list size */
117118
__s8 ____payload[];
118-
};
119+
} __packed;
119120

120121
#define KSMBD_STARTUP_CONFIG_INTERFACES(s) ((s)->____payload)
121122

fs/smb/server/mgmt/share_config.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#include "../transport_ipc.h"
2020
#include "../misc.h"
2121

22-
#define SHARE_HASH_BITS 3
22+
#define SHARE_HASH_BITS 12
2323
static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS);
2424
static DECLARE_RWSEM(shares_table_lock);
2525

fs/smb/server/mgmt/user_session.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
static DEFINE_IDA(session_ida);
2020

21-
#define SESSION_HASH_BITS 3
21+
#define SESSION_HASH_BITS 12
2222
static DEFINE_HASHTABLE(sessions_table, SESSION_HASH_BITS);
2323
static DECLARE_RWSEM(sessions_table_lock);
2424

@@ -104,29 +104,32 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
104104
if (!entry)
105105
return -ENOMEM;
106106

107-
down_read(&sess->rpc_lock);
108107
entry->method = method;
109108
entry->id = id = ksmbd_ipc_id_alloc();
110109
if (id < 0)
111110
goto free_entry;
111+
112+
down_write(&sess->rpc_lock);
112113
old = xa_store(&sess->rpc_handle_list, id, entry, KSMBD_DEFAULT_GFP);
113-
if (xa_is_err(old))
114+
if (xa_is_err(old)) {
115+
up_write(&sess->rpc_lock);
114116
goto free_id;
117+
}
115118

116119
resp = ksmbd_rpc_open(sess, id);
117-
if (!resp)
118-
goto erase_xa;
120+
if (!resp) {
121+
xa_erase(&sess->rpc_handle_list, entry->id);
122+
up_write(&sess->rpc_lock);
123+
goto free_id;
124+
}
119125

120-
up_read(&sess->rpc_lock);
126+
up_write(&sess->rpc_lock);
121127
kvfree(resp);
122128
return id;
123-
erase_xa:
124-
xa_erase(&sess->rpc_handle_list, entry->id);
125129
free_id:
126130
ksmbd_rpc_id_free(entry->id);
127131
free_entry:
128132
kfree(entry);
129-
up_read(&sess->rpc_lock);
130133
return -EINVAL;
131134
}
132135

@@ -144,9 +147,14 @@ void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id)
144147
int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
145148
{
146149
struct ksmbd_session_rpc *entry;
150+
int method;
147151

152+
down_read(&sess->rpc_lock);
148153
entry = xa_load(&sess->rpc_handle_list, id);
149-
return entry ? entry->method : 0;
154+
method = entry ? entry->method : 0;
155+
up_read(&sess->rpc_lock);
156+
157+
return method;
150158
}
151159

152160
void ksmbd_session_destroy(struct ksmbd_session *sess)

fs/smb/server/server.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct ksmbd_server_config {
4343
unsigned int auth_mechs;
4444
unsigned int max_connections;
4545
unsigned int max_inflight_req;
46+
unsigned int max_ip_connections;
4647

4748
char *conf[SERVER_CONF_WORK_GROUP + 1];
4849
struct task_struct *dh_task;

fs/smb/server/smb2pdu.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5629,7 +5629,8 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
56295629

56305630
if (!work->tcon->posix_extensions) {
56315631
pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n");
5632-
rc = -EOPNOTSUPP;
5632+
path_put(&path);
5633+
return -EOPNOTSUPP;
56335634
} else {
56345635
info = (struct filesystem_posix_info *)(rsp->Buffer);
56355636
info->OptimalTransferSize = cpu_to_le32(stfs.f_bsize);
@@ -7361,7 +7362,7 @@ int smb2_lock(struct ksmbd_work *work)
73617362
int nolock = 0;
73627363
LIST_HEAD(lock_list);
73637364
LIST_HEAD(rollback_list);
7364-
int prior_lock = 0;
7365+
int prior_lock = 0, bkt;
73657366

73667367
WORK_BUFFERS(work, req, rsp);
73677368

@@ -7471,7 +7472,7 @@ int smb2_lock(struct ksmbd_work *work)
74717472
nolock = 1;
74727473
/* check locks in connection list */
74737474
down_read(&conn_list_lock);
7474-
list_for_each_entry(conn, &conn_list, conns_list) {
7475+
hash_for_each(conn_list, bkt, conn, hlist) {
74757476
spin_lock(&conn->llist_lock);
74767477
list_for_each_entry_safe(cmp_lock, tmp2, &conn->lock_list, clist) {
74777478
if (file_inode(cmp_lock->fl->c.flc_file) !=

fs/smb/server/transport_ipc.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,9 @@ static int ipc_server_config_on_startup(struct ksmbd_startup_request *req)
335335
if (req->max_connections)
336336
server_conf.max_connections = req->max_connections;
337337

338+
if (req->max_ip_connections)
339+
server_conf.max_ip_connections = req->max_ip_connections;
340+
338341
ret = ksmbd_set_netbios_name(req->netbios_name);
339342
ret |= ksmbd_set_server_string(req->server_string);
340343
ret |= ksmbd_set_work_group(req->work_group);

fs/smb/server/transport_rdma.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,11 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id)
425425
conn = ksmbd_conn_alloc();
426426
if (!conn)
427427
goto err;
428+
429+
down_write(&conn_list_lock);
430+
hash_add(conn_list, &conn->hlist, 0);
431+
up_write(&conn_list_lock);
432+
428433
conn->transport = KSMBD_TRANS(t);
429434
KSMBD_TRANS(t)->conn = conn;
430435
KSMBD_TRANS(t)->ops = &ksmbd_smb_direct_transport_ops;

0 commit comments

Comments
 (0)