From: VMware, Inc <> Date: Mon, 21 May 2012 22:19:20 +0000 (-0700) Subject: Introduce VMCI firewall in device backend X-Git-Tag: 2012.05.21-724730~55 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e9f178eec971692fba4e8206b3fa616f378175c8;p=thirdparty%2Fopen-vm-tools.git Introduce VMCI firewall in device backend This change implements the VMCI device backend part of the VMCI firewall. Signed-off-by: Dmitry Torokhov --- diff --git a/open-vm-tools/lib/include/vmci_defs.h b/open-vm-tools/lib/include/vmci_defs.h index 3e0e753e8..6791b46cc 100644 --- a/open-vm-tools/lib/include/vmci_defs.h +++ b/open-vm-tools/lib/include/vmci_defs.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2005-2011 VMware, Inc. All rights reserved. + * Copyright (C) 2005-2012 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -143,10 +143,20 @@ typedef uint32 VMCI_Resource; #define VMCI_RPC_PRIVILEGED 15 #define VMCI_RPC_UNPRIVILEGED 16 #define VMCI_RESOURCE_MAX 17 +/* + * The core VMCI device functionality only requires the resource IDs of + * VMCI_QUEUEPAIR_DETACH and below. + */ +#define VMCI_CORE_DEVICE_RESOURCE_MAX VMCI_QUEUEPAIR_DETACH /* VMCI Ids. */ typedef uint32 VMCIId; +typedef struct VMCIIdRange { + VMCIId begin; + VMCIId end; +} VMCIIdRange; + typedef struct VMCIHandle { VMCIId context; VMCIId resource; @@ -827,5 +837,62 @@ VMCIQueueHeader_BufReady(const VMCIQueueHeader *consumeQHeader, // IN: } -#endif +/* + * Defines for the VMCI traffic filter: + * - VMCI_FP_ defines the filter protocol values + * - VMCI_FD_ defines the direction values (guest or host) + * - VMCI_FT_ are the type values (allow or deny) + */ + +#define VMCI_FP_INVALID -1 +#define VMCI_FP_HYPERVISOR 0 +#define VMCI_FP_QUEUEPAIR (VMCI_FP_HYPERVISOR + 1) +#define VMCI_FP_DOORBELL (VMCI_FP_QUEUEPAIR + 1) +#define VMCI_FP_DATAGRAM (VMCI_FP_DOORBELL + 1) +#define VMCI_FP_STREAMSOCK (VMCI_FP_DATAGRAM + 1) +#define VMCI_FP_SEQPACKET (VMCI_FP_STREAMSOCK + 1) +#define VMCI_FP_MAX (VMCI_FP_SEQPACKET + 1) + +#define VMCI_FD_INVALID -1 +#define VMCI_FD_GUEST 0 +#define VMCI_FD_HOST (VMCI_FD_GUEST + 1) +#define VMCI_FD_MAX (VMCI_FD_HOST + 1) + +#define VMCI_FT_INVALID -1 +#define VMCI_FT_ALLOW 0 +#define VMCI_FT_DENY (VMCI_FT_ALLOW + 1) +#define VMCI_FT_MAX (VMCI_FT_DENY + 1) + +/* + * The filter list tracks VMCI Id ranges for a given filter. + */ + +typedef struct { + uint32 len; + VMCIIdRange *list; +} VMCIFilterList; + +/* + * The filter info is used to communicate the filter configuration + * from the VMX to the host kernel. + */ + +typedef struct { + VA64 list; // List of VMCIIdRange + uint32 len; // Length of list + uint8 dir; // VMCI_FD_X + uint8 proto; // VMCI_FP_X + uint8 type; // VMCI_FT_X +} VMCIFilterInfo; + +/* + * In the host kernel, the ingoing and outgoing filters are + * separated. The VMCIProtoFilters type captures all filters in one + * direction. The VMCIFilters type captures all filters. + */ + +typedef VMCIFilterList VMCIProtoFilters[VMCI_FP_MAX][VMCI_FT_MAX]; +typedef VMCIProtoFilters VMCIFilters[VMCI_FD_MAX]; + +#endif diff --git a/open-vm-tools/modules/linux/shared/vmci_defs.h b/open-vm-tools/modules/linux/shared/vmci_defs.h index b5483822d..8222af726 100644 --- a/open-vm-tools/modules/linux/shared/vmci_defs.h +++ b/open-vm-tools/modules/linux/shared/vmci_defs.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2005-2011 VMware, Inc. All rights reserved. + * Copyright (C) 2005-2012 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -143,10 +143,20 @@ typedef uint32 VMCI_Resource; #define VMCI_RPC_PRIVILEGED 15 #define VMCI_RPC_UNPRIVILEGED 16 #define VMCI_RESOURCE_MAX 17 +/* + * The core VMCI device functionality only requires the resource IDs of + * VMCI_QUEUEPAIR_DETACH and below. + */ +#define VMCI_CORE_DEVICE_RESOURCE_MAX VMCI_QUEUEPAIR_DETACH /* VMCI Ids. */ typedef uint32 VMCIId; +typedef struct VMCIIdRange { + VMCIId begin; + VMCIId end; +} VMCIIdRange; + typedef struct VMCIHandle { VMCIId context; VMCIId resource; @@ -827,5 +837,62 @@ VMCIQueueHeader_BufReady(const VMCIQueueHeader *consumeQHeader, // IN: } -#endif +/* + * Defines for the VMCI traffic filter: + * - VMCI_FP_ defines the filter protocol values + * - VMCI_FD_ defines the direction values (guest or host) + * - VMCI_FT_ are the type values (allow or deny) + */ + +#define VMCI_FP_INVALID -1 +#define VMCI_FP_HYPERVISOR 0 +#define VMCI_FP_QUEUEPAIR (VMCI_FP_HYPERVISOR + 1) +#define VMCI_FP_DOORBELL (VMCI_FP_QUEUEPAIR + 1) +#define VMCI_FP_DATAGRAM (VMCI_FP_DOORBELL + 1) +#define VMCI_FP_STREAMSOCK (VMCI_FP_DATAGRAM + 1) +#define VMCI_FP_SEQPACKET (VMCI_FP_STREAMSOCK + 1) +#define VMCI_FP_MAX (VMCI_FP_SEQPACKET + 1) + +#define VMCI_FD_INVALID -1 +#define VMCI_FD_GUEST 0 +#define VMCI_FD_HOST (VMCI_FD_GUEST + 1) +#define VMCI_FD_MAX (VMCI_FD_HOST + 1) + +#define VMCI_FT_INVALID -1 +#define VMCI_FT_ALLOW 0 +#define VMCI_FT_DENY (VMCI_FT_ALLOW + 1) +#define VMCI_FT_MAX (VMCI_FT_DENY + 1) + +/* + * The filter list tracks VMCI Id ranges for a given filter. + */ + +typedef struct { + uint32 len; + VMCIIdRange *list; +} VMCIFilterList; + +/* + * The filter info is used to communicate the filter configuration + * from the VMX to the host kernel. + */ + +typedef struct { + VA64 list; // List of VMCIIdRange + uint32 len; // Length of list + uint8 dir; // VMCI_FD_X + uint8 proto; // VMCI_FP_X + uint8 type; // VMCI_FT_X +} VMCIFilterInfo; + +/* + * In the host kernel, the ingoing and outgoing filters are + * separated. The VMCIProtoFilters type captures all filters in one + * direction. The VMCIFilters type captures all filters. + */ + +typedef VMCIFilterList VMCIProtoFilters[VMCI_FP_MAX][VMCI_FT_MAX]; +typedef VMCIProtoFilters VMCIFilters[VMCI_FD_MAX]; + +#endif diff --git a/open-vm-tools/modules/linux/vmci/common/vmciCommonInt.h b/open-vm-tools/modules/linux/vmci/common/vmciCommonInt.h index 256b9dee5..8af33b472 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciCommonInt.h +++ b/open-vm-tools/modules/linux/vmci/common/vmciCommonInt.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006-2011 VMware, Inc. All rights reserved. + * Copyright (C) 2006-2012 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -26,7 +26,6 @@ #define _VMCI_COMMONINT_H_ #define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" @@ -38,7 +37,6 @@ #include "vmci_handle_array.h" #include "vmci_kernel_if.h" - /* * The DatagramQueueEntry is a queue header for the in-kernel VMCI * datagram queues. It is allocated in non-paged memory, as the @@ -55,6 +53,20 @@ typedef struct DatagramQueueEntry { } DatagramQueueEntry; +/* + * The VMCIFilterState captures the state of all VMCI filters in one + * direction. The ranges array contains all filter list in a single + * memory chunk, and the filter list pointers in the VMCIProtoFilters + * point into the ranges array. + */ + +typedef struct VMCIFilterState { + VMCIProtoFilters filters; + VMCIIdRange *ranges; + size_t rangesSize; +} VMCIFilterState; + + struct VMCIContext { VMCIListItem listItem; /* For global VMCI list. */ VMCIId cid; @@ -67,9 +79,9 @@ struct VMCIContext { * this context; e.g., VMX. */ VMCILock lock; /* - * Locks datagramQueue, doorbellArray, - * pendingDoorbellArray and - * notifierArray. + * Locks datagramQueue, inFilters, + * doorbellArray, pendingDoorbellArray + * and notifierArray. */ VMCIHandleArray *queuePairArray; /* * QueuePairs attached to. The array of @@ -96,6 +108,7 @@ struct VMCIContext { * registration/release during FSR. */ VMCIGuestMemID curGuestMemID; /* ID of current registered guest mem */ + VMCIFilterState *inFilters; /* Ingoing filters for VMCI traffic. */ #endif #ifndef VMX86_SERVER Bool *notify; /* Notify flag pointer - hosted only. */ diff --git a/open-vm-tools/modules/linux/vmci/common/vmciContext.c b/open-vm-tools/modules/linux/vmci/common/vmciContext.c index f208f86bb..8d154d4df 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciContext.c +++ b/open-vm-tools/modules/linux/vmci/common/vmciContext.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006-2011 VMware, Inc. All rights reserved. + * Copyright (C) 2006-2012 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -49,6 +49,7 @@ static int VMCIContextFireNotification(VMCIId contextID, #if defined(VMKERNEL) static void VMCIContextReleaseGuestMemLocked(VMCIContext *context, VMCIGuestMemID gid); +static void VMCIContextInFilterCleanup(VMCIContext *context); #endif /* @@ -331,6 +332,8 @@ VMCIContext_InitContext(VMCIId cid, // IN goto error; } context->curGuestMemID = INVALID_VMCI_GUEST_MEM_ID; + + context->inFilters = NULL; #endif /* Inititialize host-specific VMCI context. */ @@ -501,6 +504,7 @@ VMCIContextFreeContext(VMCIContext *context) // IN VMCIHandleArray_Destroy(context->pendingDoorbellArray); VMCI_CleanupLock(&context->lock); #if defined(VMKERNEL) + VMCIContextInFilterCleanup(context); VMCIMutex_Destroy(&context->guestMemMutex); #endif VMCIHost_ReleaseContext(&context->hostContext); @@ -606,6 +610,18 @@ VMCIContext_EnqueueDatagram(VMCIId cid, // IN: Target VM VMCIList_InitEntry(&dqEntry->listItem); VMCI_GrabLock(&context->lock, &flags); + +#if defined(VMKERNEL) + if (context->inFilters != NULL) { + if (VMCIFilterDenyDgIn(context->inFilters->filters, dg)) { + VMCI_ReleaseLock(&context->lock, flags); + VMCIContext_Release(context); + VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry); + return VMCI_ERROR_NO_ACCESS; + } + } +#endif + /* * We put a higher limit on datagrams from the hypervisor. If the pending * datagram is not from hypervisor, then we check if enqueueing it would @@ -1993,6 +2009,13 @@ VMCIContext_NotifyDoorbell(VMCIId srcCID, // IN } else { VMCI_GrabLock(&dstContext->lock, &flags); +#if defined(VMKERNEL) + if (dstContext->inFilters != NULL && + VMCIFilterProtoDeny(dstContext->inFilters->filters, handle.resource, + VMCI_FP_DOORBELL)) { + result = VMCI_ERROR_NO_ACCESS; + } else +#endif // VMKERNEL if (!VMCIHandleArray_HasEntry(dstContext->doorbellArray, handle)) { result = VMCI_ERROR_NOT_FOUND; } else { @@ -2531,3 +2554,87 @@ VMCIContext_ReleaseGuestMem(VMCIContext *context, // IN: Context structure VMCIMutex_Release(&context->guestMemMutex); #endif } + +#if defined(VMKERNEL) + +/* + *---------------------------------------------------------------------- + * + * VMCIContext_FilterSet -- + * + * Sets an ingoing (host to guest) filter for the VMCI firewall of the + * given context. If a filter list already exists for the given filter + * entry, the old entry will be deleted. It is assumed that the list + * can be used as is, and that the memory backing it will be freed by the + * VMCI Context module once the filter is deleted. + * + * Results: + * VMCI_SUCCESS on success, + * VMCI_ERROR_NOT_FOUND if there is no active context linked to the cid, + * VMCI_ERROR_INVALID_ARGS if a non-VM cid is specified. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +VMCIContext_FilterSet(VMCIId cid, // IN + VMCIFilterState *filters) // IN +{ + VMCIContext *context; + VMCILockFlags flags; + VMCIFilterState *oldState; + + if (!VMCI_CONTEXT_IS_VM(cid)) { + return VMCI_ERROR_INVALID_ARGS; + } + + context = VMCIContext_Get(cid); + if (!context) { + return VMCI_ERROR_NOT_FOUND; + } + + VMCI_GrabLock(&context->lock, &flags); + + oldState = context->inFilters; + context->inFilters = filters; + + VMCI_ReleaseLock(&context->lock, flags); + if (oldState) { + VMCIVMKDevFreeFilterState(oldState); + } + VMCIContext_Release(context); + + return VMCI_SUCCESS; +} + + +/* + *---------------------------------------------------------------------- + * + * VMCIContextInFilterCleanup -- + * + * When a context is destroyed, all filters will be deleted. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +VMCIContextInFilterCleanup(VMCIContext *context) +{ + if (context->inFilters != NULL) { + VMCIVMKDevFreeFilterState(context->inFilters); + context->inFilters = NULL; + } +} + +#endif + diff --git a/open-vm-tools/modules/linux/vmci/common/vmciContext.h b/open-vm-tools/modules/linux/vmci/common/vmciContext.h index 7041a3562..254609730 100644 --- a/open-vm-tools/modules/linux/vmci/common/vmciContext.h +++ b/open-vm-tools/modules/linux/vmci/common/vmciContext.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2006-2011 VMware, Inc. All rights reserved. + * Copyright (C) 2006-2012 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -36,6 +36,7 @@ #include "vmci_handle_array.h" #include "vmci_infrastructure.h" #include "vmci_kernel_if.h" +#include "vmciCommonInt.h" #define MAX_QUEUED_GUESTCALLS_PER_VM 100 @@ -115,6 +116,6 @@ void VMCIContext_SignalPendingDoorbells(VMCIId contextID); void VMCIContext_SignalPendingDatagrams(VMCIId contextID); int VMCIContextID2HostVmID(VMCIId contextID, void *hostVmID, size_t hostVmIDLen); +int VMCIContext_FilterSet(VMCIId cid, VMCIFilterState *filterState); #endif - #endif // _VMCI_CONTEXT_H_ diff --git a/open-vm-tools/modules/linux/vmci/linux/vmci_version.h b/open-vm-tools/modules/linux/vmci/linux/vmci_version.h index 5b222579d..0953b8d84 100644 --- a/open-vm-tools/modules/linux/vmci/linux/vmci_version.h +++ b/open-vm-tools/modules/linux/vmci/linux/vmci_version.h @@ -25,8 +25,8 @@ #ifndef _VMCI_VERSION_H_ #define _VMCI_VERSION_H_ -#define VMCI_DRIVER_VERSION 9.5.3.0 -#define VMCI_DRIVER_VERSION_COMMAS 9,5,3,0 -#define VMCI_DRIVER_VERSION_STRING "9.5.3.0" +#define VMCI_DRIVER_VERSION 9.5.4.0 +#define VMCI_DRIVER_VERSION_COMMAS 9,5,4,0 +#define VMCI_DRIVER_VERSION_STRING "9.5.4.0" #endif /* _VMCI_VERSION_H_ */