mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
ksmbd: fix out of bounds in init_smb2_rsp_hdr()
[ Upstream commit 536bb492d3 ]
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: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
99a2426b13
commit
330d900620
@@ -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)
|
|||||||
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] = {
|
|||||||
[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)
|
||||||
|
return -EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (proto == SMB1_PROTO_NUMBER)
|
if (proto == SMB1_PROTO_NUMBER)
|
||||||
init_smb1_server(conn);
|
return init_smb1_server(conn);
|
||||||
else
|
return init_smb3_11_server(conn);
|
||||||
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);
|
|||||||
|
|
||||||
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,
|
||||||
|
|||||||
Reference in New Issue
Block a user