mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-30 14:19:16 +00:00
ksmbd: validate payload size in ipc response
commit a677ebd8ca
upstream.
If installing malicious ksmbd-tools, ksmbd.mountd can return invalid ipc
response to ksmbd kernel server. ksmbd should validate payload size of
ipc response from ksmbd.mountd to avoid memory overrun or
slab-out-of-bounds. This patch validate 3 ipc response that has payload.
Cc: stable@vger.kernel.org
Reported-by: Chao Ma <machao2019@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
a06562fd4c
commit
a637fabac5
3 changed files with 45 additions and 2 deletions
|
@ -166,7 +166,8 @@ struct ksmbd_share_config_response {
|
||||||
__u16 force_uid;
|
__u16 force_uid;
|
||||||
__u16 force_gid;
|
__u16 force_gid;
|
||||||
__s8 share_name[KSMBD_REQ_MAX_SHARE_NAME];
|
__s8 share_name[KSMBD_REQ_MAX_SHARE_NAME];
|
||||||
__u32 reserved[112]; /* Reserved room */
|
__u32 reserved[111]; /* Reserved room */
|
||||||
|
__u32 payload_sz;
|
||||||
__u32 veto_list_sz;
|
__u32 veto_list_sz;
|
||||||
__s8 ____payload[];
|
__s8 ____payload[];
|
||||||
};
|
};
|
||||||
|
|
|
@ -158,7 +158,12 @@ static struct ksmbd_share_config *share_config_request(struct unicode_map *um,
|
||||||
share->name = kstrdup(name, GFP_KERNEL);
|
share->name = kstrdup(name, GFP_KERNEL);
|
||||||
|
|
||||||
if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
|
if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
|
||||||
share->path = kstrdup(ksmbd_share_config_path(resp),
|
int path_len = PATH_MAX;
|
||||||
|
|
||||||
|
if (resp->payload_sz)
|
||||||
|
path_len = resp->payload_sz - resp->veto_list_sz;
|
||||||
|
|
||||||
|
share->path = kstrndup(ksmbd_share_config_path(resp), path_len,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (share->path)
|
if (share->path)
|
||||||
share->path_sz = strlen(share->path);
|
share->path_sz = strlen(share->path);
|
||||||
|
|
|
@ -65,6 +65,7 @@ struct ipc_msg_table_entry {
|
||||||
struct hlist_node ipc_table_hlist;
|
struct hlist_node ipc_table_hlist;
|
||||||
|
|
||||||
void *response;
|
void *response;
|
||||||
|
unsigned int msg_sz;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct delayed_work ipc_timer_work;
|
static struct delayed_work ipc_timer_work;
|
||||||
|
@ -275,6 +276,7 @@ static int handle_response(int type, void *payload, size_t sz)
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(entry->response, payload, sz);
|
memcpy(entry->response, payload, sz);
|
||||||
|
entry->msg_sz = sz;
|
||||||
wake_up_interruptible(&entry->wait);
|
wake_up_interruptible(&entry->wait);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -453,6 +455,34 @@ static int ipc_msg_send(struct ksmbd_ipc_msg *msg)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
|
||||||
|
{
|
||||||
|
unsigned int msg_sz = entry->msg_sz;
|
||||||
|
|
||||||
|
if (entry->type == KSMBD_EVENT_RPC_REQUEST) {
|
||||||
|
struct ksmbd_rpc_command *resp = entry->response;
|
||||||
|
|
||||||
|
msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;
|
||||||
|
} else if (entry->type == KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST) {
|
||||||
|
struct ksmbd_spnego_authen_response *resp = entry->response;
|
||||||
|
|
||||||
|
msg_sz = sizeof(struct ksmbd_spnego_authen_response) +
|
||||||
|
resp->session_key_len + resp->spnego_blob_len;
|
||||||
|
} else if (entry->type == KSMBD_EVENT_SHARE_CONFIG_REQUEST) {
|
||||||
|
struct ksmbd_share_config_response *resp = entry->response;
|
||||||
|
|
||||||
|
if (resp->payload_sz) {
|
||||||
|
if (resp->payload_sz < resp->veto_list_sz)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
msg_sz = sizeof(struct ksmbd_share_config_response) +
|
||||||
|
resp->payload_sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry->msg_sz != msg_sz ? -EINVAL : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle)
|
static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle)
|
||||||
{
|
{
|
||||||
struct ipc_msg_table_entry entry;
|
struct ipc_msg_table_entry entry;
|
||||||
|
@ -477,6 +507,13 @@ static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle
|
||||||
ret = wait_event_interruptible_timeout(entry.wait,
|
ret = wait_event_interruptible_timeout(entry.wait,
|
||||||
entry.response != NULL,
|
entry.response != NULL,
|
||||||
IPC_WAIT_TIMEOUT);
|
IPC_WAIT_TIMEOUT);
|
||||||
|
if (entry.response) {
|
||||||
|
ret = ipc_validate_msg(&entry);
|
||||||
|
if (ret) {
|
||||||
|
kvfree(entry.response);
|
||||||
|
entry.response = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
down_write(&ipc_msg_table_lock);
|
down_write(&ipc_msg_table_lock);
|
||||||
hash_del(&entry.ipc_table_hlist);
|
hash_del(&entry.ipc_table_hlist);
|
||||||
|
|
Loading…
Reference in a new issue