]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/6.6.26/ksmbd-validate-payload-size-in-ipc-response.patch
Linux 6.6.26
[thirdparty/kernel/stable-queue.git] / releases / 6.6.26 / ksmbd-validate-payload-size-in-ipc-response.patch
CommitLineData
2ef6de7d
GKH
1From a677ebd8ca2f2632ccdecbad7b87641274e15aac Mon Sep 17 00:00:00 2001
2From: Namjae Jeon <linkinjeon@kernel.org>
3Date: Sun, 31 Mar 2024 21:59:10 +0900
4Subject: ksmbd: validate payload size in ipc response
5
6From: Namjae Jeon <linkinjeon@kernel.org>
7
8commit a677ebd8ca2f2632ccdecbad7b87641274e15aac upstream.
9
10If installing malicious ksmbd-tools, ksmbd.mountd can return invalid ipc
11response to ksmbd kernel server. ksmbd should validate payload size of
12ipc response from ksmbd.mountd to avoid memory overrun or
13slab-out-of-bounds. This patch validate 3 ipc response that has payload.
14
15Cc: stable@vger.kernel.org
16Reported-by: Chao Ma <machao2019@gmail.com>
17Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
18Signed-off-by: Steve French <stfrench@microsoft.com>
19Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
20---
21 fs/smb/server/ksmbd_netlink.h | 3 ++-
22 fs/smb/server/mgmt/share_config.c | 7 ++++++-
23 fs/smb/server/transport_ipc.c | 37 +++++++++++++++++++++++++++++++++++++
24 3 files changed, 45 insertions(+), 2 deletions(-)
25
26--- a/fs/smb/server/ksmbd_netlink.h
27+++ b/fs/smb/server/ksmbd_netlink.h
28@@ -166,7 +166,8 @@ struct ksmbd_share_config_response {
29 __u16 force_uid;
30 __u16 force_gid;
31 __s8 share_name[KSMBD_REQ_MAX_SHARE_NAME];
32- __u32 reserved[112]; /* Reserved room */
33+ __u32 reserved[111]; /* Reserved room */
34+ __u32 payload_sz;
35 __u32 veto_list_sz;
36 __s8 ____payload[];
37 };
38--- a/fs/smb/server/mgmt/share_config.c
39+++ b/fs/smb/server/mgmt/share_config.c
40@@ -158,7 +158,12 @@ static struct ksmbd_share_config *share_
41 share->name = kstrdup(name, GFP_KERNEL);
42
43 if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
44- share->path = kstrdup(ksmbd_share_config_path(resp),
45+ int path_len = PATH_MAX;
46+
47+ if (resp->payload_sz)
48+ path_len = resp->payload_sz - resp->veto_list_sz;
49+
50+ share->path = kstrndup(ksmbd_share_config_path(resp), path_len,
51 GFP_KERNEL);
52 if (share->path)
53 share->path_sz = strlen(share->path);
54--- a/fs/smb/server/transport_ipc.c
55+++ b/fs/smb/server/transport_ipc.c
56@@ -65,6 +65,7 @@ struct ipc_msg_table_entry {
57 struct hlist_node ipc_table_hlist;
58
59 void *response;
60+ unsigned int msg_sz;
61 };
62
63 static struct delayed_work ipc_timer_work;
64@@ -275,6 +276,7 @@ static int handle_response(int type, voi
65 }
66
67 memcpy(entry->response, payload, sz);
68+ entry->msg_sz = sz;
69 wake_up_interruptible(&entry->wait);
70 ret = 0;
71 break;
72@@ -453,6 +455,34 @@ out:
73 return ret;
74 }
75
76+static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
77+{
78+ unsigned int msg_sz = entry->msg_sz;
79+
80+ if (entry->type == KSMBD_EVENT_RPC_REQUEST) {
81+ struct ksmbd_rpc_command *resp = entry->response;
82+
83+ msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;
84+ } else if (entry->type == KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST) {
85+ struct ksmbd_spnego_authen_response *resp = entry->response;
86+
87+ msg_sz = sizeof(struct ksmbd_spnego_authen_response) +
88+ resp->session_key_len + resp->spnego_blob_len;
89+ } else if (entry->type == KSMBD_EVENT_SHARE_CONFIG_REQUEST) {
90+ struct ksmbd_share_config_response *resp = entry->response;
91+
92+ if (resp->payload_sz) {
93+ if (resp->payload_sz < resp->veto_list_sz)
94+ return -EINVAL;
95+
96+ msg_sz = sizeof(struct ksmbd_share_config_response) +
97+ resp->payload_sz;
98+ }
99+ }
100+
101+ return entry->msg_sz != msg_sz ? -EINVAL : 0;
102+}
103+
104 static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle)
105 {
106 struct ipc_msg_table_entry entry;
107@@ -477,6 +507,13 @@ static void *ipc_msg_send_request(struct
108 ret = wait_event_interruptible_timeout(entry.wait,
109 entry.response != NULL,
110 IPC_WAIT_TIMEOUT);
111+ if (entry.response) {
112+ ret = ipc_validate_msg(&entry);
113+ if (ret) {
114+ kvfree(entry.response);
115+ entry.response = NULL;
116+ }
117+ }
118 out:
119 down_write(&ipc_msg_table_lock);
120 hash_del(&entry.ipc_table_hlist);