ksmbd: prevent out-of-bounds reads in share config responses

Validate IPC share configuration payload sizes before consuming
variable-length fields. Bound veto list parsing and account for
the separator byte when deriving the path length.

Fixes: a677ebd8ca ("ksmbd: validate payload size in ipc response")
Reported-by: Kanishka De Silva <kpskanna1915@gmail.com>
Reported-by: Farhad Alemi <farhad.alemi@berkeley.edu>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
Namjae Jeon 2026-08-28 08:39:57 +09:00
parent feca5e70fc
commit f25e93768f
2 changed files with 41 additions and 20 deletions

View File

@ -146,9 +146,9 @@ static struct ksmbd_share_config *__share_lookup(const char *name)
static int parse_veto_list(struct ksmbd_share_config *share,
char *veto_list,
int veto_list_sz)
size_t veto_list_sz)
{
int sz = 0;
size_t sz;
if (!veto_list_sz)
return 0;
@ -156,7 +156,7 @@ static int parse_veto_list(struct ksmbd_share_config *share,
while (veto_list_sz > 0) {
struct ksmbd_veto_pattern *p;
sz = strlen(veto_list);
sz = strnlen(veto_list, veto_list_sz);
if (!sz)
break;
@ -164,7 +164,7 @@ static int parse_veto_list(struct ksmbd_share_config *share,
if (!p)
return -ENOMEM;
p->pattern = kstrdup(veto_list, KSMBD_DEFAULT_GFP);
p->pattern = kstrndup(veto_list, sz, KSMBD_DEFAULT_GFP);
if (!p->pattern) {
kfree(p);
return -ENOMEM;
@ -172,6 +172,9 @@ static int parse_veto_list(struct ksmbd_share_config *share,
list_add(&p->list, &share->veto_list);
if (sz == veto_list_sz)
break;
veto_list += sz + 1;
veto_list_sz -= (sz + 1);
}
@ -224,17 +227,28 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work,
}
if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
int path_len = PATH_MAX;
size_t path_len;
if (resp->payload_sz)
path_len = resp->payload_sz - resp->veto_list_sz;
share->path = kstrndup(ksmbd_share_config_path(resp), path_len,
KSMBD_DEFAULT_GFP);
if (!share->path) {
ret = -ENOMEM;
if (resp->payload_sz <= resp->veto_list_sz) {
ret = -EINVAL;
} else {
ret = 0;
path_len = resp->payload_sz - resp->veto_list_sz;
if (resp->veto_list_sz)
path_len--;
if (!path_len) {
ret = -EINVAL;
} else {
share->path = kstrndup(
ksmbd_share_config_path(resp),
path_len, KSMBD_DEFAULT_GFP);
if (!share->path)
ret = -ENOMEM;
else
ret = 0;
}
}
if (share->path) {
share->path_sz = strlen(share->path);
while (share->path_sz > 1 &&
share->path[share->path_sz - 1] == '/')

View File

@ -532,14 +532,21 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
if (entry->msg_sz < sizeof(struct ksmbd_share_config_response))
return -EINVAL;
if (resp->payload_sz) {
if (resp->payload_sz < resp->veto_list_sz)
return -EINVAL;
if (strnlen(resp->share_name, sizeof(resp->share_name)) ==
sizeof(resp->share_name))
return -EINVAL;
if (check_add_overflow(sizeof(struct ksmbd_share_config_response),
resp->payload_sz, &msg_sz))
return -EINVAL;
}
if (resp->veto_list_sz > resp->payload_sz)
return -EINVAL;
if (resp->flags != KSMBD_SHARE_FLAG_INVALID &&
!(resp->flags & KSMBD_SHARE_FLAG_PIPE) &&
resp->payload_sz <= resp->veto_list_sz)
return -EINVAL;
if (check_add_overflow(sizeof(struct ksmbd_share_config_response),
resp->payload_sz, &msg_sz))
return -EINVAL;
break;
}
case KSMBD_EVENT_LOGIN_REQUEST_EXT: