]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-6.1/ksmbd-validate-payload-size-in-ipc-response.patch
6.1-stable patches
[thirdparty/kernel/stable-queue.git] / queue-6.1 / ksmbd-validate-payload-size-in-ipc-response.patch
1 From a677ebd8ca2f2632ccdecbad7b87641274e15aac Mon Sep 17 00:00:00 2001
2 From: Namjae Jeon <linkinjeon@kernel.org>
3 Date: Sun, 31 Mar 2024 21:59:10 +0900
4 Subject: ksmbd: validate payload size in ipc response
5
6 From: Namjae Jeon <linkinjeon@kernel.org>
7
8 commit a677ebd8ca2f2632ccdecbad7b87641274e15aac upstream.
9
10 If installing malicious ksmbd-tools, ksmbd.mountd can return invalid ipc
11 response to ksmbd kernel server. ksmbd should validate payload size of
12 ipc response from ksmbd.mountd to avoid memory overrun or
13 slab-out-of-bounds. This patch validate 3 ipc response that has payload.
14
15 Cc: stable@vger.kernel.org
16 Reported-by: Chao Ma <machao2019@gmail.com>
17 Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
18 Signed-off-by: Steve French <stfrench@microsoft.com>
19 Signed-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);