]>
Commit | Line | Data |
---|---|---|
2ef6de7d GKH |
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); |