Commit 536bb492 authored by Namjae Jeon's avatar Namjae Jeon Committed by Steve French

ksmbd: fix out of bounds in init_smb2_rsp_hdr()

If client send smb2 negotiate request and then send smb1 negotiate
request, init_smb2_rsp_hdr is called for smb1 negotiate request since
need_neg is set to false. This patch ignore smb1 packets after ->need_neg
is set to false.

Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-21541
Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent e202a1e8
...@@ -286,6 +286,7 @@ static void handle_ksmbd_work(struct work_struct *wk) ...@@ -286,6 +286,7 @@ static void handle_ksmbd_work(struct work_struct *wk)
static int queue_ksmbd_work(struct ksmbd_conn *conn) static int queue_ksmbd_work(struct ksmbd_conn *conn)
{ {
struct ksmbd_work *work; struct ksmbd_work *work;
int err;
work = ksmbd_alloc_work_struct(); work = ksmbd_alloc_work_struct();
if (!work) { if (!work) {
...@@ -297,7 +298,11 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn) ...@@ -297,7 +298,11 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
work->request_buf = conn->request_buf; work->request_buf = conn->request_buf;
conn->request_buf = NULL; conn->request_buf = NULL;
ksmbd_init_smb_server(work); err = ksmbd_init_smb_server(work);
if (err) {
ksmbd_free_work_struct(work);
return 0;
}
ksmbd_conn_enqueue_request(work); ksmbd_conn_enqueue_request(work);
atomic_inc(&conn->r_count); atomic_inc(&conn->r_count);
......
...@@ -388,26 +388,29 @@ static struct smb_version_cmds smb1_server_cmds[1] = { ...@@ -388,26 +388,29 @@ static struct smb_version_cmds smb1_server_cmds[1] = {
[SMB_COM_NEGOTIATE_EX] = { .proc = smb1_negotiate, }, [SMB_COM_NEGOTIATE_EX] = { .proc = smb1_negotiate, },
}; };
static void init_smb1_server(struct ksmbd_conn *conn) static int init_smb1_server(struct ksmbd_conn *conn)
{ {
conn->ops = &smb1_server_ops; conn->ops = &smb1_server_ops;
conn->cmds = smb1_server_cmds; conn->cmds = smb1_server_cmds;
conn->max_cmds = ARRAY_SIZE(smb1_server_cmds); conn->max_cmds = ARRAY_SIZE(smb1_server_cmds);
return 0;
} }
void ksmbd_init_smb_server(struct ksmbd_work *work) int ksmbd_init_smb_server(struct ksmbd_work *work)
{ {
struct ksmbd_conn *conn = work->conn; struct ksmbd_conn *conn = work->conn;
__le32 proto; __le32 proto;
if (conn->need_neg == false)
return;
proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol; proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol;
if (conn->need_neg == false) {
if (proto == SMB1_PROTO_NUMBER) if (proto == SMB1_PROTO_NUMBER)
init_smb1_server(conn); return -EINVAL;
else return 0;
init_smb3_11_server(conn); }
if (proto == SMB1_PROTO_NUMBER)
return init_smb1_server(conn);
return init_smb3_11_server(conn);
} }
int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level, int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level,
......
...@@ -427,7 +427,7 @@ bool ksmbd_smb_request(struct ksmbd_conn *conn); ...@@ -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_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count);
void ksmbd_init_smb_server(struct ksmbd_work *work); int ksmbd_init_smb_server(struct ksmbd_work *work);
struct ksmbd_kstat; struct ksmbd_kstat;
int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment