mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
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: stable@vger.kernel.org # v5.15+ 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>
This commit is contained in:
parent
b8fc56fbca
commit
0a77d947f5
@ -70,6 +70,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
|
||||
atomic_set(&conn->req_running, 0);
|
||||
atomic_set(&conn->r_count, 0);
|
||||
atomic_set(&conn->refcnt, 1);
|
||||
atomic_set(&conn->mux_smb_requests, 0);
|
||||
conn->total_credits = 1;
|
||||
conn->outstanding_credits = 0;
|
||||
|
||||
|
@ -107,6 +107,7 @@ struct ksmbd_conn {
|
||||
__le16 signing_algorithm;
|
||||
bool binding;
|
||||
atomic_t refcnt;
|
||||
atomic_t mux_smb_requests;
|
||||
};
|
||||
|
||||
struct ksmbd_conn_ops {
|
||||
|
@ -270,6 +270,7 @@ static void handle_ksmbd_work(struct work_struct *wk)
|
||||
|
||||
ksmbd_conn_try_dequeue_request(work);
|
||||
ksmbd_free_work_struct(work);
|
||||
atomic_dec(&conn->mux_smb_requests);
|
||||
/*
|
||||
* Checking waitqueue to dropping pending requests on
|
||||
* disconnection. waitqueue_active is safe because it
|
||||
@ -291,6 +292,15 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
|
||||
struct ksmbd_work *work;
|
||||
int err;
|
||||
|
||||
err = ksmbd_init_smb_server(conn);
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
if (atomic_inc_return(&conn->mux_smb_requests) >= conn->vals->max_credits) {
|
||||
atomic_dec_return(&conn->mux_smb_requests);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
work = ksmbd_alloc_work_struct();
|
||||
if (!work) {
|
||||
pr_err("allocation for work failed\n");
|
||||
@ -301,12 +311,6 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
|
||||
work->request_buf = conn->request_buf;
|
||||
conn->request_buf = NULL;
|
||||
|
||||
err = ksmbd_init_smb_server(work);
|
||||
if (err) {
|
||||
ksmbd_free_work_struct(work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ksmbd_conn_enqueue_request(work);
|
||||
atomic_inc(&conn->r_count);
|
||||
/* update activity on connection */
|
||||
|
@ -388,6 +388,10 @@ static struct smb_version_ops smb1_server_ops = {
|
||||
.set_rsp_status = set_smb1_rsp_status,
|
||||
};
|
||||
|
||||
static struct smb_version_values smb1_server_values = {
|
||||
.max_credits = SMB2_MAX_CREDITS,
|
||||
};
|
||||
|
||||
static int smb1_negotiate(struct ksmbd_work *work)
|
||||
{
|
||||
return ksmbd_smb_negotiate_common(work, SMB_COM_NEGOTIATE);
|
||||
@ -399,18 +403,18 @@ static struct smb_version_cmds smb1_server_cmds[1] = {
|
||||
|
||||
static int init_smb1_server(struct ksmbd_conn *conn)
|
||||
{
|
||||
conn->vals = &smb1_server_values;
|
||||
conn->ops = &smb1_server_ops;
|
||||
conn->cmds = smb1_server_cmds;
|
||||
conn->max_cmds = ARRAY_SIZE(smb1_server_cmds);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksmbd_init_smb_server(struct ksmbd_work *work)
|
||||
int ksmbd_init_smb_server(struct ksmbd_conn *conn)
|
||||
{
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
__le32 proto;
|
||||
|
||||
proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol;
|
||||
proto = *(__le32 *)((struct smb_hdr *)conn->request_buf)->Protocol;
|
||||
if (conn->need_neg == false) {
|
||||
if (proto == SMB1_PROTO_NUMBER)
|
||||
return -EINVAL;
|
||||
|
@ -427,7 +427,7 @@ bool ksmbd_smb_request(struct ksmbd_conn *conn);
|
||||
|
||||
int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count);
|
||||
|
||||
int ksmbd_init_smb_server(struct ksmbd_work *work);
|
||||
int ksmbd_init_smb_server(struct ksmbd_conn *conn);
|
||||
|
||||
struct ksmbd_kstat;
|
||||
int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work,
|
||||
|
Loading…
Reference in New Issue
Block a user