/* $Id$ */
/** @file
* VirtualBox Support Library - Windows NT specific parts.
*/
/*
* Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#ifdef IN_SUP_HARDENED_R3
# define LOG_DISABLED
/** @todo RTLOGREL_DISABLED */
#endif
#define USE_NT_DEVICE_IO_CONTROL_FILE
#include "../SUPLibInternal.h"
#include "../SUPDrvIOC.h"
#ifdef VBOX_WITH_HARDENING
# include "win/SUPHardenedVerify-win.h"
#endif
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** The support service name. */
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
#ifndef IN_SUP_HARDENED_R3
static int suplibOsCreateService(void);
//unused: static int suplibOsUpdateService(void);
static int suplibOsDeleteService(void);
static int suplibOsStartService(void);
static int suplibOsStopService(void);
#endif
#else
static int suplibConvertWin32Err(int);
#endif
/*******************************************************************************
* Global Variables *
*******************************************************************************/
static bool g_fHardenedVerifyInited = false;
int suplibOsHardenedVerifyInit(void)
{
if (!g_fHardenedVerifyInited)
{
if (RT_FAILURE(rc))
return rc;
#endif
g_fHardenedVerifyInited = true;
}
return VINF_SUCCESS;
}
int suplibOsHardenedVerifyTerm(void)
{
/** @todo free resources... */
return VINF_SUCCESS;
}
int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
{
/*
* Make sure the image verifier is fully initialized.
*/
if (RT_FAILURE(rc))
/*
* Done if of pre-inited.
*/
if (fPreInited)
{
#if defined(VBOX_WITH_HARDENING) && !defined(IN_SUP_HARDENED_R3)
# ifdef IN_SUP_R3_STATIC
return VERR_NOT_SUPPORTED;
# else
return VINF_SUCCESS;
# endif
#else
return VINF_SUCCESS;
#endif
}
/*
* Try open the device.
*/
#ifndef IN_SUP_HARDENED_R3
#endif
for (;;)
{
InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
NULL /* Allocation Size*/,
FILE_NON_DIRECTORY_FILE, /* No FILE_SYNCHRONOUS_IO_NONALERT! */
NULL /*EaBuffer*/,
0 /*EaLength*/);
if (NT_SUCCESS(rcNt))
if (NT_SUCCESS(rcNt))
{
/*
* We're good.
*/
return VINF_SUCCESS;
}
#ifndef IN_SUP_HARDENED_R3
/*
* Failed to open, try starting the service and reopen the device
* exactly once.
*/
{
cTry++;
continue;
}
#endif
/*
* Translate the error code.
*/
switch (rcNt)
{
/** @todo someone must test what is actually returned. */
//case ERROR_BAD_DEVICE:
case STATUS_DEVICE_REMOVED:
//case ERROR_DEVICE_NOT_AVAILABLE:
break;
case STATUS_NO_SUCH_DEVICE:
case STATUS_NO_SUCH_FILE:
break;
case STATUS_ACCESS_DENIED:
case STATUS_SHARING_VIOLATION:
break;
case STATUS_UNSUCCESSFUL:
break;
case STATUS_TRUST_FAILURE:
break;
case STATUS_TOO_LATE:
break;
default:
else
break;
}
#ifdef IN_SUP_HARDENED_R3
/*
* Get more details from VBoxDrvErrorInfo if present.
*/
{
/* Prefix. */
cchPrefix = RTStrPrintf(pErrInfo->pszMsg, pErrInfo->cbMsg / 2, "Integrity error (%#x/%s): ", rcNt, pszDefine);
else
cchPrefix = RTStrPrintf(pErrInfo->pszMsg, pErrInfo->cbMsg / 2, "Integrity error (%#x/%d): ", rcNt, rc);
/* Get error info. */
{
}
else
}
#endif
return rc;
}
}
#ifndef IN_SUP_HARDENED_R3
int suplibOsInstall(void)
{
if (RT_SUCCESS(rc))
{
if (rc2 != VINF_SUCCESS)
}
return rc;
}
int suplibOsUninstall(void)
{
if (RT_SUCCESS(rc))
rc = suplibOsDeleteService();
return rc;
}
/**
* Creates the service.
*
* @returns VBox status code.
* @retval VWRN_ALREADY_EXISTS if it already exists.
*/
static int suplibOsCreateService(void)
{
/*
* Assume it didn't exist, so we'll create the service.
*/
int rc;
if (hSMgrCreate != NULL)
{
if (RT_SUCCESS(rc))
{
"VBox Support Driver",
dwErr = GetLastError();
if (hService)
{
rc = VINF_SUCCESS;
}
else if (dwErr == ERROR_SERVICE_EXISTS)
else
{
}
}
}
else
return rc;
}
/**
* Stops a possibly running service.
*
* @returns VBox status code.
*/
static int suplibOsStopService(void)
{
/*
* Assume it didn't exist, so we'll create the service.
*/
int rc;
if (hSMgr)
{
if (hService)
{
/*
* Stop the service.
*/
rc = VINF_SUCCESS;
{
{
Sleep(100);
}
rc = VINF_SUCCESS;
else
{
}
}
else
{
dwErr = GetLastError();
AssertMsgFailed(("ControlService failed with dwErr=%Rwa. status=%d\n", dwErr, Status.dwCurrentState));
}
}
else
{
dwErr = GetLastError();
if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
rc = VINF_SUCCESS;
else
{
}
}
}
else
return rc;
}
/**
* Deletes the service.
*
* @returns VBox status code.
*/
int suplibOsDeleteService(void)
{
/*
* Assume it didn't exist, so we'll create the service.
*/
int rc;
if (hSMgr)
{
if (hService)
{
/*
* Delete the service.
*/
if (DeleteService(hService))
rc = VINF_SUCCESS;
else
{
dwErr = GetLastError();
}
}
else
{
dwErr = GetLastError();
if (dwErr == ERROR_SERVICE_DOES_NOT_EXIST)
rc = VINF_SUCCESS;
else
{
}
}
}
return rc;
}
#if 0
/**
* Creates the service.
*
* @returns 0 on success.
* @returns -1 on failure.
*/
static int suplibOsUpdateService(void)
{
/*
* Assume it didn't exist, so we'll create the service.
*/
if (hSMgr)
{
if (hService)
{
char szDriver[RTPATH_MAX];
if (RT_SUCCESS(rc))
{
{
return 0;
}
else
{
}
}
}
else
{
}
}
return -1;
}
#endif
/**
* Attempts to start the service, creating it if necessary.
*
* @returns VBox status code.
*/
static int suplibOsStartService(void)
{
/*
* Check if the driver service is there.
*/
{
AssertMsgFailed(("couldn't open service manager in SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS mode! (dwErr=%d)\n", dwErr));
return RTErrConvertFromWin32(dwErr);
}
/*
* Try open our service to check it's status.
*/
if (!hService)
{
/*
* Create the service.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Try open the service.
*/
}
/*
* Check if open and on demand create succeeded.
*/
int rc;
if (hService)
{
/*
* Query service status to see if we need to start it or not.
*/
else
{
rc = VINF_SUCCESS;
else
{
/*
* Start it.
*/
rc = VINF_SUCCESS;
else
{
}
}
/*
* Wait for the service to finish starting.
* We'll wait for 10 seconds then we'll give up.
*/
{
int iWait;
{
Sleep(100);
}
}
rc = VINF_SUCCESS;
else if (RT_SUCCESS_NP(rc))
}
/*
* Close open handles.
*/
}
else
{
}
if (!CloseServiceHandle(hSMgr))
AssertFailed();
return rc;
}
{
/*
* Check if we're inited at all.
*/
{
AssertFailed();
}
return VINF_SUCCESS;
}
{
/*
* Issue the device I/O control.
*/
# ifdef USE_NT_DEVICE_IO_CONTROL_FILE
Ios.Information = 0;
NTSTATUS rcNt = NtDeviceIoControlFile((HANDLE)pThis->hDevice, NULL /*hEvent*/, NULL /*pfnApc*/, NULL /*pvApcCtx*/, &Ios,
if (NT_SUCCESS(rcNt))
{
return VINF_SUCCESS;
}
return suplibConvertNtStatus(rcNt);
# else
if (DeviceIoControl((HANDLE)pThis->hDevice, uFunction, pvReq, pHdr->cbIn, pvReq, cbReturned, &cbReturned, NULL))
return 0;
return suplibConvertWin32Err(GetLastError());
# endif
}
{
/*
* Issue device I/O control.
*/
# ifdef USE_NT_DEVICE_IO_CONTROL_FILE
Ios.Information = 0;
NTSTATUS rcNt = NtDeviceIoControlFile((HANDLE)pThis->hDevice, NULL /*hEvent*/, NULL /*pfnApc*/, NULL /*pvApcCtx*/, &Ios,
if (NT_SUCCESS(rcNt))
{
return VINF_SUCCESS;
}
return suplibConvertNtStatus(rcNt);
# else
DWORD cbReturned = 0;
if (DeviceIoControl((HANDLE)pThis->hDevice, uFunction, NULL, 0, (LPVOID)idCpu, 0, &cbReturned, NULL))
return VINF_SUCCESS;
return suplibConvertWin32Err(GetLastError());
# endif
}
{
if (*ppvPages)
return VINF_SUCCESS;
return RTErrConvertFromWin32(GetLastError());
}
{
return VINF_SUCCESS;
return RTErrConvertFromWin32(GetLastError());
}
# ifndef USE_NT_DEVICE_IO_CONTROL_FILE
/**
* Converts a supdrv win32 error code to an IPRT status code.
*
* @returns corresponding IPRT error code.
* @param rc Win32 error code.
*/
{
/* Conversion program (link with ntdll.lib from ddk):
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <ntstatus.h>
#include <winternl.h>
#include <stdio.h>
int main()
{
#define CONVERT(a) printf(#a " %#x -> %d\n", a, RtlNtStatusToDosError((a)))
CONVERT(STATUS_SUCCESS);
CONVERT(STATUS_NOT_SUPPORTED);
CONVERT(STATUS_INVALID_PARAMETER);
CONVERT(STATUS_UNKNOWN_REVISION);
CONVERT(STATUS_INVALID_HANDLE);
CONVERT(STATUS_INVALID_ADDRESS);
CONVERT(STATUS_NOT_LOCKED);
CONVERT(STATUS_IMAGE_ALREADY_LOADED);
CONVERT(STATUS_ACCESS_DENIED);
CONVERT(STATUS_REVISION_MISMATCH);
return 0;
}
*/
switch (rc)
{
//case 0: return STATUS_SUCCESS;
case 0: return VINF_SUCCESS;
case ERROR_NOT_SUPPORTED: return VERR_GENERAL_FAILURE;
case ERROR_INVALID_PARAMETER: return VERR_INVALID_PARAMETER;
case ERROR_UNKNOWN_REVISION: return VERR_INVALID_MAGIC;
case ERROR_INVALID_HANDLE: return VERR_INVALID_HANDLE;
case ERROR_UNEXP_NET_ERR: return VERR_INVALID_POINTER;
case ERROR_NOT_LOCKED: return VERR_LOCK_FAILED;
case ERROR_SERVICE_ALREADY_RUNNING: return VERR_ALREADY_LOADED;
case ERROR_ACCESS_DENIED: return VERR_PERMISSION_DENIED;
case ERROR_REVISION_MISMATCH: return VERR_VERSION_MISMATCH;
}
/* fall back on the default conversion. */
return RTErrConvertFromWin32(rc);
}
# else
/**
* Reverse of VBoxDrvNtErr2NtStatus
* returns VBox status code.
* @param rcNt NT status code.
*/
{
switch (rcNt)
{
case STATUS_SUCCESS: return VINF_SUCCESS;
case STATUS_NOT_SUPPORTED: return VERR_GENERAL_FAILURE;
case STATUS_INVALID_PARAMETER: return VERR_INVALID_PARAMETER;
case STATUS_UNKNOWN_REVISION: return VERR_INVALID_MAGIC;
case STATUS_INVALID_HANDLE: return VERR_INVALID_HANDLE;
case STATUS_INVALID_ADDRESS: return VERR_INVALID_POINTER;
case STATUS_NOT_LOCKED: return VERR_LOCK_FAILED;
case STATUS_IMAGE_ALREADY_LOADED: return VERR_ALREADY_LOADED;
case STATUS_ACCESS_DENIED: return VERR_PERMISSION_DENIED;
case STATUS_REVISION_MISMATCH: return VERR_VERSION_MISMATCH;
}
/* See VBoxDrvNtErr2NtStatus. */
if (SUP_NT_STATUS_IS_VBOX(rcNt))
return SUP_NT_STATUS_TO_VBOX(rcNt);
/* Fall back on IPRT for the rest. */
return RTErrConvertFromNtStatus(rcNt);
}
# endif
#endif /* !IN_SUP_HARDENED_R3 */