Skip to content

Commit 0a77d94

Browse files
committed
ksmbd: check outstanding simultaneous SMB operations
If Client send simultaneous SMB operations to ksmbd, It exhausts too much memory through the "ksmbd_work_cache”. It will cause OOM issue. ksmbd has a credit mechanism but it can't handle this problem. This patch add the check if it exceeds max credits to prevent this problem by assuming that one smb request consumes at least one credit. Cc: [email protected] # v5.15+ Reported-by: Norbert Szetei <[email protected]> Tested-by: Norbert Szetei <[email protected]> Signed-off-by: Namjae Jeon <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent b8fc56f commit 0a77d94

File tree

5 files changed

+20
-10
lines changed

5 files changed

+20
-10
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/server.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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)