VMCI: Fix integer overflow in VMCI handle arrays
The VMCI handle array has an integer overflow in vmci_handle_arr_append_entry when it tries to expand the array. This can be triggered from a guest, since the doorbell link hypercall doesn't impose a limit on the number of doorbell handles that a VM can create in the hypervisor, and these handles are stored in a handle array. In this change, we introduce a mandatory max capacity for handle arrays/lists to avoid excessive memory usage. Signed-off-by: Vishnu Dasa <vdasa@vmware.com> Reviewed-by: Adit Ranadive <aditr@vmware.com> Reviewed-by: Jorgen Hansen <jhansen@vmware.com> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
84705f9f8c
commit
1c2eb5b285
@@ -21,6 +21,9 @@
|
||||
#include "vmci_driver.h"
|
||||
#include "vmci_event.h"
|
||||
|
||||
/* Use a wide upper bound for the maximum contexts. */
|
||||
#define VMCI_MAX_CONTEXTS 2000
|
||||
|
||||
/*
|
||||
* List of current VMCI contexts. Contexts can be added by
|
||||
* vmci_ctx_create() and removed via vmci_ctx_destroy().
|
||||
@@ -117,19 +120,22 @@ struct vmci_ctx *vmci_ctx_create(u32 cid, u32 priv_flags,
|
||||
/* Initialize host-specific VMCI context. */
|
||||
init_waitqueue_head(&context->host_context.wait_queue);
|
||||
|
||||
context->queue_pair_array = vmci_handle_arr_create(0);
|
||||
context->queue_pair_array =
|
||||
vmci_handle_arr_create(0, VMCI_MAX_GUEST_QP_COUNT);
|
||||
if (!context->queue_pair_array) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_ctx;
|
||||
}
|
||||
|
||||
context->doorbell_array = vmci_handle_arr_create(0);
|
||||
context->doorbell_array =
|
||||
vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
|
||||
if (!context->doorbell_array) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_qp_array;
|
||||
}
|
||||
|
||||
context->pending_doorbell_array = vmci_handle_arr_create(0);
|
||||
context->pending_doorbell_array =
|
||||
vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
|
||||
if (!context->pending_doorbell_array) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_db_array;
|
||||
@@ -204,7 +210,7 @@ static int ctx_fire_notification(u32 context_id, u32 priv_flags)
|
||||
* We create an array to hold the subscribers we find when
|
||||
* scanning through all contexts.
|
||||
*/
|
||||
subscriber_array = vmci_handle_arr_create(0);
|
||||
subscriber_array = vmci_handle_arr_create(0, VMCI_MAX_CONTEXTS);
|
||||
if (subscriber_array == NULL)
|
||||
return VMCI_ERROR_NO_MEM;
|
||||
|
||||
@@ -623,20 +629,26 @@ int vmci_ctx_add_notification(u32 context_id, u32 remote_cid)
|
||||
|
||||
spin_lock(&context->lock);
|
||||
|
||||
list_for_each_entry(n, &context->notifier_list, node) {
|
||||
if (vmci_handle_is_equal(n->handle, notifier->handle)) {
|
||||
exists = true;
|
||||
break;
|
||||
if (context->n_notifiers < VMCI_MAX_CONTEXTS) {
|
||||
list_for_each_entry(n, &context->notifier_list, node) {
|
||||
if (vmci_handle_is_equal(n->handle, notifier->handle)) {
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
kfree(notifier);
|
||||
result = VMCI_ERROR_ALREADY_EXISTS;
|
||||
if (exists) {
|
||||
kfree(notifier);
|
||||
result = VMCI_ERROR_ALREADY_EXISTS;
|
||||
} else {
|
||||
list_add_tail_rcu(¬ifier->node,
|
||||
&context->notifier_list);
|
||||
context->n_notifiers++;
|
||||
result = VMCI_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
list_add_tail_rcu(¬ifier->node, &context->notifier_list);
|
||||
context->n_notifiers++;
|
||||
result = VMCI_SUCCESS;
|
||||
kfree(notifier);
|
||||
result = VMCI_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
spin_unlock(&context->lock);
|
||||
@@ -721,8 +733,7 @@ static int vmci_ctx_get_chkpt_doorbells(struct vmci_ctx *context,
|
||||
u32 *buf_size, void **pbuf)
|
||||
{
|
||||
struct dbell_cpt_state *dbells;
|
||||
size_t n_doorbells;
|
||||
int i;
|
||||
u32 i, n_doorbells;
|
||||
|
||||
n_doorbells = vmci_handle_arr_get_size(context->doorbell_array);
|
||||
if (n_doorbells > 0) {
|
||||
@@ -860,7 +871,8 @@ int vmci_ctx_rcv_notifications_get(u32 context_id,
|
||||
spin_lock(&context->lock);
|
||||
|
||||
*db_handle_array = context->pending_doorbell_array;
|
||||
context->pending_doorbell_array = vmci_handle_arr_create(0);
|
||||
context->pending_doorbell_array =
|
||||
vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
|
||||
if (!context->pending_doorbell_array) {
|
||||
context->pending_doorbell_array = *db_handle_array;
|
||||
*db_handle_array = NULL;
|
||||
@@ -942,12 +954,11 @@ int vmci_ctx_dbell_create(u32 context_id, struct vmci_handle handle)
|
||||
return VMCI_ERROR_NOT_FOUND;
|
||||
|
||||
spin_lock(&context->lock);
|
||||
if (!vmci_handle_arr_has_entry(context->doorbell_array, handle)) {
|
||||
vmci_handle_arr_append_entry(&context->doorbell_array, handle);
|
||||
result = VMCI_SUCCESS;
|
||||
} else {
|
||||
if (!vmci_handle_arr_has_entry(context->doorbell_array, handle))
|
||||
result = vmci_handle_arr_append_entry(&context->doorbell_array,
|
||||
handle);
|
||||
else
|
||||
result = VMCI_ERROR_DUPLICATE_ENTRY;
|
||||
}
|
||||
|
||||
spin_unlock(&context->lock);
|
||||
vmci_ctx_put(context);
|
||||
@@ -1083,15 +1094,16 @@ int vmci_ctx_notify_dbell(u32 src_cid,
|
||||
if (!vmci_handle_arr_has_entry(
|
||||
dst_context->pending_doorbell_array,
|
||||
handle)) {
|
||||
vmci_handle_arr_append_entry(
|
||||
result = vmci_handle_arr_append_entry(
|
||||
&dst_context->pending_doorbell_array,
|
||||
handle);
|
||||
|
||||
ctx_signal_notify(dst_context);
|
||||
wake_up(&dst_context->host_context.wait_queue);
|
||||
|
||||
if (result == VMCI_SUCCESS) {
|
||||
ctx_signal_notify(dst_context);
|
||||
wake_up(&dst_context->host_context.wait_queue);
|
||||
}
|
||||
} else {
|
||||
result = VMCI_SUCCESS;
|
||||
}
|
||||
result = VMCI_SUCCESS;
|
||||
}
|
||||
spin_unlock(&dst_context->lock);
|
||||
}
|
||||
@@ -1118,13 +1130,11 @@ int vmci_ctx_qp_create(struct vmci_ctx *context, struct vmci_handle handle)
|
||||
if (context == NULL || vmci_handle_is_invalid(handle))
|
||||
return VMCI_ERROR_INVALID_ARGS;
|
||||
|
||||
if (!vmci_handle_arr_has_entry(context->queue_pair_array, handle)) {
|
||||
vmci_handle_arr_append_entry(&context->queue_pair_array,
|
||||
handle);
|
||||
result = VMCI_SUCCESS;
|
||||
} else {
|
||||
if (!vmci_handle_arr_has_entry(context->queue_pair_array, handle))
|
||||
result = vmci_handle_arr_append_entry(
|
||||
&context->queue_pair_array, handle);
|
||||
else
|
||||
result = VMCI_ERROR_DUPLICATE_ENTRY;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
Reference in New Issue
Block a user