cloudinit/vendor/github.com/sigma/vmw-guestinfo/bridge/vmcheck.c

301 lines
6.8 KiB
C
Raw Normal View History

/*********************************************************
* Copyright (C) 2006-2015 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
* by the Free Software Foundation version 2.1 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*********************************************************/
/*
* vmcheck.c --
*
* Utility functions for discovering our virtualization status.
*/
#include <stdlib.h>
#include <string.h>
#ifdef WINNT_DDK
# include <ntddk.h>
#endif
#include "vmware.h"
/*
* #include "vm_version.h"
* #include "vm_tools_version.h"
*/
#define VMX_TYPE_UNSET 0
#define VERSION_MAGIC 0x6
#if !defined(WINNT_DDK)
# include "hostinfo.h"
/* # include "str.h" */
# define Str_Strcmp(s1, s2) strcmp(s1, s2)
#endif
/*
* backdoor.h includes some files which redefine constants in ntddk.h. Ignore
* warnings about these redefinitions for WIN32 platform.
*/
#ifdef WINNT_DDK
#pragma warning (push)
// Warning: Conditional expression is constant.
#pragma warning( disable:4127 )
#endif
#include "backdoor.h"
#ifdef WINNT_DDK
#pragma warning (pop)
#endif
#include "backdoor_def.h"
#include "debug.h"
typedef Bool (*SafeCheckFn)(void);
#if !defined(_WIN32)
# include "vmsignal.h"
# include "setjmp.h"
static sigjmp_buf jmpBuf;
static Bool jmpIsSet;
/*
*----------------------------------------------------------------------
*
* VmCheckSegvHandler --
*
* Signal handler for segv. Return to the program state saved
* by a previous call to sigsetjmp, or Panic if sigsetjmp hasn't
* been called yet. This function never returns;
*
* Return Value:
* None.
*
* Side effects:
* See the manpage for sigsetjmp for details.
*
*----------------------------------------------------------------------
*/
static void
VmCheckSegvHandler(int clientData) // UNUSED
{
if (jmpIsSet) {
siglongjmp(jmpBuf, 1);
} else {
Panic("Received SEGV, exiting.");
}
}
#endif
/*
*----------------------------------------------------------------------
*
* VmCheckSafe --
*
* Calls a potentially unsafe function, trapping possible exceptions.
*
* Results:
*
* Return value of the passed function, or FALSE in case of exception.
*
* Side effects:
*
* Temporarily suppresses signals / SEH exceptions
*
*----------------------------------------------------------------------
*/
static Bool
VmCheckSafe(SafeCheckFn checkFn)
{
Bool result = FALSE;
/*
* On a real host this call should cause a GP and we catch
* that and set result to FALSE.
*/
#if defined(_WIN32)
__try {
result = checkFn();
} __except(EXCEPTION_EXECUTE_HANDLER) {
/* no op */
}
#else
do {
int signals[] = {
SIGILL,
SIGSEGV,
};
struct sigaction olds[ARRAYSIZE(signals)];
if (Signal_SetGroupHandler(signals, olds, ARRAYSIZE(signals),
VmCheckSegvHandler) == 0) {
Warning("%s: Failed to set signal handlers.\n", __FUNCTION__);
break;
}
if (sigsetjmp(jmpBuf, TRUE) == 0) {
jmpIsSet = TRUE;
result = checkFn();
} else {
jmpIsSet = FALSE;
}
if (Signal_ResetGroupHandler(signals, olds, ARRAYSIZE(signals)) == 0) {
Warning("%s: Failed to reset signal handlers.\n", __FUNCTION__);
}
} while (0);
#endif
return result;
}
/*
*----------------------------------------------------------------------
*
* VmCheck_GetVersion --
*
* Retrieve the version of VMware that's running on the
* other side of the backdoor.
*
* Return value:
* TRUE on success
* *version contains the VMX version
* *type contains the VMX type
* FALSE on failure
*
* Side effects:
* None
*
*----------------------------------------------------------------------
*/
Bool
VmCheck_GetVersion(uint32 *version, // OUT
uint32 *type) // OUT
{
Backdoor_proto bp;
ASSERT(version);
ASSERT(type);
/* Make sure EBX does not contain BDOOR_MAGIC */
bp.in.size = ~BDOOR_MAGIC;
/* Make sure ECX does not contain any known VMX type */
bp.in.cx.halfs.high = 0xFFFF;
bp.in.cx.halfs.low = BDOOR_CMD_GETVERSION;
Backdoor(&bp);
if (bp.out.ax.word == 0xFFFFFFFF) {
/*
* No backdoor device there. This code is not executing in a VMware
* virtual machine. --hpreg
*/
return FALSE;
}
if (bp.out.bx.word != BDOOR_MAGIC) {
return FALSE;
}
*version = bp.out.ax.word;
/*
* Old VMXs (workstation and express) didn't set their type. In that case,
* our special pattern will still be there. --hpreg
*/
/*
* Need to expand this out since the toolchain's gcc doesn't like mixing
* integral types and enums in the same trinary operator.
*/
if (bp.in.cx.halfs.high == 0xFFFF)
*type = VMX_TYPE_UNSET;
else
*type = bp.out.cx.word;
return TRUE;
}
/*
*----------------------------------------------------------------------
*
* VmCheck_IsVirtualWorld --
*
* Verify that we're running in a VM & we're version compatible with our
* environment.
*
* Return value:
* TRUE if we're in a virtual machine, FALSE otherwise.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
Bool
VmCheck_IsVirtualWorld(void)
{
uint32 version;
uint32 dummy;
#if !defined(WINNT_DDK)
if (VmCheckSafe(Hostinfo_TouchXen)) {
Debug("%s: detected Xen.\n", __FUNCTION__);
return FALSE;
}
if (VmCheckSafe(Hostinfo_TouchVirtualPC)) {
Debug("%s: detected Virtual PC.\n", __FUNCTION__);
return FALSE;
}
if (!VmCheckSafe(Hostinfo_TouchBackDoor)) {
Debug("%s: backdoor not detected.\n", __FUNCTION__);
return FALSE;
}
/* It should be safe to use the backdoor without a crash handler now. */
VmCheck_GetVersion(&version, &dummy);
#else
/*
* The Win32 vmwvaudio driver uses this function, so keep the old,
* VMware-only check.
*/
__try {
VmCheck_GetVersion(&version, &dummy);
} __except (GetExceptionCode() == STATUS_PRIVILEGED_INSTRUCTION) {
return FALSE;
}
#endif
if (version != VERSION_MAGIC) {
Debug("The version of this program is incompatible with your platform.\n");
return FALSE;
}
return TRUE;
}