Skip to content

Commit 1eb714c

Browse files
committed
Merge tag 'v6.12-rc6-ksmbd-fixes' of git://git.samba.org/ksmbd
Pull smb server fixes from Steve French: "Four fixes, all also marked for stable: - fix two potential use after free issues - fix OOM issue with many simultaneous requests - fix missing error check in RPC pipe handling" * tag 'v6.12-rc6-ksmbd-fixes' of git://git.samba.org/ksmbd: ksmbd: check outstanding simultaneous SMB operations ksmbd: fix slab-use-after-free in smb3_preauth_hash_rsp ksmbd: fix slab-use-after-free in ksmbd_smb2_session_create ksmbd: Fix the missing xa_store error check
2 parents c291c9c + 0a77d94 commit 1eb714c

File tree

6 files changed

+32
-17
lines changed

6 files changed

+32
-17
lines changed

fs/smb/server/connection.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
7070
atomic_set(&conn->req_running, 0);
7171
atomic_set(&conn->r_count, 0);
7272
atomic_set(&conn->refcnt, 1);
73+
atomic_set(&conn->mux_smb_requests, 0);
7374
conn->total_credits = 1;
7475
conn->outstanding_credits = 0;
7576

fs/smb/server/connection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ struct ksmbd_conn {
107107
__le16 signing_algorithm;
108108
bool binding;
109109
atomic_t refcnt;
110+
atomic_t mux_smb_requests;
110111
};
111112

112113
struct ksmbd_conn_ops {

fs/smb/server/mgmt/user_session.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ static int __rpc_method(char *rpc_name)
9090

9191
int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
9292
{
93-
struct ksmbd_session_rpc *entry;
93+
struct ksmbd_session_rpc *entry, *old;
9494
struct ksmbd_rpc_command *resp;
9595
int method;
9696

@@ -106,16 +106,19 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
106106
entry->id = ksmbd_ipc_id_alloc();
107107
if (entry->id < 0)
108108
goto free_entry;
109-
xa_store(&sess->rpc_handle_list, entry->id, entry, GFP_KERNEL);
109+
old = xa_store(&sess->rpc_handle_list, entry->id, entry, GFP_KERNEL);
110+
if (xa_is_err(old))
111+
goto free_id;
110112

111113
resp = ksmbd_rpc_open(sess, entry->id);
112114
if (!resp)
113-
goto free_id;
115+
goto erase_xa;
114116

115117
kvfree(resp);
116118
return entry->id;
117-
free_id:
119+
erase_xa:
118120
xa_erase(&sess->rpc_handle_list, entry->id);
121+
free_id:
119122
ksmbd_rpc_id_free(entry->id);
120123
free_entry:
121124
kfree(entry);
@@ -175,6 +178,7 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn)
175178
unsigned long id;
176179
struct ksmbd_session *sess;
177180

181+
down_write(&sessions_table_lock);
178182
down_write(&conn->session_lock);
179183
xa_for_each(&conn->sessions, id, sess) {
180184
if (atomic_read(&sess->refcnt) == 0 &&
@@ -188,6 +192,7 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn)
188192
}
189193
}
190194
up_write(&conn->session_lock);
195+
up_write(&sessions_table_lock);
191196
}
192197

193198
int ksmbd_session_register(struct ksmbd_conn *conn,
@@ -229,7 +234,6 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
229234
}
230235
}
231236
}
232-
up_write(&sessions_table_lock);
233237

234238
down_write(&conn->session_lock);
235239
xa_for_each(&conn->sessions, id, sess) {
@@ -249,6 +253,7 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
249253
}
250254
}
251255
up_write(&conn->session_lock);
256+
up_write(&sessions_table_lock);
252257
}
253258

254259
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,

fs/smb/server/server.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,11 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
238238
} while (is_chained == true);
239239

240240
send:
241-
if (work->sess)
242-
ksmbd_user_session_put(work->sess);
243241
if (work->tcon)
244242
ksmbd_tree_connect_put(work->tcon);
245243
smb3_preauth_hash_rsp(work);
244+
if (work->sess)
245+
ksmbd_user_session_put(work->sess);
246246
if (work->sess && work->sess->enc && work->encrypted &&
247247
conn->ops->encrypt_resp) {
248248
rc = conn->ops->encrypt_resp(work);
@@ -270,6 +270,7 @@ static void handle_ksmbd_work(struct work_struct *wk)
270270

271271
ksmbd_conn_try_dequeue_request(work);
272272
ksmbd_free_work_struct(work);
273+
atomic_dec(&conn->mux_smb_requests);
273274
/*
274275
* Checking waitqueue to dropping pending requests on
275276
* disconnection. waitqueue_active is safe because it
@@ -291,6 +292,15 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
291292
struct ksmbd_work *work;
292293
int err;
293294

295+
err = ksmbd_init_smb_server(conn);
296+
if (err)
297+
return 0;
298+
299+
if (atomic_inc_return(&conn->mux_smb_requests) >= conn->vals->max_credits) {
300+
atomic_dec_return(&conn->mux_smb_requests);
301+
return -ENOSPC;
302+
}
303+
294304
work = ksmbd_alloc_work_struct();
295305
if (!work) {
296306
pr_err("allocation for work failed\n");
@@ -301,12 +311,6 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
301311
work->request_buf = conn->request_buf;
302312
conn->request_buf = NULL;
303313

304-
err = ksmbd_init_smb_server(work);
305-
if (err) {
306-
ksmbd_free_work_struct(work);
307-
return 0;
308-
}
309-
310314
ksmbd_conn_enqueue_request(work);
311315
atomic_inc(&conn->r_count);
312316
/* update activity on connection */

fs/smb/server/smb_common.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,10 @@ static struct smb_version_ops smb1_server_ops = {
388388
.set_rsp_status = set_smb1_rsp_status,
389389
};
390390

391+
static struct smb_version_values smb1_server_values = {
392+
.max_credits = SMB2_MAX_CREDITS,
393+
};
394+
391395
static int smb1_negotiate(struct ksmbd_work *work)
392396
{
393397
return ksmbd_smb_negotiate_common(work, SMB_COM_NEGOTIATE);
@@ -399,18 +403,18 @@ static struct smb_version_cmds smb1_server_cmds[1] = {
399403

400404
static int init_smb1_server(struct ksmbd_conn *conn)
401405
{
406+
conn->vals = &smb1_server_values;
402407
conn->ops = &smb1_server_ops;
403408
conn->cmds = smb1_server_cmds;
404409
conn->max_cmds = ARRAY_SIZE(smb1_server_cmds);
405410
return 0;
406411
}
407412

408-
int ksmbd_init_smb_server(struct ksmbd_work *work)
413+
int ksmbd_init_smb_server(struct ksmbd_conn *conn)
409414
{
410-
struct ksmbd_conn *conn = work->conn;
411415
__le32 proto;
412416

413-
proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol;
417+
proto = *(__le32 *)((struct smb_hdr *)conn->request_buf)->Protocol;
414418
if (conn->need_neg == false) {
415419
if (proto == SMB1_PROTO_NUMBER)
416420
return -EINVAL;

fs/smb/server/smb_common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ bool ksmbd_smb_request(struct ksmbd_conn *conn);
427427

428428
int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count);
429429

430-
int ksmbd_init_smb_server(struct ksmbd_work *work);
430+
int ksmbd_init_smb_server(struct ksmbd_conn *conn);
431431

432432
struct ksmbd_kstat;
433433
int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work,

0 commit comments

Comments
 (0)