mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-06 01:03:55 -06:00
nbd: Don't send oversize strings
Qemu as server currently won't accept export names larger than 256 bytes, nor create dirty bitmap names longer than 1023 bytes, so most uses of qemu as client or server have no reason to get anywhere near the NBD spec maximum of a 4k limit per string. However, we weren't actually enforcing things, ignoring when the remote side violates the protocol on input, and also having several code paths where we send oversize strings on output (for example, qemu-nbd --description could easily send more than 4k). Tighten things up as follows: client: - Perform bounds check on export name and dirty bitmap request prior to handing it to server - Validate that copied server replies are not too long (ignoring NBD_INFO_* replies that are not copied is not too bad) server: - Perform bounds check on export name and description prior to advertising it to client - Reject client name or metadata query that is too long - Adjust things to allow full 4k name limit rather than previous 256 byte limit Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <20191114024635.11363-4-eblake@redhat.com> Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
This commit is contained in:
parent
cf7c49cf6a
commit
93676c88d7
6 changed files with 58 additions and 12 deletions
18
nbd/client.c
18
nbd/client.c
|
@ -289,8 +289,8 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description,
|
|||
return -1;
|
||||
}
|
||||
len -= sizeof(namelen);
|
||||
if (len < namelen) {
|
||||
error_setg(errp, "incorrect option name length");
|
||||
if (len < namelen || namelen > NBD_MAX_STRING_SIZE) {
|
||||
error_setg(errp, "incorrect name length in server's list response");
|
||||
nbd_send_opt_abort(ioc);
|
||||
return -1;
|
||||
}
|
||||
|
@ -303,6 +303,12 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description,
|
|||
local_name[namelen] = '\0';
|
||||
len -= namelen;
|
||||
if (len) {
|
||||
if (len > NBD_MAX_STRING_SIZE) {
|
||||
error_setg(errp, "incorrect description length in server's "
|
||||
"list response");
|
||||
nbd_send_opt_abort(ioc);
|
||||
return -1;
|
||||
}
|
||||
local_desc = g_malloc(len + 1);
|
||||
if (nbd_read(ioc, local_desc, len, "export description", errp) < 0) {
|
||||
nbd_send_opt_abort(ioc);
|
||||
|
@ -479,6 +485,10 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt,
|
|||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* Not worth the bother to check if NBD_INFO_NAME or
|
||||
* NBD_INFO_DESCRIPTION exceed NBD_MAX_STRING_SIZE.
|
||||
*/
|
||||
trace_nbd_opt_info_unknown(type, nbd_info_lookup(type));
|
||||
if (nbd_drop(ioc, len, errp) < 0) {
|
||||
error_prepend(errp, "Failed to read info payload: ");
|
||||
|
@ -645,9 +655,11 @@ static int nbd_send_meta_query(QIOChannel *ioc, uint32_t opt,
|
|||
char *p;
|
||||
|
||||
data_len = sizeof(export_len) + export_len + sizeof(queries);
|
||||
assert(export_len <= NBD_MAX_STRING_SIZE);
|
||||
if (query) {
|
||||
query_len = strlen(query);
|
||||
data_len += sizeof(query_len) + query_len;
|
||||
assert(query_len <= NBD_MAX_STRING_SIZE);
|
||||
} else {
|
||||
assert(opt == NBD_OPT_LIST_META_CONTEXT);
|
||||
}
|
||||
|
@ -1009,7 +1021,7 @@ int nbd_receive_negotiate(AioContext *aio_context, QIOChannel *ioc,
|
|||
bool zeroes;
|
||||
bool base_allocation = info->base_allocation;
|
||||
|
||||
assert(info->name);
|
||||
assert(info->name && strlen(info->name) <= NBD_MAX_STRING_SIZE);
|
||||
trace_nbd_receive_negotiate_name(info->name);
|
||||
|
||||
result = nbd_start_negotiate(aio_context, ioc, tlscreds, hostname, outioc,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue