VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp@ 64281

Last change on this file since 64281 was 64281, checked in by vboxsync, 8 years ago

IPRT,SUP: Major vboxdrv and GIP version change; more flexible processor group handling on Windows.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 193.6 KB
Line 
1/* $Id: SUPDrv-win.cpp 64281 2016-10-15 16:46:29Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Windows NT specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define IPRT_NT_MAP_TO_ZW
32#define LOG_GROUP LOG_GROUP_SUP_DRV
33#include "../SUPDrvInternal.h"
34#include <excpt.h>
35#include <ntimage.h>
36
37#include <iprt/assert.h>
38#include <iprt/avl.h>
39#include <iprt/ctype.h>
40#include <iprt/initterm.h>
41#include <iprt/mem.h>
42#include <iprt/process.h>
43#include <iprt/power.h>
44#include <iprt/rand.h>
45#include <iprt/semaphore.h>
46#include <iprt/spinlock.h>
47#include <iprt/string.h>
48#include <VBox/log.h>
49#include <VBox/err.h>
50
51#include <iprt/asm-amd64-x86.h>
52
53#ifdef VBOX_WITH_HARDENING
54# include "SUPHardenedVerify-win.h"
55#endif
56
57
58/*********************************************************************************************************************************
59* Defined Constants And Macros *
60*********************************************************************************************************************************/
61/** The support service name. */
62#define SERVICE_NAME "VBoxDrv"
63/** The Pool tag (VBox). */
64#define SUPDRV_NT_POOL_TAG 'xoBV'
65
66/** NT device name for user access. */
67#define DEVICE_NAME_NT_USR L"\\Device\\VBoxDrvU"
68#ifdef VBOX_WITH_HARDENING
69/** Macro for checking for deflecting calls to the stub device. */
70# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) \
71 do { if ((a_pDevObj) == g_pDevObjStub) \
72 return supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); \
73 } while (0)
74/** Macro for checking for deflecting calls to the stub and error info
75 * devices. */
76# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(a_pDevObj, a_pIrp) \
77 do { if ((a_pDevObj) == g_pDevObjStub || (a_pDevObj) == g_pDevObjErrorInfo) \
78 return supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); \
79 } while (0)
80#else
81# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) do {} while (0)
82# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(a_pDevObj, a_pIrp) do {} while (0)
83#endif
84
85/** Enables the fast I/O control code path. */
86#define VBOXDRV_WITH_FAST_IO
87
88
89/*********************************************************************************************************************************
90* Structures and Typedefs *
91*********************************************************************************************************************************/
92/**
93 * Device extension used by VBoxDrvU.
94 */
95typedef struct SUPDRVDEVEXTUSR
96{
97 /** Global cookie (same location as in SUPDRVDEVEXT, different value). */
98 uint32_t u32Cookie;
99 /** Pointer to the main driver extension. */
100 PSUPDRVDEVEXT pMainDrvExt;
101} SUPDRVDEVEXTUSR;
102AssertCompileMembersAtSameOffset(SUPDRVDEVEXT, u32Cookie, SUPDRVDEVEXTUSR, u32Cookie);
103/** Pointer to the VBoxDrvU device extension. */
104typedef SUPDRVDEVEXTUSR *PSUPDRVDEVEXTUSR;
105/** Value of SUPDRVDEVEXTUSR::u32Cookie. */
106#define SUPDRVDEVEXTUSR_COOKIE UINT32_C(0x12345678)
107
108/** Get the main device extension. */
109#define SUPDRVNT_GET_DEVEXT(pDevObj) \
110 ( pDevObj != g_pDevObjUsr \
111 ? (PSUPDRVDEVEXT)pDevObj->DeviceExtension \
112 : ((PSUPDRVDEVEXTUSR)pDevObj->DeviceExtension)->pMainDrvExt )
113
114#ifdef VBOX_WITH_HARDENING
115
116/**
117 * Device extension used by VBoxDrvStub.
118 */
119typedef struct SUPDRVDEVEXTSTUB
120{
121 /** Common header. */
122 SUPDRVDEVEXTUSR Common;
123} SUPDRVDEVEXTSTUB;
124/** Pointer to the VBoxDrvStub device extension. */
125typedef SUPDRVDEVEXTSTUB *PSUPDRVDEVEXTSTUB;
126/** Value of SUPDRVDEVEXTSTUB::Common.u32Cookie. */
127#define SUPDRVDEVEXTSTUB_COOKIE UINT32_C(0x90abcdef)
128
129
130/**
131 * Device extension used by VBoxDrvErrorInfo.
132 */
133typedef struct SUPDRVDEVEXTERRORINFO
134{
135 /** Common header. */
136 SUPDRVDEVEXTUSR Common;
137} SUPDRVDEVEXTERRORINFO;
138/** Pointer to the VBoxDrvErrorInfo device extension. */
139typedef SUPDRVDEVEXTERRORINFO *PSUPDRVDEVEXTERRORINFO;
140/** Value of SUPDRVDEVEXTERRORINFO::Common.u32Cookie. */
141#define SUPDRVDEVEXTERRORINFO_COOKIE UINT32_C(0xBadC0ca0)
142
143/**
144 * Error info for a failed VBoxDrv or VBoxDrvStub open attempt.
145 */
146typedef struct SUPDRVNTERRORINFO
147{
148 /** The list entry (in g_ErrorInfoHead). */
149 RTLISTNODE ListEntry;
150 /** The ID of the process this error info belongs to. */
151 HANDLE hProcessId;
152 /** The ID of the thread owning this info. */
153 HANDLE hThreadId;
154 /** Milliseconds createion timestamp (for cleaning up). */
155 uint64_t uCreatedMsTs;
156 /** Number of bytes of valid info. */
157 uint32_t cchErrorInfo;
158 /** The error info. */
159 char szErrorInfo[16384 - sizeof(RTLISTNODE) - sizeof(HANDLE)*2 - sizeof(uint64_t) - sizeof(uint32_t) - 0x20];
160} SUPDRVNTERRORINFO;
161/** Pointer to error info. */
162typedef SUPDRVNTERRORINFO *PSUPDRVNTERRORINFO;
163
164
165/**
166 * The kind of process we're protecting.
167 */
168typedef enum SUPDRVNTPROTECTKIND
169{
170 kSupDrvNtProtectKind_Invalid = 0,
171
172 /** Stub process protection while performing process verification.
173 * Next: StubSpawning (or free) */
174 kSupDrvNtProtectKind_StubUnverified,
175 /** Stub process protection before it creates the VM process.
176 * Next: StubParent, StubDead. */
177 kSupDrvNtProtectKind_StubSpawning,
178 /** Stub process protection while having a VM process as child.
179 * Next: StubDead */
180 kSupDrvNtProtectKind_StubParent,
181 /** Dead stub process. */
182 kSupDrvNtProtectKind_StubDead,
183
184 /** Potential VM process.
185 * Next: VmProcessConfirmed, VmProcessDead. */
186 kSupDrvNtProtectKind_VmProcessUnconfirmed,
187 /** Confirmed VM process.
188 * Next: VmProcessDead. */
189 kSupDrvNtProtectKind_VmProcessConfirmed,
190 /** Dead VM process. */
191 kSupDrvNtProtectKind_VmProcessDead,
192
193 /** End of valid protection kinds. */
194 kSupDrvNtProtectKind_End
195} SUPDRVNTPROTECTKIND;
196
197/**
198 * A NT process protection structure.
199 */
200typedef struct SUPDRVNTPROTECT
201{
202 /** The AVL node core structure. The process ID is the pid. */
203 AVLPVNODECORE AvlCore;
204 /** Magic value (SUPDRVNTPROTECT_MAGIC). */
205 uint32_t volatile u32Magic;
206 /** Reference counter. */
207 uint32_t volatile cRefs;
208 /** The kind of process we're protecting. */
209 SUPDRVNTPROTECTKIND volatile enmProcessKind;
210 /** Whether this structure is in the tree. */
211 bool fInTree : 1;
212 /** 7,: Hack to allow the supid themes service duplicate handle privileges to
213 * our process. */
214 bool fThemesFirstProcessCreateHandle : 1;
215 /** Vista, 7 & 8: Hack to allow more rights to the handle returned by
216 * NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
217 bool fFirstProcessCreateHandle : 1;
218 /** Vista, 7 & 8: Hack to allow more rights to the handle returned by
219 * NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
220 bool fFirstThreadCreateHandle : 1;
221 /** 8.1: Hack to allow more rights to the handle returned by
222 * NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
223 bool fCsrssFirstProcessCreateHandle : 1;
224 /** Vista, 7 & 8: Hack to allow more rights to the handle duplicated by CSRSS
225 * during process creation. Only applicable to VmProcessUnconfirmed. On
226 * 32-bit systems we allow two as ZoneAlarm's system call hooks has been
227 * observed to do some seemingly unnecessary duplication work. */
228 int32_t volatile cCsrssFirstProcessDuplicateHandle;
229
230 /** The parent PID for VM processes, otherwise NULL. */
231 HANDLE hParentPid;
232 /** The TID of the thread opening VBoxDrv or VBoxDrvStub, NULL if not opened. */
233 HANDLE hOpenTid;
234 /** The PID of the CSRSS process associated with this process. */
235 HANDLE hCsrssPid;
236 /** Pointer to the CSRSS process structure (referenced). */
237 PEPROCESS pCsrssProcess;
238 /** State dependent data. */
239 union
240 {
241 /** A stub process in the StubParent state will keep a reference to a child
242 * while it's in the VmProcessUnconfirmed state so that it can be cleaned up
243 * correctly if things doesn't work out. */
244 struct SUPDRVNTPROTECT *pChild;
245 /** A process in the VmProcessUnconfirmed state will keep a weak
246 * reference to the parent's protection structure so it can clean up the pChild
247 * reference the parent has to it. */
248 struct SUPDRVNTPROTECT *pParent;
249 } u;
250} SUPDRVNTPROTECT;
251/** Pointer to a NT process protection record. */
252typedef SUPDRVNTPROTECT *PSUPDRVNTPROTECT;
253/** The SUPDRVNTPROTECT::u32Magic value (Robert A. Heinlein). */
254# define SUPDRVNTPROTECT_MAGIC UINT32_C(0x19070707)
255/** The SUPDRVNTPROTECT::u32Magic value of a dead structure. */
256# define SUPDRVNTPROTECT_MAGIC_DEAD UINT32_C(0x19880508)
257
258/** Pointer to ObGetObjectType. */
259typedef POBJECT_TYPE (NTAPI *PFNOBGETOBJECTTYPE)(PVOID);
260/** Pointer to ObRegisterCallbacks. */
261typedef NTSTATUS (NTAPI *PFNOBREGISTERCALLBACKS)(POB_CALLBACK_REGISTRATION, PVOID *);
262/** Pointer to ObUnregisterCallbacks. */
263typedef VOID (NTAPI *PFNOBUNREGISTERCALLBACKS)(PVOID);
264/** Pointer to PsSetCreateProcessNotifyRoutineEx. */
265typedef NTSTATUS (NTAPI *PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)(PCREATE_PROCESS_NOTIFY_ROUTINE_EX, BOOLEAN);
266/** Pointer to PsReferenceProcessFilePointer. */
267typedef NTSTATUS (NTAPI *PFNPSREFERENCEPROCESSFILEPOINTER)(PEPROCESS, PFILE_OBJECT *);
268/** Pointer to PsIsProtectedProcessLight. */
269typedef BOOLEAN (NTAPI *PFNPSISPROTECTEDPROCESSLIGHT)(PEPROCESS);
270/** Pointer to ZwAlpcCreatePort. */
271typedef NTSTATUS (NTAPI *PFNZWALPCCREATEPORT)(PHANDLE, POBJECT_ATTRIBUTES, struct _ALPC_PORT_ATTRIBUTES *);
272
273#endif /* VBOX_WITH_HARDENINIG */
274
275
276/*********************************************************************************************************************************
277* Internal Functions *
278*********************************************************************************************************************************/
279static void _stdcall VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj);
280static NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
281static NTSTATUS _stdcall VBoxDrvNtCleanup(PDEVICE_OBJECT pDevObj, PIRP pIrp);
282static NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
283#ifdef VBOXDRV_WITH_FAST_IO
284static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOLEAN fWait, PVOID pvInput, ULONG cbInput,
285 PVOID pvOutput, ULONG cbOutput, ULONG uCmd,
286 PIO_STATUS_BLOCK pIoStatus, PDEVICE_OBJECT pDevObj);
287#endif
288static NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
289static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack);
290static NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
291static VOID _stdcall VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pArgument1, PVOID pArgument2);
292static NTSTATUS _stdcall VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp);
293static NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
294static NTSTATUS VBoxDrvNtErr2NtStatus(int rc);
295#ifdef VBOX_WITH_HARDENING
296static NTSTATUS supdrvNtProtectInit(void);
297static void supdrvNtProtectTerm(void);
298static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid,
299 SUPDRVNTPROTECTKIND enmProcessKind, bool fLink);
300static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect);
301static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid);
302static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect);
303static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect);
304
305static bool supdrvNtIsDebuggerAttached(void);
306static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId);
307
308#endif
309
310
311/*********************************************************************************************************************************
312* Exported Functions *
313*********************************************************************************************************************************/
314RT_C_DECLS_BEGIN
315NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
316RT_C_DECLS_END
317
318
319/*********************************************************************************************************************************
320* Global Variables *
321*********************************************************************************************************************************/
322/** Pointer to the system device instance. */
323static PDEVICE_OBJECT g_pDevObjSys = NULL;
324/** Pointer to the user device instance. */
325static PDEVICE_OBJECT g_pDevObjUsr = NULL;
326#ifdef VBOXDRV_WITH_FAST_IO
327/** Fast I/O dispatch table. */
328static FAST_IO_DISPATCH const g_VBoxDrvFastIoDispatch =
329{
330 /* .SizeOfFastIoDispatch = */ sizeof(g_VBoxDrvFastIoDispatch),
331 /* .FastIoCheckIfPossible = */ NULL,
332 /* .FastIoRead = */ NULL,
333 /* .FastIoWrite = */ NULL,
334 /* .FastIoQueryBasicInfo = */ NULL,
335 /* .FastIoQueryStandardInfo = */ NULL,
336 /* .FastIoLock = */ NULL,
337 /* .FastIoUnlockSingle = */ NULL,
338 /* .FastIoUnlockAll = */ NULL,
339 /* .FastIoUnlockAllByKey = */ NULL,
340 /* .FastIoDeviceControl = */ VBoxDrvNtFastIoDeviceControl,
341 /* .AcquireFileForNtCreateSection = */ NULL,
342 /* .ReleaseFileForNtCreateSection = */ NULL,
343 /* .FastIoDetachDevice = */ NULL,
344 /* .FastIoQueryNetworkOpenInfo = */ NULL,
345 /* .AcquireForModWrite = */ NULL,
346 /* .MdlRead = */ NULL,
347 /* .MdlReadComplete = */ NULL,
348 /* .PrepareMdlWrite = */ NULL,
349 /* .MdlWriteComplete = */ NULL,
350 /* .FastIoReadCompressed = */ NULL,
351 /* .FastIoWriteCompressed = */ NULL,
352 /* .MdlReadCompleteCompressed = */ NULL,
353 /* .MdlWriteCompleteCompressed = */ NULL,
354 /* .FastIoQueryOpen = */ NULL,
355 /* .ReleaseForModWrite = */ NULL,
356 /* .AcquireForCcFlush = */ NULL,
357 /* .ReleaseForCcFlush = */ NULL,
358};
359#endif /* VBOXDRV_WITH_FAST_IO */
360
361/** Default ZERO value. */
362static ULONG g_fOptDefaultZero = 0;
363/** Registry values.
364 * We wrap these in a struct to ensure they are followed by a little zero
365 * padding in order to limit the chance of trouble on unpatched systems. */
366struct
367{
368 /** The ForceAsync registry value. */
369 ULONG fOptForceAsyncTsc;
370 /** Padding. */
371 uint64_t au64Padding[2];
372} g_Options = { FALSE, 0, 0 };
373/** Registry query table for RtlQueryRegistryValues. */
374static RTL_QUERY_REGISTRY_TABLE g_aRegValues[] =
375{
376 {
377 /* .QueryRoutine = */ NULL,
378 /* .Flags = */ RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK,
379 /* .Name = */ L"ForceAsyncTsc",
380 /* .EntryContext = */ &g_Options.fOptForceAsyncTsc,
381 /* .DefaultType = */ (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD,
382 /* .DefaultData = */ &g_fOptDefaultZero,
383 /* .DefaultLength = */ sizeof(g_fOptDefaultZero),
384 },
385 { NULL, 0, NULL, NULL, 0, NULL, 0 } /* terminator entry. */
386};
387
388/** Pointer to KeQueryMaximumGroupCount. */
389static PFNKEQUERYMAXIMUMGROUPCOUNT g_pfnKeQueryMaximumGroupCount = NULL;
390/** Pointer to KeGetProcessorIndexFromNumber. */
391static PFNKEGETPROCESSORINDEXFROMNUMBER g_pfnKeGetProcessorIndexFromNumber = NULL;
392/** Pointer to KeGetProcessorNumberFromIndex. */
393static PFNKEGETPROCESSORNUMBERFROMINDEX g_pfnKeGetProcessorNumberFromIndex = NULL;
394
395#ifdef VBOX_WITH_HARDENING
396/** Pointer to the stub device instance. */
397static PDEVICE_OBJECT g_pDevObjStub = NULL;
398/** Spinlock protecting g_NtProtectTree as well as the releasing of protection
399 * structures. */
400static RTSPINLOCK g_hNtProtectLock = NIL_RTSPINLOCK;
401/** AVL tree of SUPDRVNTPROTECT structures. */
402static AVLPVTREE g_NtProtectTree = NULL;
403/** Cookie returned by ObRegisterCallbacks for the callbacks. */
404static PVOID g_pvObCallbacksCookie = NULL;
405/** Combined windows NT version number. See SUP_MAKE_NT_VER_COMBINED. */
406uint32_t g_uNtVerCombined = 0;
407/** Pointer to ObGetObjectType if available.. */
408static PFNOBGETOBJECTTYPE g_pfnObGetObjectType = NULL;
409/** Pointer to ObRegisterCallbacks if available.. */
410static PFNOBREGISTERCALLBACKS g_pfnObRegisterCallbacks = NULL;
411/** Pointer to ObUnregisterCallbacks if available.. */
412static PFNOBUNREGISTERCALLBACKS g_pfnObUnRegisterCallbacks = NULL;
413/** Pointer to PsSetCreateProcessNotifyRoutineEx if available.. */
414static PFNPSSETCREATEPROCESSNOTIFYROUTINEEX g_pfnPsSetCreateProcessNotifyRoutineEx = NULL;
415/** Pointer to PsReferenceProcessFilePointer if available. */
416static PFNPSREFERENCEPROCESSFILEPOINTER g_pfnPsReferenceProcessFilePointer = NULL;
417/** Pointer to PsIsProtectedProcessLight. */
418static PFNPSISPROTECTEDPROCESSLIGHT g_pfnPsIsProtectedProcessLight = NULL;
419/** Pointer to ZwAlpcCreatePort. */
420static PFNZWALPCCREATEPORT g_pfnZwAlpcCreatePort = NULL;
421
422# ifdef RT_ARCH_AMD64
423extern "C" {
424/** Pointer to KiServiceLinkage (used to fake missing ZwQueryVirtualMemory on
425 * XP64 / W2K3-64). */
426PFNRT g_pfnKiServiceLinkage = NULL;
427/** Pointer to KiServiceInternal (used to fake missing ZwQueryVirtualMemory on
428 * XP64 / W2K3-64) */
429PFNRT g_pfnKiServiceInternal = NULL;
430}
431# endif
432/** The primary ALPC port object type. (LpcPortObjectType at init time.) */
433static POBJECT_TYPE g_pAlpcPortObjectType1 = NULL;
434/** The secondary ALPC port object type. (Sampled at runtime.) */
435static POBJECT_TYPE volatile g_pAlpcPortObjectType2 = NULL;
436
437/** Pointer to the error information device instance. */
438static PDEVICE_OBJECT g_pDevObjErrorInfo = NULL;
439/** Fast mutex semaphore protecting the error info list. */
440static RTSEMMUTEX g_hErrorInfoLock = NIL_RTSEMMUTEX;
441/** Head of the error info (SUPDRVNTERRORINFO). */
442static RTLISTANCHOR g_ErrorInfoHead;
443
444#endif
445
446
447/**
448 * Takes care of creating the devices and their symbolic links.
449 *
450 * @returns NT status code.
451 * @param pDrvObj Pointer to driver object.
452 */
453static NTSTATUS vboxdrvNtCreateDevices(PDRIVER_OBJECT pDrvObj)
454{
455 /*
456 * System device.
457 */
458 UNICODE_STRING DevName;
459 RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_SYS);
460 NTSTATUS rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXT), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjSys);
461 if (NT_SUCCESS(rcNt))
462 {
463 /*
464 * User device.
465 */
466 RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_USR);
467 rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTUSR), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjUsr);
468 if (NT_SUCCESS(rcNt))
469 {
470 PSUPDRVDEVEXTUSR pDevExtUsr = (PSUPDRVDEVEXTUSR)g_pDevObjUsr->DeviceExtension;
471 pDevExtUsr->pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
472 pDevExtUsr->u32Cookie = SUPDRVDEVEXTUSR_COOKIE;
473
474#ifdef VBOX_WITH_HARDENING
475 /*
476 * Hardened stub device.
477 */
478 RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_STUB);
479 rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTSTUB), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjStub);
480 if (NT_SUCCESS(rcNt))
481 {
482 if (NT_SUCCESS(rcNt))
483 {
484 PSUPDRVDEVEXTSTUB pDevExtStub = (PSUPDRVDEVEXTSTUB)g_pDevObjStub->DeviceExtension;
485 pDevExtStub->Common.pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
486 pDevExtStub->Common.u32Cookie = SUPDRVDEVEXTSTUB_COOKIE;
487
488 /*
489 * Hardened error information device.
490 */
491 RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_ERROR_INFO);
492 rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTERRORINFO), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE,
493 &g_pDevObjErrorInfo);
494 if (NT_SUCCESS(rcNt))
495 {
496 g_pDevObjErrorInfo->Flags |= DO_BUFFERED_IO;
497
498 if (NT_SUCCESS(rcNt))
499 {
500 PSUPDRVDEVEXTERRORINFO pDevExtStub = (PSUPDRVDEVEXTERRORINFO)g_pDevObjStub->DeviceExtension;
501 pDevExtStub->Common.pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
502 pDevExtStub->Common.u32Cookie = SUPDRVDEVEXTERRORINFO_COOKIE;
503
504#endif
505 /* Done. */
506 return rcNt;
507#ifdef VBOX_WITH_HARDENING
508 }
509
510 /* Bail out. */
511 IoDeleteDevice(g_pDevObjErrorInfo);
512 g_pDevObjErrorInfo = NULL;
513 }
514 }
515
516 /* Bail out. */
517 IoDeleteDevice(g_pDevObjStub);
518 g_pDevObjUsr = NULL;
519 }
520 IoDeleteDevice(g_pDevObjUsr);
521 g_pDevObjUsr = NULL;
522#endif
523 }
524 IoDeleteDevice(g_pDevObjSys);
525 g_pDevObjSys = NULL;
526 }
527 return rcNt;
528}
529
530/**
531 * Destroys the devices and links created by vboxdrvNtCreateDevices.
532 */
533static void vboxdrvNtDestroyDevices(void)
534{
535 if (g_pDevObjUsr)
536 {
537 PSUPDRVDEVEXTUSR pDevExtUsr = (PSUPDRVDEVEXTUSR)g_pDevObjUsr->DeviceExtension;
538 pDevExtUsr->pMainDrvExt = NULL;
539 }
540#ifdef VBOX_WITH_HARDENING
541 if (g_pDevObjStub)
542 {
543 PSUPDRVDEVEXTSTUB pDevExtStub = (PSUPDRVDEVEXTSTUB)g_pDevObjStub->DeviceExtension;
544 pDevExtStub->Common.pMainDrvExt = NULL;
545 }
546 if (g_pDevObjErrorInfo)
547 {
548 PSUPDRVDEVEXTERRORINFO pDevExtErrorInfo = (PSUPDRVDEVEXTERRORINFO)g_pDevObjStub->DeviceExtension;
549 pDevExtErrorInfo->Common.pMainDrvExt = NULL;
550 }
551#endif
552
553#ifdef VBOX_WITH_HARDENING
554 IoDeleteDevice(g_pDevObjErrorInfo);
555 g_pDevObjErrorInfo = NULL;
556 IoDeleteDevice(g_pDevObjStub);
557 g_pDevObjStub = NULL;
558#endif
559 IoDeleteDevice(g_pDevObjUsr);
560 g_pDevObjUsr = NULL;
561 IoDeleteDevice(g_pDevObjSys);
562 g_pDevObjSys = NULL;
563}
564
565
566/**
567 * Driver entry point.
568 *
569 * @returns appropriate status code.
570 * @param pDrvObj Pointer to driver object.
571 * @param pRegPath Registry base path.
572 */
573NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
574{
575 RT_NOREF1(pRegPath);
576
577 /*
578 * Sanity checks.
579 */
580#ifdef VBOXDRV_WITH_FAST_IO
581 if (g_VBoxDrvFastIoDispatch.FastIoDeviceControl != VBoxDrvNtFastIoDeviceControl)
582 {
583 DbgPrint("VBoxDrv: FastIoDeviceControl=%p instead of %p\n",
584 g_VBoxDrvFastIoDispatch.FastIoDeviceControl, VBoxDrvNtFastIoDeviceControl);
585 return STATUS_INTERNAL_ERROR;
586 }
587#endif
588
589 /*
590 * Query options first so any overflows on unpatched machines will do less
591 * harm (see MS11-011 / 2393802 / 2011-03-18).
592 *
593 * Unfortunately, pRegPath isn't documented as zero terminated, even if it
594 * quite likely always is, so we have to make a copy here.
595 */
596 NTSTATUS rcNt;
597 PWSTR pwszCopy = (PWSTR)ExAllocatePoolWithTag(NonPagedPool, pRegPath->Length + sizeof(WCHAR), 'VBox');
598 if (pwszCopy)
599 {
600 memcpy(pwszCopy, pRegPath->Buffer, pRegPath->Length);
601 pwszCopy[pRegPath->Length / sizeof(WCHAR)] = '\0';
602 rcNt = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, pwszCopy,
603 g_aRegValues, NULL /*pvContext*/, NULL /*pvEnv*/);
604 ExFreePoolWithTag(pwszCopy, 'VBox');
605 /* Probably safe to ignore rcNt here. */
606 }
607
608 /*
609 * Resolve methods we want but isn't available everywhere.
610 */
611 UNICODE_STRING RoutineName;
612 RtlInitUnicodeString(&RoutineName, L"KeQueryMaximumGroupCount");
613 g_pfnKeQueryMaximumGroupCount = (PFNKEQUERYMAXIMUMGROUPCOUNT)MmGetSystemRoutineAddress(&RoutineName);
614
615 RtlInitUnicodeString(&RoutineName, L"KeGetProcessorIndexFromNumber");
616 g_pfnKeGetProcessorIndexFromNumber = (PFNKEGETPROCESSORINDEXFROMNUMBER)MmGetSystemRoutineAddress(&RoutineName);
617
618 RtlInitUnicodeString(&RoutineName, L"KeGetProcessorNumberFromIndex");
619 g_pfnKeGetProcessorNumberFromIndex = (PFNKEGETPROCESSORNUMBERFROMINDEX)MmGetSystemRoutineAddress(&RoutineName);
620
621 Assert( (g_pfnKeGetProcessorNumberFromIndex != NULL) == (g_pfnKeGetProcessorIndexFromNumber != NULL)
622 && (g_pfnKeGetProcessorNumberFromIndex != NULL) == (g_pfnKeQueryMaximumGroupCount != NULL)); /* all or nothing. */
623
624 /*
625 * Initialize the runtime (IPRT).
626 */
627 int vrc = RTR0Init(0);
628 if (RT_SUCCESS(vrc))
629 {
630 Log(("VBoxDrv::DriverEntry\n"));
631
632#ifdef VBOX_WITH_HARDENING
633 /*
634 * Initialize process protection.
635 */
636 rcNt = supdrvNtProtectInit();
637 if (NT_SUCCESS(rcNt))
638#endif
639 {
640 /*
641 * Create device.
642 * (That means creating a device object and a symbolic link so the DOS
643 * subsystems (OS/2, win32, ++) can access the device.)
644 */
645 rcNt = vboxdrvNtCreateDevices(pDrvObj);
646 if (NT_SUCCESS(rcNt))
647 {
648 /*
649 * Initialize the device extension.
650 */
651 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
652 memset(pDevExt, 0, sizeof(*pDevExt));
653
654 vrc = supdrvInitDevExt(pDevExt, sizeof(SUPDRVSESSION));
655 if (!vrc)
656 {
657 /*
658 * Setup the driver entry points in pDrvObj.
659 */
660 pDrvObj->DriverUnload = VBoxDrvNtUnload;
661 pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxDrvNtCreate;
662 pDrvObj->MajorFunction[IRP_MJ_CLEANUP] = VBoxDrvNtCleanup;
663 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxDrvNtClose;
664 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxDrvNtDeviceControl;
665 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = VBoxDrvNtInternalDeviceControl;
666 pDrvObj->MajorFunction[IRP_MJ_READ] = VBoxDrvNtRead;
667 pDrvObj->MajorFunction[IRP_MJ_WRITE] = VBoxDrvNtNotSupportedStub;
668
669#ifdef VBOXDRV_WITH_FAST_IO
670 /* Fast I/O to speed up guest execution roundtrips. */
671 pDrvObj->FastIoDispatch = (PFAST_IO_DISPATCH)&g_VBoxDrvFastIoDispatch;
672#endif
673
674 /*
675 * Register ourselves for power state changes. We don't
676 * currently care if this fails.
677 */
678 UNICODE_STRING CallbackName;
679 RtlInitUnicodeString(&CallbackName, L"\\Callback\\PowerState");
680
681 OBJECT_ATTRIBUTES Attr;
682 InitializeObjectAttributes(&Attr, &CallbackName, OBJ_CASE_INSENSITIVE, NULL, NULL);
683
684 rcNt = ExCreateCallback(&pDevExt->pObjPowerCallback, &Attr, TRUE, TRUE);
685 if (rcNt == STATUS_SUCCESS)
686 pDevExt->hPowerCallback = ExRegisterCallback(pDevExt->pObjPowerCallback,
687 VBoxPowerDispatchCallback,
688 g_pDevObjSys);
689
690 /*
691 * Done! Returning success!
692 */
693 Log(("VBoxDrv::DriverEntry returning STATUS_SUCCESS\n"));
694 return STATUS_SUCCESS;
695 }
696
697 Log(("supdrvInitDevExit failed with vrc=%d!\n", vrc));
698 rcNt = VBoxDrvNtErr2NtStatus(vrc);
699
700 vboxdrvNtDestroyDevices();
701 }
702#ifdef VBOX_WITH_HARDENING
703 supdrvNtProtectTerm();
704#endif
705 }
706 RTTermRunCallbacks(RTTERMREASON_UNLOAD, 0);
707 RTR0Term();
708 }
709 else
710 {
711 Log(("RTR0Init failed with vrc=%d!\n", vrc));
712 rcNt = VBoxDrvNtErr2NtStatus(vrc);
713 }
714 if (NT_SUCCESS(rcNt))
715 rcNt = STATUS_INVALID_PARAMETER;
716 return rcNt;
717}
718
719
720/**
721 * Unload the driver.
722 *
723 * @param pDrvObj Driver object.
724 */
725void _stdcall VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj)
726{
727 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
728
729 Log(("VBoxDrvNtUnload at irql %d\n", KeGetCurrentIrql()));
730
731 /* Clean up the power callback registration. */
732 if (pDevExt->hPowerCallback)
733 ExUnregisterCallback(pDevExt->hPowerCallback);
734 if (pDevExt->pObjPowerCallback)
735 ObDereferenceObject(pDevExt->pObjPowerCallback);
736
737 /*
738 * We ASSUME that it's not possible to unload a driver with open handles.
739 */
740 supdrvDeleteDevExt(pDevExt);
741#ifdef VBOX_WITH_HARDENING
742 supdrvNtProtectTerm();
743#endif
744 RTTermRunCallbacks(RTTERMREASON_UNLOAD, 0);
745 RTR0Term();
746 vboxdrvNtDestroyDevices();
747
748 NOREF(pDrvObj);
749}
750
751
752/**
753 * For simplifying request completion into a simple return statement, extended
754 * version.
755 *
756 * @returns rcNt
757 * @param rcNt The status code.
758 * @param uInfo Extra info value.
759 * @param pIrp The IRP.
760 */
761DECLINLINE(NTSTATUS) supdrvNtCompleteRequestEx(NTSTATUS rcNt, ULONG_PTR uInfo, PIRP pIrp)
762{
763 pIrp->IoStatus.Status = rcNt;
764 pIrp->IoStatus.Information = uInfo;
765 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
766 return rcNt;
767}
768
769
770/**
771 * For simplifying request completion into a simple return statement.
772 *
773 * @returns rcNt
774 * @param rcNt The status code.
775 * @param pIrp The IRP.
776 */
777DECLINLINE(NTSTATUS) supdrvNtCompleteRequest(NTSTATUS rcNt, PIRP pIrp)
778{
779 return supdrvNtCompleteRequestEx(rcNt, 0 /*uInfo*/, pIrp);
780}
781
782
783/**
784 * Create (i.e. Open) file entry point.
785 *
786 * @param pDevObj Device object.
787 * @param pIrp Request packet.
788 */
789NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
790{
791 Log(("VBoxDrvNtCreate: RequestorMode=%d\n", pIrp->RequestorMode));
792 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
793 PFILE_OBJECT pFileObj = pStack->FileObject;
794 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
795
796 /*
797 * We are not remotely similar to a directory...
798 * (But this is possible.)
799 */
800 if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
801 return supdrvNtCompleteRequest(STATUS_NOT_A_DIRECTORY, pIrp);
802
803 /*
804 * Don't create a session for kernel clients, they'll close the handle
805 * immediately and work with the file object via
806 * VBoxDrvNtInternalDeviceControl. The first request will be one to
807 * create a session.
808 */
809 NTSTATUS rcNt;
810 if (pIrp->RequestorMode == KernelMode)
811 {
812 if (pDevObj == g_pDevObjSys)
813 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
814
815 rcNt = STATUS_ACCESS_DENIED;
816 }
817#ifdef VBOX_WITH_HARDENING
818 /*
819 * Anyone can open the error device.
820 */
821 else if (pDevObj == g_pDevObjErrorInfo)
822 {
823 pFileObj->FsContext = NULL;
824 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
825 }
826#endif
827 else
828 {
829#if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
830 /*
831 * Make sure no debuggers are attached to non-user processes.
832 */
833 if ( pDevObj != g_pDevObjUsr
834 && supdrvNtIsDebuggerAttached())
835 {
836 LogRel(("vboxdrv: Process %p is being debugged, access to vboxdrv / vboxdrvu declined.\n",
837 PsGetProcessId(PsGetCurrentProcess())));
838 rcNt = STATUS_TRUST_FAILURE;
839 }
840 else
841#endif
842 {
843 int rc = VINF_SUCCESS;
844
845#ifdef VBOX_WITH_HARDENING
846 /*
847 * Access to the stub device is only granted to processes which
848 * passes verification.
849 *
850 * Note! The stub device has no need for a SUPDRVSESSION structure,
851 * so the it uses the SUPDRVNTPROTECT directly instead.
852 */
853 if (pDevObj == g_pDevObjStub)
854 {
855 PSUPDRVNTPROTECT pNtProtect = NULL;
856 rc = supdrvNtProtectCreate(&pNtProtect, PsGetProcessId(PsGetCurrentProcess()),
857 kSupDrvNtProtectKind_StubUnverified, true /*fLink*/);
858 if (RT_SUCCESS(rc))
859 {
860 rc = supdrvNtProtectFindAssociatedCsrss(pNtProtect);
861 if (RT_SUCCESS(rc))
862 rc = supdrvNtProtectVerifyProcess(pNtProtect);
863 if (RT_SUCCESS(rc))
864 {
865 pFileObj->FsContext = pNtProtect; /* Keeps reference. */
866 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
867 }
868
869 supdrvNtProtectRelease(pNtProtect);
870 }
871 LogRel(("vboxdrv: Declined %p access to VBoxDrvStub: rc=%d\n", PsGetProcessId(PsGetCurrentProcess()), rc));
872 }
873 /*
874 * Unrestricted access is only granted to a process in the
875 * VmProcessUnconfirmed state that checks out correctly and is
876 * allowed to transition to VmProcessConfirmed. Again, only one
877 * session per process.
878 */
879 else if (pDevObj != g_pDevObjUsr)
880 {
881 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(PsGetProcessId(PsGetCurrentProcess()));
882 if (pNtProtect)
883 {
884 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
885 {
886 rc = supdrvNtProtectVerifyProcess(pNtProtect);
887 if (RT_SUCCESS(rc))
888 {
889 /* Create a session. */
890 PSUPDRVSESSION pSession;
891 rc = supdrvCreateSession(pDevExt, true /*fUser*/, pDevObj == g_pDevObjSys /*fUnrestricted*/,
892 &pSession);
893 if (RT_SUCCESS(rc))
894 {
895 rc = supdrvSessionHashTabInsert(pDevExt, pSession, (PSUPDRVSESSION *)&pFileObj->FsContext, NULL);
896 supdrvSessionRelease(pSession);
897 if (RT_SUCCESS(rc))
898 {
899 pSession->pNtProtect = pNtProtect; /* Keeps reference. */
900 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
901 }
902 }
903
904 /* No second attempt. */
905 RTSpinlockAcquire(g_hNtProtectLock);
906 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessConfirmed)
907 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
908 RTSpinlockRelease(g_hNtProtectLock);
909
910 LogRel(("vboxdrv: supdrvCreateSession failed for process %p: rc=%d.\n",
911 PsGetProcessId(PsGetCurrentProcess()), rc));
912 }
913 else
914 LogRel(("vboxdrv: Process %p failed process verification: rc=%d.\n",
915 PsGetProcessId(PsGetCurrentProcess()), rc));
916 }
917 else
918 {
919 LogRel(("vboxdrv: %p is not a budding VM process (enmProcessKind=%d).\n",
920 PsGetProcessId(PsGetCurrentProcess()), pNtProtect->enmProcessKind));
921 rc = VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_2;
922 }
923 supdrvNtProtectRelease(pNtProtect);
924 }
925 else
926 {
927 LogRel(("vboxdrv: %p is not a budding VM process.\n", PsGetProcessId(PsGetCurrentProcess())));
928 rc = VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_1;
929 }
930 }
931 /*
932 * Call common code to create an unprivileged session.
933 */
934 else
935 {
936 PSUPDRVSESSION pSession;
937 rc = supdrvCreateSession(pDevExt, true /*fUser*/, false /*fUnrestricted*/, &pSession);
938 if (RT_SUCCESS(rc))
939 {
940 rc = supdrvSessionHashTabInsert(pDevExt, pSession, (PSUPDRVSESSION *)&pFileObj->FsContext, NULL);
941 supdrvSessionRelease(pSession);
942 if (RT_SUCCESS(rc))
943 {
944 pFileObj->FsContext = pSession; /* Keeps reference. No race. */
945 pSession->pNtProtect = NULL;
946 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
947 }
948 }
949 }
950
951#else /* !VBOX_WITH_HARDENING */
952 /*
953 * Call common code to create a session.
954 */
955 pFileObj->FsContext = NULL;
956 PSUPDRVSESSION pSession;
957 rc = supdrvCreateSession(pDevExt, true /*fUser*/, pDevObj == g_pDevObjSys /*fUnrestricted*/, &pSession);
958 if (RT_SUCCESS(rc))
959 {
960 rc = supdrvSessionHashTabInsert(pDevExt, pSession, (PSUPDRVSESSION *)&pFileObj->FsContext, NULL);
961 supdrvSessionRelease(pSession);
962 if (RT_SUCCESS(rc))
963 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
964
965 }
966#endif /* !VBOX_WITH_HARDENING */
967
968 /* bail out */
969 rcNt = VBoxDrvNtErr2NtStatus(rc);
970 }
971 }
972
973 Assert(!NT_SUCCESS(rcNt));
974 pFileObj->FsContext = NULL;
975 return supdrvNtCompleteRequest(rcNt, pIrp); /* Note. the IoStatus is completely ignored on error. */
976}
977
978
979/**
980 * Clean up file handle entry point.
981 *
982 * @param pDevObj Device object.
983 * @param pIrp Request packet.
984 */
985NTSTATUS _stdcall VBoxDrvNtCleanup(PDEVICE_OBJECT pDevObj, PIRP pIrp)
986{
987 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
988 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
989 PFILE_OBJECT pFileObj = pStack->FileObject;
990
991#ifdef VBOX_WITH_HARDENING
992 if (pDevObj == g_pDevObjStub)
993 {
994 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)pFileObj->FsContext;
995 Log(("VBoxDrvNtCleanup: pDevExt=%p pFileObj=%p pNtProtect=%p\n", pDevExt, pFileObj, pNtProtect));
996 if (pNtProtect)
997 {
998 supdrvNtProtectRelease(pNtProtect);
999 pFileObj->FsContext = NULL;
1000 }
1001 }
1002 else if (pDevObj == g_pDevObjErrorInfo)
1003 supdrvNtErrorInfoCleanupProcess(PsGetCurrentProcessId());
1004 else
1005#endif
1006 {
1007 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
1008 (PSUPDRVSESSION *)&pFileObj->FsContext);
1009 Log(("VBoxDrvNtCleanup: pDevExt=%p pFileObj=%p pSession=%p\n", pDevExt, pFileObj, pSession));
1010 if (pSession)
1011 {
1012 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
1013 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
1014 }
1015 }
1016
1017 return supdrvNtCompleteRequest(STATUS_SUCCESS, pIrp);
1018}
1019
1020
1021/**
1022 * Close file entry point.
1023 *
1024 * @param pDevObj Device object.
1025 * @param pIrp Request packet.
1026 */
1027NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1028{
1029 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
1030 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1031 PFILE_OBJECT pFileObj = pStack->FileObject;
1032
1033#ifdef VBOX_WITH_HARDENING
1034 if (pDevObj == g_pDevObjStub)
1035 {
1036 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)pFileObj->FsContext;
1037 Log(("VBoxDrvNtClose: pDevExt=%p pFileObj=%p pNtProtect=%p\n", pDevExt, pFileObj, pNtProtect));
1038 if (pNtProtect)
1039 {
1040 supdrvNtProtectRelease(pNtProtect);
1041 pFileObj->FsContext = NULL;
1042 }
1043 }
1044 else if (pDevObj == g_pDevObjErrorInfo)
1045 supdrvNtErrorInfoCleanupProcess(PsGetCurrentProcessId());
1046 else
1047#endif
1048 {
1049 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
1050 (PSUPDRVSESSION *)&pFileObj->FsContext);
1051 Log(("VBoxDrvNtCleanup: pDevExt=%p pFileObj=%p pSession=%p\n", pDevExt, pFileObj, pSession));
1052 if (pSession)
1053 {
1054 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
1055 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
1056 }
1057 }
1058
1059 return supdrvNtCompleteRequest(STATUS_SUCCESS, pIrp);
1060}
1061
1062
1063#ifdef VBOXDRV_WITH_FAST_IO
1064/**
1065 * Fast I/O device control callback.
1066 *
1067 * This performs no buffering, neither on the way in or out.
1068 *
1069 * @returns TRUE if handled, FALSE if the normal I/O control routine should be
1070 * called.
1071 * @param pFileObj The file object.
1072 * @param fWait Whether it's a blocking call
1073 * @param pvInput The input buffer as specified by the user.
1074 * @param cbInput The size of the input buffer.
1075 * @param pvOutput The output buffer as specfied by the user.
1076 * @param cbOutput The size of the output buffer.
1077 * @param uCmd The I/O command/function being invoked.
1078 * @param pIoStatus Where to return the status of the operation.
1079 * @param pDevObj The device object..
1080 */
1081static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOLEAN fWait, PVOID pvInput, ULONG cbInput,
1082 PVOID pvOutput, ULONG cbOutput, ULONG uCmd,
1083 PIO_STATUS_BLOCK pIoStatus, PDEVICE_OBJECT pDevObj)
1084{
1085 RT_NOREF1(fWait);
1086
1087 /*
1088 * Only the normal devices, not the stub or error info ones.
1089 */
1090 if (pDevObj != g_pDevObjSys && pDevObj != g_pDevObjUsr)
1091 {
1092 pIoStatus->Status = STATUS_NOT_SUPPORTED;
1093 pIoStatus->Information = 0;
1094 return TRUE;
1095 }
1096
1097 /*
1098 * Check the input a little bit and get a the session references.
1099 */
1100 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
1101 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
1102 (PSUPDRVSESSION *)&pFileObj->FsContext);
1103 if (!pSession)
1104 {
1105 pIoStatus->Status = STATUS_TRUST_FAILURE;
1106 pIoStatus->Information = 0;
1107 return TRUE;
1108 }
1109
1110 if (pSession->fUnrestricted)
1111 {
1112#if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
1113 if (supdrvNtIsDebuggerAttached())
1114 {
1115 pIoStatus->Status = STATUS_TRUST_FAILURE;
1116 pIoStatus->Information = 0;
1117 supdrvSessionRelease(pSession);
1118 return TRUE;
1119 }
1120#endif
1121
1122 /*
1123 * Deal with the 2-3 high-speed IOCtl that takes their arguments from
1124 * the session and iCmd, and does not return anything.
1125 */
1126 if ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
1127 || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
1128 || uCmd == SUP_IOCTL_FAST_DO_NOP)
1129 {
1130 int rc = supdrvIOCtlFast(uCmd, (unsigned)(uintptr_t)pvOutput/* VMCPU id */, pDevExt, pSession);
1131 pIoStatus->Status = RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER;
1132 pIoStatus->Information = 0; /* Could be used to pass rc if we liked. */
1133 supdrvSessionRelease(pSession);
1134 return TRUE;
1135 }
1136 }
1137
1138 /*
1139 * The normal path.
1140 */
1141 NTSTATUS rcNt;
1142 unsigned cbOut = 0;
1143 int rc = 0;
1144 Log2(("VBoxDrvNtFastIoDeviceControl(%p): ioctl=%#x pvIn=%p cbIn=%#x pvOut=%p cbOut=%#x pSession=%p\n",
1145 pDevExt, uCmd, pvInput, cbInput, pvOutput, cbOutput, pSession));
1146
1147# ifdef RT_ARCH_AMD64
1148 /* Don't allow 32-bit processes to do any I/O controls. */
1149 if (!IoIs32bitProcess(NULL))
1150# endif
1151 {
1152 /*
1153 * In this fast I/O device control path we have to do our own buffering.
1154 */
1155 /* Verify that the I/O control function matches our pattern. */
1156 if ((uCmd & 0x3) == METHOD_BUFFERED)
1157 {
1158 /* Get the header so we can validate it a little bit against the
1159 parameters before allocating any memory kernel for the reqest. */
1160 SUPREQHDR Hdr;
1161 if (cbInput >= sizeof(Hdr) && cbOutput >= sizeof(Hdr))
1162 {
1163 __try
1164 {
1165 RtlCopyMemory(&Hdr, pvInput, sizeof(Hdr));
1166 rcNt = STATUS_SUCCESS;
1167 }
1168 __except(EXCEPTION_EXECUTE_HANDLER)
1169 {
1170 rcNt = GetExceptionCode();
1171 Hdr.cbIn = Hdr.cbOut = 0; /* shut up MSC */
1172 }
1173 }
1174 else
1175 {
1176 Hdr.cbIn = Hdr.cbOut = 0; /* shut up MSC */
1177 rcNt = STATUS_INVALID_PARAMETER;
1178 }
1179 if (NT_SUCCESS(rcNt))
1180 {
1181 /* Verify that the sizes in the request header are correct. */
1182 ULONG cbBuf = RT_MAX(cbInput, cbOutput);
1183 if ( cbInput == Hdr.cbIn
1184 && cbOutput == Hdr.cbOut
1185 && cbBuf < _1M*16)
1186 {
1187 /* Allocate a buffer and copy all the input into it. */
1188 PSUPREQHDR pHdr = (PSUPREQHDR)ExAllocatePoolWithTag(NonPagedPool, cbBuf, 'VBox');
1189 if (pHdr)
1190 {
1191 __try
1192 {
1193 RtlCopyMemory(pHdr, pvInput, cbInput);
1194 if (cbInput < cbBuf)
1195 RtlZeroMemory((uint8_t *)pHdr + cbInput, cbBuf - cbInput);
1196 if (!memcmp(pHdr, &Hdr, sizeof(Hdr)))
1197 rcNt = STATUS_SUCCESS;
1198 else
1199 rcNt = STATUS_INVALID_PARAMETER;
1200 }
1201 __except(EXCEPTION_EXECUTE_HANDLER)
1202 {
1203 rcNt = GetExceptionCode();
1204 }
1205 if (NT_SUCCESS(rcNt))
1206 {
1207 /*
1208 * Now call the common code to do the real work.
1209 */
1210 rc = supdrvIOCtl(uCmd, pDevExt, pSession, pHdr, cbBuf);
1211 if (RT_SUCCESS(rc))
1212 {
1213 /*
1214 * Copy back the result.
1215 */
1216 cbOut = pHdr->cbOut;
1217 if (cbOut > cbOutput)
1218 {
1219 cbOut = cbOutput;
1220 OSDBGPRINT(("VBoxDrvNtFastIoDeviceControl: too much output! %#x > %#x; uCmd=%#x!\n",
1221 pHdr->cbOut, cbOut, uCmd));
1222 }
1223 if (cbOut)
1224 {
1225 __try
1226 {
1227 RtlCopyMemory(pvOutput, pHdr, cbOut);
1228 rcNt = STATUS_SUCCESS;
1229 }
1230 __except(EXCEPTION_EXECUTE_HANDLER)
1231 {
1232 rcNt = GetExceptionCode();
1233 }
1234 }
1235 else
1236 rcNt = STATUS_SUCCESS;
1237 }
1238 else if (rc == VERR_INVALID_PARAMETER)
1239 rcNt = STATUS_INVALID_PARAMETER;
1240 else
1241 rcNt = STATUS_NOT_SUPPORTED;
1242 Log2(("VBoxDrvNtFastIoDeviceControl: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
1243 }
1244 else
1245 Log(("VBoxDrvNtFastIoDeviceControl: Error reading %u bytes of user memory at %p (uCmd=%#x)\n",
1246 cbInput, pvInput, uCmd));
1247 ExFreePoolWithTag(pHdr, 'VBox');
1248 }
1249 else
1250 rcNt = STATUS_NO_MEMORY;
1251 }
1252 else
1253 {
1254 Log(("VBoxDrvNtFastIoDeviceControl: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
1255 uCmd, Hdr.cbIn, Hdr.cbOut, cbInput, cbOutput));
1256 rcNt = STATUS_INVALID_PARAMETER;
1257 }
1258 }
1259 }
1260 else
1261 {
1262 Log(("VBoxDrvNtFastIoDeviceControl: not buffered request (%#x) - not supported\n", uCmd));
1263 rcNt = STATUS_NOT_SUPPORTED;
1264 }
1265 }
1266# ifdef RT_ARCH_AMD64
1267 else
1268 {
1269 Log(("VBoxDrvNtFastIoDeviceControl: WOW64 req - not supported\n"));
1270 rcNt = STATUS_NOT_SUPPORTED;
1271 }
1272# endif
1273
1274 /* complete the request. */
1275 pIoStatus->Status = rcNt;
1276 pIoStatus->Information = cbOut;
1277 supdrvSessionRelease(pSession);
1278 return TRUE; /* handled. */
1279}
1280#endif /* VBOXDRV_WITH_FAST_IO */
1281
1282
1283/**
1284 * Device I/O Control entry point.
1285 *
1286 * @param pDevObj Device object.
1287 * @param pIrp Request packet.
1288 */
1289NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1290{
1291 VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(pDevObj, pIrp);
1292
1293 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
1294 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1295 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
1296 (PSUPDRVSESSION *)&pStack->FileObject->FsContext);
1297
1298 if (!RT_VALID_PTR(pSession))
1299 return supdrvNtCompleteRequest(STATUS_TRUST_FAILURE, pIrp);
1300
1301 /*
1302 * Deal with the 2-3 high-speed IOCtl that takes their arguments from
1303 * the session and iCmd, and does not return anything.
1304 */
1305 if (pSession->fUnrestricted)
1306 {
1307#if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
1308 if (supdrvNtIsDebuggerAttached())
1309 {
1310 supdrvSessionRelease(pSession);
1311 return supdrvNtCompleteRequest(STATUS_TRUST_FAILURE, pIrp);
1312 }
1313#endif
1314
1315 ULONG ulCmd = pStack->Parameters.DeviceIoControl.IoControlCode;
1316 if ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
1317 || ulCmd == SUP_IOCTL_FAST_DO_HM_RUN
1318 || ulCmd == SUP_IOCTL_FAST_DO_NOP)
1319 {
1320 int rc = supdrvIOCtlFast(ulCmd, (unsigned)(uintptr_t)pIrp->UserBuffer /* VMCPU id */, pDevExt, pSession);
1321
1322 /* Complete the I/O request. */
1323 supdrvSessionRelease(pSession);
1324 return supdrvNtCompleteRequest(RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER, pIrp);
1325 }
1326 }
1327
1328 return VBoxDrvNtDeviceControlSlow(pDevExt, pSession, pIrp, pStack);
1329}
1330
1331
1332/**
1333 * Worker for VBoxDrvNtDeviceControl that takes the slow IOCtl functions.
1334 *
1335 * @returns NT status code.
1336 *
1337 * @param pDevExt Device extension.
1338 * @param pSession The session.
1339 * @param pIrp Request packet.
1340 * @param pStack The stack location containing the DeviceControl parameters.
1341 */
1342static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack)
1343{
1344 NTSTATUS rcNt;
1345 unsigned cbOut = 0;
1346 int rc = 0;
1347 Log2(("VBoxDrvNtDeviceControlSlow(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
1348 pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
1349 pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
1350 pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
1351
1352#ifdef RT_ARCH_AMD64
1353 /* Don't allow 32-bit processes to do any I/O controls. */
1354 if (!IoIs32bitProcess(pIrp))
1355#endif
1356 {
1357 /* Verify that it's a buffered CTL. */
1358 if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
1359 {
1360 /* Verify that the sizes in the request header are correct. */
1361 PSUPREQHDR pHdr = (PSUPREQHDR)pIrp->AssociatedIrp.SystemBuffer;
1362 if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
1363 && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cbIn
1364 && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cbOut)
1365 {
1366 /* Zero extra output bytes to make sure we don't leak anything. */
1367 if (pHdr->cbIn < pHdr->cbOut)
1368 RtlZeroMemory((uint8_t *)pHdr + pHdr->cbIn, pHdr->cbOut - pHdr->cbIn);
1369
1370 /*
1371 * Do the job.
1372 */
1373 rc = supdrvIOCtl(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr,
1374 RT_MAX(pHdr->cbIn, pHdr->cbOut));
1375 if (!rc)
1376 {
1377 rcNt = STATUS_SUCCESS;
1378 cbOut = pHdr->cbOut;
1379 if (cbOut > pStack->Parameters.DeviceIoControl.OutputBufferLength)
1380 {
1381 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
1382 OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n",
1383 pHdr->cbOut, cbOut, pStack->Parameters.DeviceIoControl.IoControlCode));
1384 }
1385 }
1386 else
1387 rcNt = STATUS_INVALID_PARAMETER;
1388 Log2(("VBoxDrvNtDeviceControlSlow: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
1389 }
1390 else
1391 {
1392 Log(("VBoxDrvNtDeviceControlSlow: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
1393 pStack->Parameters.DeviceIoControl.IoControlCode,
1394 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbIn : 0,
1395 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbOut : 0,
1396 pStack->Parameters.DeviceIoControl.InputBufferLength,
1397 pStack->Parameters.DeviceIoControl.OutputBufferLength));
1398 rcNt = STATUS_INVALID_PARAMETER;
1399 }
1400 }
1401 else
1402 {
1403 Log(("VBoxDrvNtDeviceControlSlow: not buffered request (%#x) - not supported\n",
1404 pStack->Parameters.DeviceIoControl.IoControlCode));
1405 rcNt = STATUS_NOT_SUPPORTED;
1406 }
1407 }
1408#ifdef RT_ARCH_AMD64
1409 else
1410 {
1411 Log(("VBoxDrvNtDeviceControlSlow: WOW64 req - not supported\n"));
1412 rcNt = STATUS_NOT_SUPPORTED;
1413 }
1414#endif
1415
1416 /* complete the request. */
1417 pIrp->IoStatus.Status = rcNt;
1418 pIrp->IoStatus.Information = cbOut;
1419 supdrvSessionRelease(pSession);
1420 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1421 return rcNt;
1422}
1423
1424
1425/**
1426 * Internal Device I/O Control entry point, used for IDC.
1427 *
1428 * @param pDevObj Device object.
1429 * @param pIrp Request packet.
1430 */
1431NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1432{
1433 VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(pDevObj, pIrp);
1434
1435 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
1436 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1437 PFILE_OBJECT pFileObj = pStack ? pStack->FileObject : NULL;
1438 PSUPDRVSESSION pSession = pFileObj ? (PSUPDRVSESSION)pFileObj->FsContext : NULL;
1439 NTSTATUS rcNt;
1440 unsigned cbOut = 0;
1441 int rc = 0;
1442 Log2(("VBoxDrvNtInternalDeviceControl(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
1443 pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
1444 pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
1445 pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
1446
1447 /* Verify that it's a buffered CTL. */
1448 if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
1449 {
1450 /* Verify the pDevExt in the session. */
1451 if ( pStack->Parameters.DeviceIoControl.IoControlCode != SUPDRV_IDC_REQ_CONNECT
1452 ? VALID_PTR(pSession) && pSession->pDevExt == pDevExt
1453 : !pSession
1454 )
1455 {
1456 /* Verify that the size in the request header is correct. */
1457 PSUPDRVIDCREQHDR pHdr = (PSUPDRVIDCREQHDR)pIrp->AssociatedIrp.SystemBuffer;
1458 if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
1459 && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cb
1460 && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cb)
1461 {
1462 /*
1463 * Call the generic code.
1464 *
1465 * Note! Connect and disconnect requires some extra attention
1466 * in order to get the session handling right.
1467 */
1468 if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_DISCONNECT)
1469 pFileObj->FsContext = NULL;
1470
1471 rc = supdrvIDC(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr);
1472 if (!rc)
1473 {
1474 if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_CONNECT)
1475 pFileObj->FsContext = ((PSUPDRVIDCREQCONNECT)pHdr)->u.Out.pSession;
1476
1477 rcNt = STATUS_SUCCESS;
1478 cbOut = pHdr->cb;
1479 }
1480 else
1481 {
1482 rcNt = STATUS_INVALID_PARAMETER;
1483 if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_DISCONNECT)
1484 pFileObj->FsContext = pSession;
1485 }
1486 Log2(("VBoxDrvNtInternalDeviceControl: returns %#x/rc=%#x\n", rcNt, rc));
1487 }
1488 else
1489 {
1490 Log(("VBoxDrvNtInternalDeviceControl: Mismatching sizes (%#x) - Hdr=%#lx Irp=%#lx/%#lx!\n",
1491 pStack->Parameters.DeviceIoControl.IoControlCode,
1492 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cb : 0,
1493 pStack->Parameters.DeviceIoControl.InputBufferLength,
1494 pStack->Parameters.DeviceIoControl.OutputBufferLength));
1495 rcNt = STATUS_INVALID_PARAMETER;
1496 }
1497 }
1498 else
1499 rcNt = STATUS_NOT_SUPPORTED;
1500 }
1501 else
1502 {
1503 Log(("VBoxDrvNtInternalDeviceControl: not buffered request (%#x) - not supported\n",
1504 pStack->Parameters.DeviceIoControl.IoControlCode));
1505 rcNt = STATUS_NOT_SUPPORTED;
1506 }
1507
1508 /* complete the request. */
1509 pIrp->IoStatus.Status = rcNt;
1510 pIrp->IoStatus.Information = cbOut;
1511 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1512 return rcNt;
1513}
1514
1515
1516/**
1517 * Implementation of the read major function for VBoxDrvErrorInfo.
1518 *
1519 * This is a stub function for the other devices.
1520 *
1521 * @returns NT status code.
1522 * @param pDevObj The device object.
1523 * @param pIrp The I/O request packet.
1524 */
1525NTSTATUS _stdcall VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1526{
1527 Log(("VBoxDrvNtRead\n"));
1528 RT_NOREF1(pDevObj);
1529
1530 NTSTATUS rcNt;
1531 pIrp->IoStatus.Information = 0;
1532
1533#ifdef VBOX_WITH_HARDENING
1534 /*
1535 * VBoxDrvErrorInfo?
1536 */
1537 if (pDevObj == g_pDevObjErrorInfo)
1538 {
1539 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1540 if ( pStack
1541 && (pIrp->Flags & IRP_BUFFERED_IO))
1542 {
1543 /*
1544 * Look up the process error information.
1545 */
1546 HANDLE hCurThreadId = PsGetCurrentThreadId();
1547 HANDLE hCurProcessId = PsGetCurrentProcessId();
1548 int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
1549 if (RT_SUCCESS(rc))
1550 {
1551 PSUPDRVNTERRORINFO pCur;
1552 RTListForEach(&g_ErrorInfoHead, pCur, SUPDRVNTERRORINFO, ListEntry)
1553 {
1554 if ( pCur->hProcessId == hCurProcessId
1555 && pCur->hThreadId == hCurThreadId)
1556 break;
1557 }
1558
1559 /*
1560 * Did we find error info and is the caller requesting data within it?
1561 * If so, check the destination buffer and copy the data into it.
1562 */
1563 if ( pCur
1564 && pStack->Parameters.Read.ByteOffset.QuadPart < pCur->cchErrorInfo
1565 && pStack->Parameters.Read.ByteOffset.QuadPart >= 0)
1566 {
1567 PVOID pvDstBuf = pIrp->AssociatedIrp.SystemBuffer;
1568 if (pvDstBuf)
1569 {
1570 uint32_t offRead = (uint32_t)pStack->Parameters.Read.ByteOffset.QuadPart;
1571 uint32_t cbToRead = pCur->cchErrorInfo - offRead;
1572 if (cbToRead < pStack->Parameters.Read.Length)
1573 RT_BZERO((uint8_t *)pvDstBuf + cbToRead, pStack->Parameters.Read.Length - cbToRead);
1574 else
1575 cbToRead = pStack->Parameters.Read.Length;
1576 memcpy(pvDstBuf, &pCur->szErrorInfo[offRead], cbToRead);
1577 pIrp->IoStatus.Information = cbToRead;
1578
1579 rcNt = STATUS_SUCCESS;
1580 }
1581 else
1582 rcNt = STATUS_INVALID_ADDRESS;
1583 }
1584 /*
1585 * End of file. Free the info.
1586 */
1587 else if (pCur)
1588 {
1589 RTListNodeRemove(&pCur->ListEntry);
1590 RTMemFree(pCur);
1591 rcNt = STATUS_END_OF_FILE;
1592 }
1593 /*
1594 * We found no error info. Return EOF.
1595 */
1596 else
1597 rcNt = STATUS_END_OF_FILE;
1598
1599 RTSemMutexRelease(g_hErrorInfoLock);
1600 }
1601 else
1602 rcNt = STATUS_UNSUCCESSFUL;
1603
1604 /* Paranoia: Clear the buffer on failure. */
1605 if (!NT_SUCCESS(rcNt))
1606 {
1607 PVOID pvDstBuf = pIrp->AssociatedIrp.SystemBuffer;
1608 if ( pvDstBuf
1609 && pStack->Parameters.Read.Length)
1610 RT_BZERO(pvDstBuf, pStack->Parameters.Read.Length);
1611 }
1612 }
1613 else
1614 rcNt = STATUS_INVALID_PARAMETER;
1615 }
1616 else
1617#endif /* VBOX_WITH_HARDENING */
1618 {
1619 /*
1620 * Stub.
1621 */
1622 rcNt = STATUS_NOT_SUPPORTED;
1623 }
1624
1625 /*
1626 * Complete the request.
1627 */
1628 pIrp->IoStatus.Status = rcNt;
1629 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1630 return rcNt;
1631}
1632
1633
1634/**
1635 * Stub function for functions we don't implemented.
1636 *
1637 * @returns STATUS_NOT_SUPPORTED
1638 * @param pDevObj Device object.
1639 * @param pIrp IRP.
1640 */
1641NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1642{
1643 Log(("VBoxDrvNtNotSupportedStub\n"));
1644 NOREF(pDevObj);
1645
1646 pIrp->IoStatus.Information = 0;
1647 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1648 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1649
1650 return STATUS_NOT_SUPPORTED;
1651}
1652
1653
1654/**
1655 * ExRegisterCallback handler for power events
1656 *
1657 * @param pCallbackContext User supplied parameter (pDevObj)
1658 * @param pvArgument1 First argument
1659 * @param pvArgument2 Second argument
1660 */
1661VOID _stdcall VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pvArgument1, PVOID pvArgument2)
1662{
1663 /*PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCallbackContext;*/ RT_NOREF1(pCallbackContext);
1664 Log(("VBoxPowerDispatchCallback: %x %x\n", pvArgument1, pvArgument2));
1665
1666 /* Power change imminent? */
1667 if ((uintptr_t)pvArgument1 == PO_CB_SYSTEM_STATE_LOCK)
1668 {
1669 if (pvArgument2 == NULL)
1670 Log(("VBoxPowerDispatchCallback: about to go into suspend mode!\n"));
1671 else
1672 Log(("VBoxPowerDispatchCallback: resumed!\n"));
1673
1674 /* Inform any clients that have registered themselves with IPRT. */
1675 RTPowerSignalEvent(pvArgument2 == NULL ? RTPOWEREVENT_SUSPEND : RTPOWEREVENT_RESUME);
1676 }
1677}
1678
1679
1680/**
1681 * Called to clean up the session structure before it's freed.
1682 *
1683 * @param pDevExt The device globals.
1684 * @param pSession The session that's being cleaned up.
1685 */
1686void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1687{
1688#ifdef VBOX_WITH_HARDENING
1689 if (pSession->pNtProtect)
1690 {
1691 supdrvNtProtectRelease(pSession->pNtProtect);
1692 pSession->pNtProtect = NULL;
1693 }
1694 RT_NOREF1(pDevExt);
1695#else
1696 RT_NOREF2(pDevExt, pSession);
1697#endif
1698}
1699
1700
1701void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
1702{
1703 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
1704}
1705
1706
1707void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
1708{
1709 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
1710}
1711
1712
1713size_t VBOXCALL supdrvOSGipGetGroupTableSize(PSUPDRVDEVEXT pDevExt)
1714{
1715 NOREF(pDevExt);
1716 uint32_t cMaxCpus = RTMpGetCount();
1717 uint32_t cGroups = RTMpGetMaxCpuGroupCount();
1718
1719 return cGroups * RT_OFFSETOF(SUPGIPCPUGROUP, aiCpuSetIdxs)
1720 + RT_SIZEOFMEMB(SUPGIPCPUGROUP, aiCpuSetIdxs[0]) * cMaxCpus;
1721}
1722
1723
1724int VBOXCALL supdrvOSInitGipGroupTable(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, size_t cbGipCpuGroups)
1725{
1726 Assert(cbGipCpuGroups > 0); NOREF(cbGipCpuGroups); NOREF(pDevExt);
1727
1728 unsigned const cGroups = RTMpGetMaxCpuGroupCount();
1729 AssertReturn(cGroups > 0 && cGroups < RT_ELEMENTS(pGip->aoffCpuGroup), VERR_INTERNAL_ERROR_2);
1730 pGip->cPossibleCpuGroups = cGroups;
1731
1732 PSUPGIPCPUGROUP pGroup = (PSUPGIPCPUGROUP)&pGip->aCPUs[pGip->cCpus];
1733 for (uint32_t idxGroup = 0; idxGroup < cGroups; idxGroup++)
1734 {
1735 uint32_t cActive = 0;
1736 uint32_t cMax = RTMpGetCpuGroupCounts(idxGroup, &cActive);
1737 uint32_t cbNeeded = RT_OFFSETOF(SUPGIPCPUGROUP, aiCpuSetIdxs[cMax]);
1738 AssertReturn(cbNeeded <= cbGipCpuGroups, VERR_INTERNAL_ERROR_3);
1739 AssertReturn(cActive <= cMax, VERR_INTERNAL_ERROR_4);
1740
1741 pGip->aoffCpuGroup[idxGroup] = (uint16_t)((uintptr_t)pGroup - (uintptr_t)pGip);
1742 pGroup->cMembers = cActive;
1743 pGroup->cMaxMembers = cMax;
1744 for (uint32_t idxMember = 0; idxMember < cMax; idxMember++)
1745 {
1746 pGroup->aiCpuSetIdxs[idxMember] = RTMpSetIndexFromCpuGroupMember(idxGroup, idxMember);
1747 Assert((unsigned)pGroup->aiCpuSetIdxs[idxMember] < pGip->cPossibleCpus);
1748 }
1749
1750 /* advance. */
1751 cbGipCpuGroups -= cbNeeded;
1752 pGroup = (PSUPGIPCPUGROUP)&pGroup->aiCpuSetIdxs[cMax];
1753 }
1754
1755 return VINF_SUCCESS;
1756}
1757
1758
1759void VBOXCALL supdrvOSGipInitGroupBitsForCpu(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pGipCpu)
1760{
1761 NOREF(pDevExt);
1762
1763 /*
1764 * Translate the CPU index into a group and member.
1765 */
1766 PROCESSOR_NUMBER ProcNum = { 0, pGipCpu->iCpuSet, 0 };
1767 if (g_pfnKeGetProcessorNumberFromIndex)
1768 {
1769 NTSTATUS rcNt = g_pfnKeGetProcessorNumberFromIndex(pGipCpu->iCpuSet, &ProcNum);
1770 if (NT_SUCCESS(rcNt))
1771 Assert(ProcNum.Group < g_pfnKeQueryMaximumGroupCount());
1772 else
1773 {
1774 AssertFailed();
1775 ProcNum.Group = 0;
1776 ProcNum.Number = pGipCpu->iCpuSet;
1777 }
1778 }
1779 pGipCpu->iCpuGroup = ProcNum.Group;
1780 pGipCpu->iCpuGroupMember = ProcNum.Number;
1781
1782 /*
1783 * Update the group info. Just do this wholesale for now (doesn't scale well).
1784 */
1785 for (uint32_t idxGroup = 0; idxGroup < pGip->cPossibleCpuGroups; idxGroup++)
1786 if (pGip->aoffCpuGroup[idxGroup] != UINT16_MAX)
1787 {
1788 PSUPGIPCPUGROUP pGroup = (PSUPGIPCPUGROUP)((uintptr_t)pGip + pGip->aoffCpuGroup[idxGroup]);
1789
1790 uint32_t cActive = 0;
1791 uint32_t cMax = RTMpGetCpuGroupCounts(idxGroup, &cActive);
1792 AssertStmt(cMax == pGroup->cMaxMembers, cMax = pGroup->cMaxMembers);
1793 AssertStmt(cActive <= cMax, cActive = cMax);
1794 if (pGroup->cMembers != cActive)
1795 pGroup->cMembers = cActive;
1796
1797 for (uint32_t idxMember = 0; idxMember < cMax; idxMember++)
1798 {
1799 int idxCpuSet = RTMpSetIndexFromCpuGroupMember(idxGroup, idxMember);
1800 AssertMsg((unsigned)idxCpuSet < pGip->cPossibleCpus,
1801 ("%d vs %d for %u.%u\n", idxCpuSet, pGip->cPossibleCpus, idxGroup, idxMember));
1802
1803 if (pGroup->aiCpuSetIdxs[idxMember] != idxCpuSet)
1804 pGroup->aiCpuSetIdxs[idxMember] = idxCpuSet;
1805 }
1806 }
1807}
1808
1809
1810/**
1811 * Initializes any OS specific object creator fields.
1812 */
1813void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
1814{
1815 NOREF(pObj);
1816 NOREF(pSession);
1817}
1818
1819
1820/**
1821 * Checks if the session can access the object.
1822 *
1823 * @returns true if a decision has been made.
1824 * @returns false if the default access policy should be applied.
1825 *
1826 * @param pObj The object in question.
1827 * @param pSession The session wanting to access the object.
1828 * @param pszObjName The object name, can be NULL.
1829 * @param prc Where to store the result when returning true.
1830 */
1831bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
1832{
1833 NOREF(pObj);
1834 NOREF(pSession);
1835 NOREF(pszObjName);
1836 NOREF(prc);
1837 return false;
1838}
1839
1840
1841/**
1842 * Force async tsc mode (stub).
1843 */
1844bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
1845{
1846 RT_NOREF1(pDevExt);
1847 return g_Options.fOptForceAsyncTsc != 0;
1848}
1849
1850
1851/**
1852 * Whether the host takes CPUs offline during a suspend/resume operation.
1853 */
1854bool VBOXCALL supdrvOSAreCpusOfflinedOnSuspend(void)
1855{
1856 return false;
1857}
1858
1859
1860/**
1861 * Whether the hardware TSC has been synchronized by the OS.
1862 */
1863bool VBOXCALL supdrvOSAreTscDeltasInSync(void)
1864{
1865 /* If IPRT didn't find KeIpiGenericCall we pretend windows(, the firmware,
1866 or whoever) always configures TSCs perfectly. */
1867 return !RTMpOnPairIsConcurrentExecSupported();
1868}
1869
1870
1871#define MY_SystemLoadGdiDriverInSystemSpaceInformation 54
1872#define MY_SystemUnloadGdiDriverInformation 27
1873
1874typedef struct MYSYSTEMGDIDRIVERINFO
1875{
1876 UNICODE_STRING Name; /**< In: image file name. */
1877 PVOID ImageAddress; /**< Out: the load address. */
1878 PVOID SectionPointer; /**< Out: section object. */
1879 PVOID EntryPointer; /**< Out: entry point address. */
1880 PVOID ExportSectionPointer; /**< Out: export directory/section. */
1881 ULONG ImageLength; /**< Out: SizeOfImage. */
1882} MYSYSTEMGDIDRIVERINFO;
1883
1884extern "C" __declspec(dllimport) NTSTATUS NTAPI ZwSetSystemInformation(ULONG, PVOID, ULONG);
1885
1886int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1887{
1888 pImage->pvNtSectionObj = NULL;
1889 pImage->hMemLock = NIL_RTR0MEMOBJ;
1890
1891#ifdef VBOX_WITHOUT_NATIVE_R0_LOADER
1892# ifndef RT_ARCH_X86
1893# error "VBOX_WITHOUT_NATIVE_R0_LOADER is only safe on x86."
1894# endif
1895 NOREF(pDevExt); NOREF(pszFilename); NOREF(pImage);
1896 return VERR_NOT_SUPPORTED;
1897
1898#else
1899 /*
1900 * Convert the filename from DOS UTF-8 to NT UTF-16.
1901 */
1902 size_t cwcFilename;
1903 int rc = RTStrCalcUtf16LenEx(pszFilename, RTSTR_MAX, &cwcFilename);
1904 if (RT_FAILURE(rc))
1905 return rc;
1906
1907 PRTUTF16 pwcsFilename = (PRTUTF16)RTMemTmpAlloc((4 + cwcFilename + 1) * sizeof(RTUTF16));
1908 if (!pwcsFilename)
1909 return VERR_NO_TMP_MEMORY;
1910
1911 pwcsFilename[0] = '\\';
1912 pwcsFilename[1] = '?';
1913 pwcsFilename[2] = '?';
1914 pwcsFilename[3] = '\\';
1915 PRTUTF16 pwcsTmp = &pwcsFilename[4];
1916 rc = RTStrToUtf16Ex(pszFilename, RTSTR_MAX, &pwcsTmp, cwcFilename + 1, NULL);
1917 if (RT_SUCCESS(rc))
1918 {
1919 /*
1920 * Try load it.
1921 */
1922 MYSYSTEMGDIDRIVERINFO Info;
1923 RtlInitUnicodeString(&Info.Name, pwcsFilename);
1924 Info.ImageAddress = NULL;
1925 Info.SectionPointer = NULL;
1926 Info.EntryPointer = NULL;
1927 Info.ExportSectionPointer = NULL;
1928 Info.ImageLength = 0;
1929
1930 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemLoadGdiDriverInSystemSpaceInformation, &Info, sizeof(Info));
1931 if (NT_SUCCESS(rcNt))
1932 {
1933 pImage->pvImage = Info.ImageAddress;
1934 pImage->pvNtSectionObj = Info.SectionPointer;
1935 Log(("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ls'\n",
1936 Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer));
1937# ifdef DEBUG_bird
1938 SUPR0Printf("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ws'\n",
1939 Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer);
1940# endif
1941 if (pImage->cbImageBits == Info.ImageLength)
1942 {
1943 /*
1944 * Lock down the entire image, just to be on the safe side.
1945 */
1946 rc = RTR0MemObjLockKernel(&pImage->hMemLock, pImage->pvImage, pImage->cbImageBits, RTMEM_PROT_READ);
1947 if (RT_FAILURE(rc))
1948 {
1949 pImage->hMemLock = NIL_RTR0MEMOBJ;
1950 supdrvOSLdrUnload(pDevExt, pImage);
1951 }
1952 }
1953 else
1954 {
1955 supdrvOSLdrUnload(pDevExt, pImage);
1956 rc = VERR_LDR_MISMATCH_NATIVE;
1957 }
1958 }
1959 else
1960 {
1961 Log(("rcNt=%#x '%ls'\n", rcNt, pwcsFilename));
1962 SUPR0Printf("VBoxDrv: rcNt=%x '%ws'\n", rcNt, pwcsFilename);
1963 switch (rcNt)
1964 {
1965 case /* 0xc0000003 */ STATUS_INVALID_INFO_CLASS:
1966# ifdef RT_ARCH_AMD64
1967 /* Unwind will crash and BSOD, so no fallback here! */
1968 rc = VERR_NOT_IMPLEMENTED;
1969# else
1970 /*
1971 * Use the old way of loading the modules.
1972 *
1973 * Note! We do *NOT* try class 26 because it will probably
1974 * not work correctly on terminal servers and such.
1975 */
1976 rc = VERR_NOT_SUPPORTED;
1977# endif
1978 break;
1979 case /* 0xc0000034 */ STATUS_OBJECT_NAME_NOT_FOUND:
1980 rc = VERR_MODULE_NOT_FOUND;
1981 break;
1982 case /* 0xC0000263 */ STATUS_DRIVER_ENTRYPOINT_NOT_FOUND:
1983 rc = VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND;
1984 break;
1985 case /* 0xC0000428 */ STATUS_INVALID_IMAGE_HASH:
1986 rc = VERR_LDR_IMAGE_HASH;
1987 break;
1988 case /* 0xC000010E */ STATUS_IMAGE_ALREADY_LOADED:
1989 Log(("WARNING: see @bugref{4853} for cause of this failure on Windows 7 x64\n"));
1990 rc = VERR_ALREADY_LOADED;
1991 break;
1992 default:
1993 rc = VERR_LDR_GENERAL_FAILURE;
1994 break;
1995 }
1996
1997 pImage->pvNtSectionObj = NULL;
1998 }
1999 }
2000
2001 RTMemTmpFree(pwcsFilename);
2002 NOREF(pDevExt);
2003 return rc;
2004#endif
2005}
2006
2007
2008void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
2009{
2010 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
2011}
2012
2013void VBOXCALL supdrvOSLdrNotifyUnloaded(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2014{
2015 NOREF(pDevExt); NOREF(pImage);
2016}
2017
2018int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
2019{
2020 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
2021 return VINF_SUCCESS;
2022}
2023
2024
2025/**
2026 * memcmp + errormsg + log.
2027 *
2028 * @returns Same as memcmp.
2029 * @param pImage The image.
2030 * @param pbImageBits The image bits ring-3 uploads.
2031 * @param uRva The RVA to start comparing at.
2032 * @param cb The number of bytes to compare.
2033 * @param pReq The load request.
2034 */
2035static int supdrvNtCompare(PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, uint32_t uRva, uint32_t cb, PSUPLDRLOAD pReq)
2036{
2037 int iDiff = memcmp((uint8_t const *)pImage->pvImage + uRva, pbImageBits + uRva, cb);
2038 if (iDiff)
2039 {
2040 uint32_t cbLeft = cb;
2041 const uint8_t *pbNativeBits = (const uint8_t *)pImage->pvImage;
2042 for (size_t off = uRva; cbLeft > 0; off++, cbLeft--)
2043 if (pbNativeBits[off] != pbImageBits[off])
2044 {
2045 /* Note! We need to copy image bits into a temporary stack buffer here as we'd
2046 otherwise risk overwriting them while formatting the error message. */
2047 uint8_t abBytes[64];
2048 memcpy(abBytes, &pbImageBits[off], RT_MIN(64, cbLeft));
2049 supdrvLdrLoadError(VERR_LDR_MISMATCH_NATIVE, pReq,
2050 "Mismatch at %#x (%p) of %s loaded at %p:\n"
2051 "ntld: %.*Rhxs\n"
2052 "iprt: %.*Rhxs",
2053 off, &pbNativeBits[off], pImage->szName, pImage->pvImage,
2054 RT_MIN(64, cbLeft), &pbNativeBits[off],
2055 RT_MIN(64, cbLeft), &abBytes[0]);
2056 SUPR0Printf("VBoxDrv: %s", pReq->u.Out.szError);
2057 break;
2058 }
2059 }
2060 return iDiff;
2061}
2062
2063
2064int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
2065{
2066 NOREF(pDevExt);
2067 if (pImage->pvNtSectionObj)
2068 {
2069 /*
2070 * Usually, the entire image matches exactly.
2071 */
2072 if (!memcmp(pImage->pvImage, pbImageBits, pImage->cbImageBits))
2073 return VINF_SUCCESS;
2074
2075 /*
2076 * On Windows 10 the ImageBase member of the optional header is sometimes
2077 * updated with the actual load address and sometimes not. Try compare
2078 *
2079 */
2080 uint32_t const offNtHdrs = *(uint16_t *)pbImageBits == IMAGE_DOS_SIGNATURE
2081 ? ((IMAGE_DOS_HEADER const *)pbImageBits)->e_lfanew
2082 : 0;
2083 AssertLogRelReturn(offNtHdrs + sizeof(IMAGE_NT_HEADERS) < pImage->cbImageBits, VERR_INTERNAL_ERROR_5);
2084 IMAGE_NT_HEADERS const *pNtHdrsIprt = (IMAGE_NT_HEADERS const *)(pbImageBits + offNtHdrs);
2085 IMAGE_NT_HEADERS const *pNtHdrsNtLd = (IMAGE_NT_HEADERS const *)((uintptr_t)pImage->pvImage + offNtHdrs);
2086
2087 uint32_t const offImageBase = offNtHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS, OptionalHeader.ImageBase);
2088 uint32_t const cbImageBase = RT_SIZEOFMEMB(IMAGE_NT_HEADERS, OptionalHeader.ImageBase);
2089 if ( pNtHdrsNtLd->OptionalHeader.ImageBase != pNtHdrsIprt->OptionalHeader.ImageBase
2090 && ( pNtHdrsNtLd->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage
2091 || pNtHdrsIprt->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage)
2092 && pNtHdrsIprt->Signature == IMAGE_NT_SIGNATURE
2093 && pNtHdrsIprt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
2094 && !memcmp(pImage->pvImage, pbImageBits, offImageBase)
2095 && !memcmp((uint8_t const *)pImage->pvImage + offImageBase + cbImageBase,
2096 pbImageBits + offImageBase + cbImageBase,
2097 pImage->cbImageBits - offImageBase - cbImageBase))
2098 return VINF_SUCCESS;
2099
2100 /*
2101 * On Windows Server 2003 (sp2 x86) both import thunk tables are fixed
2102 * up and we typically get a mismatch in the INIT section.
2103 *
2104 * So, lets see if everything matches when excluding the
2105 * OriginalFirstThunk tables and (maybe) the ImageBase member.
2106 * For simplicity the max number of exclusion regions is set to 16.
2107 */
2108 if ( pNtHdrsIprt->Signature == IMAGE_NT_SIGNATURE
2109 && pNtHdrsIprt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
2110 && pNtHdrsIprt->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT
2111 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR)
2112 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress > sizeof(IMAGE_NT_HEADERS)
2113 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress < pImage->cbImageBits
2114 )
2115 {
2116 struct MyRegion
2117 {
2118 uint32_t uRva;
2119 uint32_t cb;
2120 } aExcludeRgns[16];
2121 unsigned cExcludeRgns = 0;
2122
2123 /* ImageBase: */
2124 if ( pNtHdrsNtLd->OptionalHeader.ImageBase != pNtHdrsIprt->OptionalHeader.ImageBase
2125 && ( pNtHdrsNtLd->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage
2126 || pNtHdrsIprt->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage) )
2127 {
2128 aExcludeRgns[cExcludeRgns].uRva = offImageBase;
2129 aExcludeRgns[cExcludeRgns].cb = cbImageBase;
2130 cExcludeRgns++;
2131 }
2132
2133 /* Imports: */
2134 uint32_t cImpsLeft = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
2135 / sizeof(IMAGE_IMPORT_DESCRIPTOR);
2136 uint32_t offImps = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
2137 AssertLogRelReturn(offImps + cImpsLeft * sizeof(IMAGE_IMPORT_DESCRIPTOR) <= pImage->cbImageBits, VERR_INTERNAL_ERROR_3);
2138 IMAGE_IMPORT_DESCRIPTOR const *pImp = (IMAGE_IMPORT_DESCRIPTOR const *)(pbImageBits + offImps);
2139 while ( cImpsLeft-- > 0
2140 && cExcludeRgns < RT_ELEMENTS(aExcludeRgns))
2141 {
2142 uint32_t uRvaThunk = pImp->OriginalFirstThunk;
2143 if ( uRvaThunk > sizeof(IMAGE_NT_HEADERS)
2144 && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA)
2145 && uRvaThunk != pImp->FirstThunk)
2146 {
2147 /* Find the size of the thunk table. */
2148 IMAGE_THUNK_DATA const *paThunk = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk);
2149 uint32_t cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA);
2150 uint32_t cThunks = 0;
2151 while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
2152 cThunks++;
2153
2154 /* Ordered table insert. */
2155 unsigned i = 0;
2156 for (; i < cExcludeRgns; i++)
2157 if (uRvaThunk < aExcludeRgns[i].uRva)
2158 break;
2159 if (i != cExcludeRgns)
2160 memmove(&aExcludeRgns[i + 1], &aExcludeRgns[i], (cExcludeRgns - i) * sizeof(aExcludeRgns[0]));
2161 aExcludeRgns[i].uRva = uRvaThunk;
2162 aExcludeRgns[i].cb = cThunks * sizeof(IMAGE_THUNK_DATA);
2163 cExcludeRgns++;
2164 }
2165
2166 /* advance */
2167 pImp++;
2168 }
2169
2170 /*
2171 * Ok, do the comparison.
2172 */
2173 int iDiff = 0;
2174 uint32_t uRvaNext = 0;
2175 for (unsigned i = 0; !iDiff && i < cExcludeRgns; i++)
2176 {
2177 if (uRvaNext < aExcludeRgns[i].uRva)
2178 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, aExcludeRgns[i].uRva - uRvaNext, pReq);
2179 uRvaNext = aExcludeRgns[i].uRva + aExcludeRgns[i].cb;
2180 }
2181 if (!iDiff && uRvaNext < pImage->cbImageBits)
2182 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, pImage->cbImageBits - uRvaNext, pReq);
2183 if (!iDiff)
2184 return VINF_SUCCESS;
2185 }
2186 else
2187 supdrvNtCompare(pImage, pbImageBits, 0, pImage->cbImageBits, pReq);
2188 return VERR_LDR_MISMATCH_NATIVE;
2189 }
2190 return supdrvLdrLoadError(VERR_INTERNAL_ERROR_4, pReq, "No NT section object! Impossible!");
2191}
2192
2193
2194void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2195{
2196 if (pImage->pvNtSectionObj)
2197 {
2198 if (pImage->hMemLock != NIL_RTR0MEMOBJ)
2199 {
2200 RTR0MemObjFree(pImage->hMemLock, false /*fFreeMappings*/);
2201 pImage->hMemLock = NIL_RTR0MEMOBJ;
2202 }
2203
2204 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemUnloadGdiDriverInformation,
2205 &pImage->pvNtSectionObj, sizeof(pImage->pvNtSectionObj));
2206 if (rcNt != STATUS_SUCCESS)
2207 SUPR0Printf("VBoxDrv: failed to unload '%s', rcNt=%#x\n", pImage->szName, rcNt);
2208 pImage->pvNtSectionObj = NULL;
2209 }
2210 NOREF(pDevExt);
2211}
2212
2213
2214#ifdef SUPDRV_WITH_MSR_PROBER
2215
2216#if 1
2217/** @todo make this selectable. */
2218# define AMD_MSR_PASSCODE 0x9c5a203a
2219#else
2220# define ASMRdMsrEx(a, b, c) ASMRdMsr(a)
2221# define ASMWrMsrEx(a, b, c) ASMWrMsr(a,c)
2222#endif
2223
2224
2225/**
2226 * Argument package used by supdrvOSMsrProberRead and supdrvOSMsrProberWrite.
2227 */
2228typedef struct SUPDRVNTMSPROBERARGS
2229{
2230 uint32_t uMsr;
2231 uint64_t uValue;
2232 bool fGp;
2233} SUPDRVNTMSPROBERARGS;
2234
2235/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberRead.} */
2236static DECLCALLBACK(void) supdrvNtMsProberReadOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2237{
2238 /*
2239 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
2240 * (At least on 32-bit XP.)
2241 */
2242 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
2243 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
2244 __try
2245 {
2246 pArgs->uValue = ASMRdMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE);
2247 pArgs->fGp = false;
2248 }
2249 __except(EXCEPTION_EXECUTE_HANDLER)
2250 {
2251 pArgs->fGp = true;
2252 pArgs->uValue = 0;
2253 }
2254 ASMSetFlags(fOldFlags);
2255}
2256
2257
2258int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
2259{
2260 SUPDRVNTMSPROBERARGS Args;
2261 Args.uMsr = uMsr;
2262 Args.uValue = 0;
2263 Args.fGp = true;
2264
2265 if (idCpu == NIL_RTCPUID)
2266 supdrvNtMsProberReadOnCpu(idCpu, &Args, NULL);
2267 else
2268 {
2269 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberReadOnCpu, &Args, NULL);
2270 if (RT_FAILURE(rc))
2271 return rc;
2272 }
2273
2274 if (Args.fGp)
2275 return VERR_ACCESS_DENIED;
2276 *puValue = Args.uValue;
2277 return VINF_SUCCESS;
2278}
2279
2280
2281/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberWrite.} */
2282static DECLCALLBACK(void) supdrvNtMsProberWriteOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2283{
2284 /*
2285 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
2286 * (At least on 32-bit XP.)
2287 */
2288 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
2289 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
2290 __try
2291 {
2292 ASMWrMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE, pArgs->uValue);
2293 pArgs->fGp = false;
2294 }
2295 __except(EXCEPTION_EXECUTE_HANDLER)
2296 {
2297 pArgs->fGp = true;
2298 }
2299 ASMSetFlags(fOldFlags);
2300}
2301
2302int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
2303{
2304 SUPDRVNTMSPROBERARGS Args;
2305 Args.uMsr = uMsr;
2306 Args.uValue = uValue;
2307 Args.fGp = true;
2308
2309 if (idCpu == NIL_RTCPUID)
2310 supdrvNtMsProberWriteOnCpu(idCpu, &Args, NULL);
2311 else
2312 {
2313 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberWriteOnCpu, &Args, NULL);
2314 if (RT_FAILURE(rc))
2315 return rc;
2316 }
2317
2318 if (Args.fGp)
2319 return VERR_ACCESS_DENIED;
2320 return VINF_SUCCESS;
2321}
2322
2323/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberModify.} */
2324static DECLCALLBACK(void) supdrvNtMsProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2325{
2326 PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
2327 register uint32_t uMsr = pReq->u.In.uMsr;
2328 bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
2329 uint64_t uBefore = 0;
2330 uint64_t uWritten = 0;
2331 uint64_t uAfter = 0;
2332 bool fBeforeGp = true;
2333 bool fModifyGp = true;
2334 bool fAfterGp = true;
2335 bool fRestoreGp = true;
2336 RTCCUINTREG fOldFlags;
2337 RT_NOREF2(idCpu, pvUser2);
2338
2339 /*
2340 * Do the job.
2341 */
2342 fOldFlags = ASMIntDisableFlags();
2343 ASMCompilerBarrier(); /* paranoia */
2344 if (!fFaster)
2345 ASMWriteBackAndInvalidateCaches();
2346
2347 __try
2348 {
2349 uBefore = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
2350 fBeforeGp = false;
2351 }
2352 __except(EXCEPTION_EXECUTE_HANDLER)
2353 {
2354 fBeforeGp = true;
2355 }
2356 if (!fBeforeGp)
2357 {
2358 register uint64_t uRestore = uBefore;
2359
2360 /* Modify. */
2361 uWritten = uRestore;
2362 uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
2363 uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
2364 __try
2365 {
2366 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uWritten);
2367 fModifyGp = false;
2368 }
2369 __except(EXCEPTION_EXECUTE_HANDLER)
2370 {
2371 fModifyGp = true;
2372 }
2373
2374 /* Read modified value. */
2375 __try
2376 {
2377 uAfter = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
2378 fAfterGp = false;
2379 }
2380 __except(EXCEPTION_EXECUTE_HANDLER)
2381 {
2382 fAfterGp = true;
2383 }
2384
2385 /* Restore original value. */
2386 __try
2387 {
2388 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uRestore);
2389 fRestoreGp = false;
2390 }
2391 __except(EXCEPTION_EXECUTE_HANDLER)
2392 {
2393 fRestoreGp = true;
2394 }
2395
2396 /* Invalid everything we can. */
2397 if (!fFaster)
2398 {
2399 ASMWriteBackAndInvalidateCaches();
2400 ASMReloadCR3();
2401 ASMNopPause();
2402 }
2403 }
2404
2405 ASMCompilerBarrier(); /* paranoia */
2406 ASMSetFlags(fOldFlags);
2407
2408 /*
2409 * Write out the results.
2410 */
2411 pReq->u.Out.uResults.Modify.uBefore = uBefore;
2412 pReq->u.Out.uResults.Modify.uWritten = uWritten;
2413 pReq->u.Out.uResults.Modify.uAfter = uAfter;
2414 pReq->u.Out.uResults.Modify.fBeforeGp = fBeforeGp;
2415 pReq->u.Out.uResults.Modify.fModifyGp = fModifyGp;
2416 pReq->u.Out.uResults.Modify.fAfterGp = fAfterGp;
2417 pReq->u.Out.uResults.Modify.fRestoreGp = fRestoreGp;
2418 RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
2419}
2420
2421
2422int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
2423{
2424 if (idCpu == NIL_RTCPUID)
2425 {
2426 supdrvNtMsProberModifyOnCpu(idCpu, pReq, NULL);
2427 return VINF_SUCCESS;
2428 }
2429 return RTMpOnSpecific(idCpu, supdrvNtMsProberModifyOnCpu, pReq, NULL);
2430}
2431
2432#endif /* SUPDRV_WITH_MSR_PROBER */
2433
2434
2435/**
2436 * Converts an IPRT error code to an nt status code.
2437 *
2438 * @returns corresponding nt status code.
2439 * @param rc IPRT error status code.
2440 */
2441static NTSTATUS VBoxDrvNtErr2NtStatus(int rc)
2442{
2443 switch (rc)
2444 {
2445 case VINF_SUCCESS: return STATUS_SUCCESS;
2446 case VERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
2447 case VERR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
2448 case VERR_INVALID_MAGIC: return STATUS_UNKNOWN_REVISION;
2449 case VERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
2450 case VERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
2451 case VERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
2452 case VERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
2453 case VERR_PERMISSION_DENIED: return STATUS_ACCESS_DENIED;
2454 case VERR_VERSION_MISMATCH: return STATUS_REVISION_MISMATCH;
2455 }
2456
2457 if (rc < 0)
2458 {
2459 if (((uint32_t)rc & UINT32_C(0xffff0000)) == UINT32_C(0xffff0000))
2460 return (NTSTATUS)( ((uint32_t)rc & UINT32_C(0xffff)) | SUP_NT_STATUS_BASE );
2461 }
2462 return STATUS_UNSUCCESSFUL;
2463}
2464
2465
2466#if 0 /* See alternative in SUPDrvA-win.asm */
2467/**
2468 * Alternative version of SUPR0Printf for Windows.
2469 *
2470 * @returns 0.
2471 * @param pszFormat The format string.
2472 */
2473SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
2474{
2475 va_list va;
2476 char szMsg[512];
2477
2478 va_start(va, pszFormat);
2479 size_t cch = RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
2480 szMsg[sizeof(szMsg) - 1] = '\0';
2481 va_end(va);
2482
2483 RTLogWriteDebugger(szMsg, cch);
2484 return 0;
2485}
2486#endif
2487
2488
2489SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
2490{
2491 return 0;
2492}
2493
2494
2495#ifdef VBOX_WITH_HARDENING
2496
2497/** @name Identifying Special Processes: CSRSS.EXE
2498 * @{ */
2499
2500
2501/**
2502 * Checks if the process is a system32 process by the given name.
2503 *
2504 * @returns true / false.
2505 * @param pProcess The process to check.
2506 * @param pszName The lower case process name (no path!).
2507 */
2508static bool supdrvNtProtectIsSystem32ProcessMatch(PEPROCESS pProcess, const char *pszName)
2509{
2510 Assert(strlen(pszName) < 16); /* see buffer below */
2511
2512 /*
2513 * This test works on XP+.
2514 */
2515 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
2516 if (!pszImageFile)
2517 return false;
2518
2519 if (RTStrICmp(pszImageFile, pszName) != 0)
2520 return false;
2521
2522 /*
2523 * This test requires a Vista+ API.
2524 */
2525 if (g_pfnPsReferenceProcessFilePointer)
2526 {
2527 PFILE_OBJECT pFile = NULL;
2528 NTSTATUS rcNt = g_pfnPsReferenceProcessFilePointer(pProcess, &pFile);
2529 if (!NT_SUCCESS(rcNt))
2530 return false;
2531
2532 union
2533 {
2534 OBJECT_NAME_INFORMATION Info;
2535 uint8_t abBuffer[sizeof(g_System32NtPath) + 16 * sizeof(WCHAR)];
2536 } Buf;
2537 ULONG cbIgn;
2538 rcNt = ObQueryNameString(pFile, &Buf.Info, sizeof(Buf) - sizeof(WCHAR), &cbIgn);
2539 ObDereferenceObject(pFile);
2540 if (!NT_SUCCESS(rcNt))
2541 return false;
2542
2543 /* Terminate the name. */
2544 PRTUTF16 pwszName = Buf.Info.Name.Buffer;
2545 pwszName[Buf.Info.Name.Length / sizeof(RTUTF16)] = '\0';
2546
2547 /* Match the name against the system32 directory path. */
2548 uint32_t cbSystem32 = g_System32NtPath.UniStr.Length;
2549 if (Buf.Info.Name.Length < cbSystem32)
2550 return false;
2551 if (memcmp(pwszName, g_System32NtPath.UniStr.Buffer, cbSystem32))
2552 return false;
2553 pwszName += cbSystem32 / sizeof(RTUTF16);
2554 if (*pwszName++ != '\\')
2555 return false;
2556
2557 /* Compare the name. */
2558 const char *pszRight = pszName;
2559 for (;;)
2560 {
2561 WCHAR wchLeft = *pwszName++;
2562 char chRight = *pszRight++;
2563 Assert(chRight == RT_C_TO_LOWER(chRight));
2564
2565 if ( wchLeft != chRight
2566 && RT_C_TO_LOWER(wchLeft) != chRight)
2567 return false;
2568 if (!chRight)
2569 break;
2570 }
2571 }
2572
2573 return true;
2574}
2575
2576
2577/**
2578 * Checks if the current process is likely to be CSRSS.
2579 *
2580 * @returns true/false.
2581 * @param pProcess The process.
2582 */
2583static bool supdrvNtProtectIsCsrssByProcess(PEPROCESS pProcess)
2584{
2585 /*
2586 * On Windows 8.1 CSRSS.EXE is a protected process.
2587 */
2588 if (g_pfnPsIsProtectedProcessLight)
2589 {
2590 if (!g_pfnPsIsProtectedProcessLight(pProcess))
2591 return false;
2592 }
2593
2594 /*
2595 * The name tests.
2596 */
2597 if (!supdrvNtProtectIsSystem32ProcessMatch(pProcess, "csrss.exe"))
2598 return false;
2599
2600 /** @todo Could extend the CSRSS.EXE check with that the TokenUser of the
2601 * current process must be "NT AUTHORITY\SYSTEM" (S-1-5-18). */
2602
2603 return true;
2604}
2605
2606
2607/**
2608 * Helper for supdrvNtProtectGetAlpcPortObjectType that tries out a name.
2609 *
2610 * @returns true if done, false if not.
2611 * @param pwszPortNm The port path.
2612 * @param ppObjType The object type return variable, updated when
2613 * returning true.
2614 */
2615static bool supdrvNtProtectGetAlpcPortObjectType2(PCRTUTF16 pwszPortNm, POBJECT_TYPE *ppObjType)
2616{
2617 bool fDone = false;
2618
2619 UNICODE_STRING UniStrPortNm;
2620 UniStrPortNm.Buffer = (WCHAR *)pwszPortNm;
2621 UniStrPortNm.Length = (USHORT)(RTUtf16Len(pwszPortNm) * sizeof(WCHAR));
2622 UniStrPortNm.MaximumLength = UniStrPortNm.Length + sizeof(WCHAR);
2623
2624 OBJECT_ATTRIBUTES ObjAttr;
2625 InitializeObjectAttributes(&ObjAttr, &UniStrPortNm, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
2626
2627 HANDLE hPort;
2628 NTSTATUS rcNt = g_pfnZwAlpcCreatePort(&hPort, &ObjAttr, NULL /*pPortAttribs*/);
2629 if (NT_SUCCESS(rcNt))
2630 {
2631 PVOID pvObject;
2632 rcNt = ObReferenceObjectByHandle(hPort, 0 /*DesiredAccess*/, NULL /*pObjectType*/,
2633 KernelMode, &pvObject, NULL /*pHandleInfo*/);
2634 if (NT_SUCCESS(rcNt))
2635 {
2636 POBJECT_TYPE pObjType = g_pfnObGetObjectType(pvObject);
2637 if (pObjType)
2638 {
2639 SUPR0Printf("vboxdrv: ALPC Port Object Type %p (vs %p)\n", pObjType, *ppObjType);
2640 *ppObjType = pObjType;
2641 fDone = true;
2642 }
2643 ObDereferenceObject(pvObject);
2644 }
2645 NtClose(hPort);
2646 }
2647 return fDone;
2648}
2649
2650
2651/**
2652 * Attempts to retrieve the ALPC Port object type.
2653 *
2654 * We've had at least three reports that using LpcPortObjectType when trying to
2655 * get at the ApiPort object results in STATUS_OBJECT_TYPE_MISMATCH errors.
2656 * It's not known who has modified LpcPortObjectType or AlpcPortObjectType (not
2657 * exported) so that it differs from the actual ApiPort type, or maybe this
2658 * unknown entity is intercepting our attempt to reference the port and
2659 * tries to mislead us. The paranoid explanataion is of course that some evil
2660 * root kit like software is messing with the OS, however, it's possible that
2661 * this is valid kernel behavior that 99.8% of our users and 100% of the
2662 * developers are not triggering for some reason.
2663 *
2664 * The code here creates an ALPC port object and gets it's type. It will cache
2665 * the result in g_pAlpcPortObjectType2 on success.
2666 *
2667 * @returns Object type.
2668 * @param uSessionId The session id.
2669 * @param pszSessionId The session id formatted as a string.
2670 */
2671static POBJECT_TYPE supdrvNtProtectGetAlpcPortObjectType(uint32_t uSessionId, const char *pszSessionId)
2672{
2673 POBJECT_TYPE pObjType = *LpcPortObjectType;
2674
2675 if ( g_pfnZwAlpcCreatePort
2676 && g_pfnObGetObjectType)
2677 {
2678 int rc;
2679 ssize_t cchTmp; NOREF(cchTmp);
2680 char szTmp[16];
2681 RTUTF16 wszPortNm[128];
2682 size_t offRand;
2683
2684 /*
2685 * First attempt is in the session directory.
2686 */
2687 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
2688 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
2689 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\VBoxDrv-");
2690 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
2691 Assert(cchTmp > 0);
2692 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2693 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
2694 offRand = RTUtf16Len(wszPortNm);
2695 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
2696 Assert(cchTmp > 0);
2697 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2698 AssertRCSuccess(rc);
2699
2700 bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2701 if (!fDone)
2702 {
2703 wszPortNm[offRand] = '\0';
2704 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0); Assert(cchTmp > 0);
2705 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2706 AssertRCSuccess(rc);
2707
2708 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2709 }
2710 if (!fDone)
2711 {
2712 /*
2713 * Try base names.
2714 */
2715 if (uSessionId == 0)
2716 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
2717 else
2718 {
2719 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
2720 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
2721 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
2722 }
2723 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
2724 Assert(cchTmp > 0);
2725 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2726 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
2727 offRand = RTUtf16Len(wszPortNm);
2728 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
2729 Assert(cchTmp > 0);
2730 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2731 AssertRCSuccess(rc);
2732
2733 bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2734 if (!fDone)
2735 {
2736 wszPortNm[offRand] = '\0';
2737 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
2738 Assert(cchTmp > 0);
2739 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2740 AssertRCSuccess(rc);
2741
2742 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2743 }
2744 }
2745
2746 /* Cache the result in g_pAlpcPortObjectType2. */
2747 if ( g_pAlpcPortObjectType2 == NULL
2748 && pObjType != g_pAlpcPortObjectType1
2749 && fDone)
2750 g_pAlpcPortObjectType2 = pObjType;
2751
2752 }
2753
2754 return pObjType;
2755}
2756
2757
2758/**
2759 * Called in the context of VBoxDrvNtCreate to determin the CSRSS for the
2760 * current process.
2761 *
2762 * The Client/Server Runtime Subsystem (CSRSS) process needs to be allowed some
2763 * additional access right so we need to make 101% sure we correctly identify
2764 * the CSRSS process a process is associated with.
2765 *
2766 * @returns IPRT status code.
2767 * @param pNtProtect The NT protected process structure. The
2768 * hCsrssPid member will be updated on success.
2769 */
2770static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect)
2771{
2772 Assert(pNtProtect->AvlCore.Key == PsGetCurrentProcessId());
2773 Assert(pNtProtect->pCsrssProcess == NULL);
2774 Assert(pNtProtect->hCsrssPid == NULL);
2775
2776 /*
2777 * We'll try use the ApiPort LPC object for the session we're in to track
2778 * down the CSRSS process. So, we start by constructing a path to it.
2779 */
2780 int rc;
2781 uint32_t uSessionId = PsGetProcessSessionId(PsGetCurrentProcess());
2782 char szSessionId[16];
2783 WCHAR wszApiPort[48];
2784 if (uSessionId == 0)
2785 {
2786 szSessionId[0] = '0';
2787 szSessionId[1] = '\0';
2788 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
2789 }
2790 else
2791 {
2792 ssize_t cchTmp = RTStrFormatU32(szSessionId, sizeof(szSessionId), uSessionId, 10, 0, 0, 0);
2793 AssertReturn(cchTmp > 0, (int)cchTmp);
2794 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Sessions\\");
2795 if (RT_SUCCESS(rc))
2796 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), szSessionId);
2797 if (RT_SUCCESS(rc))
2798 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
2799 }
2800 AssertRCReturn(rc, rc);
2801
2802 UNICODE_STRING ApiPortStr;
2803 ApiPortStr.Buffer = wszApiPort;
2804 ApiPortStr.Length = (USHORT)(RTUtf16Len(wszApiPort) * sizeof(RTUTF16));
2805 ApiPortStr.MaximumLength = ApiPortStr.Length + sizeof(RTUTF16);
2806
2807 /*
2808 * The object cannot be opened, but we can reference it by name.
2809 */
2810 void *pvApiPortObj = NULL;
2811 NTSTATUS rcNt = ObReferenceObjectByName(&ApiPortStr,
2812 0,
2813 NULL /*pAccessState*/,
2814 STANDARD_RIGHTS_READ,
2815 g_pAlpcPortObjectType1,
2816 KernelMode,
2817 NULL /*pvParseContext*/,
2818 &pvApiPortObj);
2819 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
2820 && g_pAlpcPortObjectType2 != NULL)
2821 rcNt = ObReferenceObjectByName(&ApiPortStr,
2822 0,
2823 NULL /*pAccessState*/,
2824 STANDARD_RIGHTS_READ,
2825 g_pAlpcPortObjectType2,
2826 KernelMode,
2827 NULL /*pvParseContext*/,
2828 &pvApiPortObj);
2829 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
2830 && g_pfnObGetObjectType
2831 && g_pfnZwAlpcCreatePort)
2832 rcNt = ObReferenceObjectByName(&ApiPortStr,
2833 0,
2834 NULL /*pAccessState*/,
2835 STANDARD_RIGHTS_READ,
2836 supdrvNtProtectGetAlpcPortObjectType(uSessionId, szSessionId),
2837 KernelMode,
2838 NULL /*pvParseContext*/,
2839 &pvApiPortObj);
2840 if (!NT_SUCCESS(rcNt))
2841 {
2842 SUPR0Printf("vboxdrv: Error opening '%ls': %#x\n", wszApiPort, rcNt);
2843 return rcNt == STATUS_OBJECT_TYPE_MISMATCH ? VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE : VERR_SUPDRV_APIPORT_OPEN_ERROR;
2844 }
2845
2846 /*
2847 * Query the processes in the system so we can locate CSRSS.EXE candidates.
2848 * Note! Attempts at using SystemSessionProcessInformation failed with
2849 * STATUS_ACCESS_VIOLATION.
2850 * Note! The 32 bytes on the size of to counteract the allocation header
2851 * that rtR0MemAllocEx slaps on everything.
2852 */
2853 ULONG cbNeeded = _64K - 32;
2854 uint32_t cbBuf;
2855 uint8_t *pbBuf = NULL;
2856 do
2857 {
2858 cbBuf = RT_ALIGN(cbNeeded + _4K, _64K) - 32;
2859 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
2860 if (!pbBuf)
2861 break;
2862
2863 cbNeeded = 0;
2864#if 0 /* doesn't work. */
2865 SYSTEM_SESSION_PROCESS_INFORMATION Req;
2866 Req.SessionId = uSessionId;
2867 Req.BufferLength = cbBuf;
2868 Req.Buffer = pbBuf;
2869 rcNt = NtQuerySystemInformation(SystemSessionProcessInformation, &Req, sizeof(Req), &cbNeeded);
2870#else
2871 rcNt = NtQuerySystemInformation(SystemProcessInformation, pbBuf, cbBuf, &cbNeeded);
2872#endif
2873 if (NT_SUCCESS(rcNt))
2874 break;
2875
2876 RTMemFree(pbBuf);
2877 pbBuf = NULL;
2878 } while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
2879 && cbNeeded > cbBuf
2880 && cbNeeded < 32U*_1M);
2881
2882 if ( pbBuf
2883 && NT_SUCCESS(rcNt)
2884 && cbNeeded >= sizeof(SYSTEM_PROCESS_INFORMATION))
2885 {
2886 /*
2887 * Walk the returned data and look for the process associated with the
2888 * ApiPort object. The ApiPort object keeps the EPROCESS address of
2889 * the owner process (i.e. CSRSS) relatively early in the structure. On
2890 * 64-bit windows 8.1 it's at offset 0x18. So, obtain the EPROCESS
2891 * pointer to likely CSRSS processes and check for a match in the first
2892 * 0x40 bytes of the ApiPort object.
2893 */
2894 rc = VERR_SUPDRV_CSRSS_NOT_FOUND;
2895 for (uint32_t offBuf = 0; offBuf <= cbNeeded - sizeof(SYSTEM_PROCESS_INFORMATION);)
2896 {
2897 PRTNT_SYSTEM_PROCESS_INFORMATION pProcInfo = (PRTNT_SYSTEM_PROCESS_INFORMATION)&pbBuf[offBuf];
2898 if ( pProcInfo->ProcessName.Length == 9 * sizeof(WCHAR)
2899 && pProcInfo->NumberOfThreads > 2 /* Very low guess. */
2900 && pProcInfo->HandleCount > 32 /* Very low guess, I hope. */
2901 && (uintptr_t)pProcInfo->ProcessName.Buffer - (uintptr_t)pbBuf < cbNeeded
2902 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[0]) == 'c'
2903 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[1]) == 's'
2904 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[2]) == 'r'
2905 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[3]) == 's'
2906 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[4]) == 's'
2907 && pProcInfo->ProcessName.Buffer[5] == '.'
2908 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[6]) == 'e'
2909 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[7]) == 'x'
2910 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[8]) == 'e' )
2911 {
2912
2913 /* Get the process structure and perform some more thorough
2914 process checks. */
2915 PEPROCESS pProcess;
2916 rcNt = PsLookupProcessByProcessId(pProcInfo->UniqueProcessId, &pProcess);
2917 if (NT_SUCCESS(rcNt))
2918 {
2919 if (supdrvNtProtectIsCsrssByProcess(pProcess))
2920 {
2921 if (PsGetProcessSessionId(pProcess) == uSessionId)
2922 {
2923 /* Final test, check the ApiPort.
2924 Note! The old LPC (pre Vista) objects has the PID
2925 much earlier in the structure. Might be
2926 worth looking for it instead. */
2927 bool fThatsIt = false;
2928 __try
2929 {
2930 PEPROCESS *ppPortProc = (PEPROCESS *)pvApiPortObj;
2931 uint32_t cTests = g_uNtVerCombined >= SUP_NT_VER_VISTA ? 16 : 38; /* ALPC since Vista. */
2932 do
2933 {
2934 fThatsIt = *ppPortProc == pProcess;
2935 ppPortProc++;
2936 } while (!fThatsIt && --cTests > 0);
2937 }
2938 __except(EXCEPTION_EXECUTE_HANDLER)
2939 {
2940 fThatsIt = false;
2941 }
2942 if (fThatsIt)
2943 {
2944 /* Ok, we found it! Keep the process structure
2945 reference as well as the PID so we can
2946 safely identify it later on. */
2947 pNtProtect->hCsrssPid = pProcInfo->UniqueProcessId;
2948 pNtProtect->pCsrssProcess = pProcess;
2949 rc = VINF_SUCCESS;
2950 break;
2951 }
2952 }
2953 }
2954
2955 ObDereferenceObject(pProcess);
2956 }
2957 }
2958
2959 /* Advance. */
2960 if (!pProcInfo->NextEntryOffset)
2961 break;
2962 offBuf += pProcInfo->NextEntryOffset;
2963 }
2964 }
2965 else
2966 rc = VERR_SUPDRV_SESSION_PROCESS_ENUM_ERROR;
2967 RTMemFree(pbBuf);
2968 ObDereferenceObject(pvApiPortObj);
2969 return rc;
2970}
2971
2972
2973/**
2974 * Checks that the given process is the CSRSS process associated with protected
2975 * process.
2976 *
2977 * @returns true / false.
2978 * @param pNtProtect The NT protection structure.
2979 * @param pCsrss The process structure of the alleged CSRSS.EXE
2980 * process.
2981 */
2982static bool supdrvNtProtectIsAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pCsrss)
2983{
2984 if (pNtProtect->pCsrssProcess == pCsrss)
2985 {
2986 if (pNtProtect->hCsrssPid == PsGetProcessId(pCsrss))
2987 {
2988 return true;
2989 }
2990 }
2991 return false;
2992}
2993
2994
2995/**
2996 * Checks if the given process is the stupid themes service.
2997 *
2998 * The caller does some screening of access masks and what not. We do the rest.
2999 *
3000 * @returns true / false.
3001 * @param pNtProtect The NT protection structure.
3002 * @param pAnnoyingProcess The process structure of an process that might
3003 * happen to be the annoying themes process.
3004 */
3005static bool supdrvNtProtectIsFrigginThemesService(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pAnnoyingProcess)
3006{
3007 RT_NOREF1(pNtProtect);
3008
3009 /*
3010 * Check the process name.
3011 */
3012 if (!supdrvNtProtectIsSystem32ProcessMatch(pAnnoyingProcess, "svchost.exe"))
3013 return false;
3014
3015 /** @todo Come up with more checks. */
3016
3017 return true;
3018}
3019
3020
3021#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3022/**
3023 * Checks if the given process is one of the whitelisted debuggers.
3024 *
3025 * @returns true / false.
3026 * @param pProcess The process to check.
3027 */
3028static bool supdrvNtProtectIsWhitelistedDebugger(PEPROCESS pProcess)
3029{
3030 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
3031 if (!pszImageFile)
3032 return false;
3033
3034 if (pszImageFile[0] == 'w' || pszImageFile[0] == 'W')
3035 {
3036 if (RTStrICmp(pszImageFile, "windbg.exe") == 0)
3037 return true;
3038 if (RTStrICmp(pszImageFile, "werfault.exe") == 0)
3039 return true;
3040 if (RTStrICmp(pszImageFile, "werfaultsecure.exe") == 0)
3041 return true;
3042 }
3043 else if (pszImageFile[0] == 'd' || pszImageFile[0] == 'D')
3044 {
3045 if (RTStrICmp(pszImageFile, "drwtsn32.exe") == 0)
3046 return true;
3047 if (RTStrICmp(pszImageFile, "dwwin.exe") == 0)
3048 return true;
3049 }
3050
3051 return false;
3052}
3053#endif /* VBOX_WITHOUT_DEBUGGER_CHECKS */
3054
3055
3056/** @} */
3057
3058
3059/** @name Process Creation Callbacks.
3060 * @{ */
3061
3062
3063/**
3064 * Cleans up VBoxDrv or VBoxDrvStub error info not collected by the dead process.
3065 *
3066 * @param hProcessId The ID of the dead process.
3067 */
3068static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId)
3069{
3070 int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
3071 if (RT_SUCCESS(rc))
3072 {
3073 PSUPDRVNTERRORINFO pCur, pNext;
3074 RTListForEachSafe(&g_ErrorInfoHead, pCur, pNext, SUPDRVNTERRORINFO, ListEntry)
3075 {
3076 if (pCur->hProcessId == hProcessId)
3077 {
3078 RTListNodeRemove(&pCur->ListEntry);
3079 RTMemFree(pCur);
3080 }
3081 }
3082 RTSemMutexRelease(g_hErrorInfoLock);
3083 }
3084}
3085
3086
3087/**
3088 * Common worker used by the process creation hooks as well as the process
3089 * handle creation hooks to check if a VM process is being created.
3090 *
3091 * @returns true if likely to be a VM process, false if not.
3092 * @param pNtStub The NT protection structure for the possible
3093 * stub process.
3094 * @param hParentPid The parent pid.
3095 * @param hChildPid The child pid.
3096 */
3097static bool supdrvNtProtectIsSpawningStubProcess(PSUPDRVNTPROTECT pNtStub, HANDLE hParentPid, HANDLE hChildPid)
3098{
3099 bool fRc = false;
3100 if (pNtStub->AvlCore.Key == hParentPid) /* paranoia */
3101 {
3102 if (pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
3103 {
3104 /* Compare short names. */
3105 PEPROCESS pStubProcess;
3106 NTSTATUS rcNt = PsLookupProcessByProcessId(hParentPid, &pStubProcess);
3107 if (NT_SUCCESS(rcNt))
3108 {
3109 PEPROCESS pChildProcess;
3110 rcNt = PsLookupProcessByProcessId(hChildPid, &pChildProcess);
3111 if (NT_SUCCESS(rcNt))
3112 {
3113 const char *pszStub = (const char *)PsGetProcessImageFileName(pStubProcess);
3114 const char *pszChild = (const char *)PsGetProcessImageFileName(pChildProcess);
3115 fRc = pszStub != NULL
3116 && pszChild != NULL
3117 && strcmp(pszStub, pszChild) == 0;
3118
3119 /** @todo check that the full image names matches. */
3120
3121 ObDereferenceObject(pChildProcess);
3122 }
3123 ObDereferenceObject(pStubProcess);
3124 }
3125 }
3126 }
3127 return fRc;
3128}
3129
3130
3131/**
3132 * Common code used by the notifies to protect a child process.
3133 *
3134 * @returns VBox status code.
3135 * @param pNtStub The NT protect structure for the parent.
3136 * @param hChildPid The child pid.
3137 */
3138static int supdrvNtProtectProtectNewStubChild(PSUPDRVNTPROTECT pNtParent, HANDLE hChildPid)
3139{
3140 /*
3141 * Create a child protection struction.
3142 */
3143 PSUPDRVNTPROTECT pNtChild;
3144 int rc = supdrvNtProtectCreate(&pNtChild, hChildPid, kSupDrvNtProtectKind_VmProcessUnconfirmed, false /*fLink*/);
3145 if (RT_SUCCESS(rc))
3146 {
3147 pNtChild->fFirstProcessCreateHandle = true;
3148 pNtChild->fFirstThreadCreateHandle = true;
3149 pNtChild->fCsrssFirstProcessCreateHandle = true;
3150 pNtChild->cCsrssFirstProcessDuplicateHandle = ARCH_BITS == 32 ? 2 : 1;
3151 pNtChild->fThemesFirstProcessCreateHandle = true;
3152 pNtChild->hParentPid = pNtParent->AvlCore.Key;
3153 pNtChild->hCsrssPid = pNtParent->hCsrssPid;
3154 pNtChild->pCsrssProcess = pNtParent->pCsrssProcess;
3155 if (pNtChild->pCsrssProcess)
3156 ObReferenceObject(pNtChild->pCsrssProcess);
3157
3158 /*
3159 * Take the spinlock, recheck parent conditions and link things.
3160 */
3161 RTSpinlockAcquire(g_hNtProtectLock);
3162 if (pNtParent->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
3163 {
3164 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtChild->AvlCore);
3165 if (fSuccess)
3166 {
3167 pNtChild->fInTree = true;
3168 pNtParent->u.pChild = pNtChild; /* Parent keeps the initial reference. */
3169 pNtParent->enmProcessKind = kSupDrvNtProtectKind_StubParent;
3170 pNtChild->u.pParent = pNtParent;
3171
3172 RTSpinlockRelease(g_hNtProtectLock);
3173 return VINF_SUCCESS;
3174 }
3175
3176 rc = VERR_INTERNAL_ERROR_2;
3177 }
3178 else
3179 rc = VERR_WRONG_ORDER;
3180 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3181 RTSpinlockRelease(g_hNtProtectLock);
3182
3183 supdrvNtProtectRelease(pNtChild);
3184 }
3185 return rc;
3186}
3187
3188
3189/**
3190 * Common process termination code.
3191 *
3192 * Transitions protected process to the dead states, protecting against handle
3193 * PID reuse (esp. with unconfirmed VM processes) and handle cleanup issues.
3194 *
3195 * @param hDeadPid The PID of the dead process.
3196 */
3197static void supdrvNtProtectUnprotectDeadProcess(HANDLE hDeadPid)
3198{
3199 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hDeadPid);
3200 if (pNtProtect)
3201 {
3202 PSUPDRVNTPROTECT pNtChild = NULL;
3203
3204 RTSpinlockAcquire(g_hNtProtectLock);
3205
3206 /*
3207 * If this is an unconfirmed VM process, we must release the reference
3208 * the parent structure holds.
3209 */
3210 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3211 {
3212 PSUPDRVNTPROTECT pNtParent = pNtProtect->u.pParent;
3213 AssertRelease(pNtParent); AssertRelease(pNtParent->u.pChild == pNtProtect);
3214 pNtParent->u.pChild = NULL;
3215 pNtProtect->u.pParent = NULL;
3216 pNtChild = pNtProtect;
3217 }
3218 /*
3219 * If this is a stub exitting before the VM process gets confirmed,
3220 * release the protection of the potential VM process as this is not
3221 * the prescribed behavior.
3222 */
3223 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
3224 && pNtProtect->u.pChild)
3225 {
3226 pNtChild = pNtProtect->u.pChild;
3227 pNtProtect->u.pChild = NULL;
3228 pNtChild->u.pParent = NULL;
3229 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3230 }
3231
3232 /*
3233 * Transition it to the dead state to prevent it from opening the
3234 * support driver again or be posthumously abused as a vm process parent.
3235 */
3236 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3237 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessConfirmed)
3238 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3239 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
3240 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubSpawning
3241 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
3242 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_StubDead;
3243
3244 RTSpinlockRelease(g_hNtProtectLock);
3245
3246 supdrvNtProtectRelease(pNtProtect);
3247 supdrvNtProtectRelease(pNtChild);
3248
3249 /*
3250 * Do session cleanups.
3251 */
3252 AssertReturnVoid((HANDLE)(uintptr_t)RTProcSelf() == hDeadPid);
3253 if (g_pDevObjSys)
3254 {
3255 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
3256 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, (RTPROCESS)(uintptr_t)hDeadPid,
3257 RTR0ProcHandleSelf(), NULL);
3258 if (pSession)
3259 {
3260 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
3261 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
3262 }
3263 }
3264 }
3265}
3266
3267
3268/**
3269 * Common worker for the process creation callback that verifies a new child
3270 * being created by the handle creation callback code.
3271 *
3272 * @param pNtStub The parent.
3273 * @param pNtVm The child.
3274 * @param fCallerChecks The result of any additional tests the caller made.
3275 * This is in order to avoid duplicating the failure
3276 * path code.
3277 */
3278static void supdrvNtProtectVerifyNewChildProtection(PSUPDRVNTPROTECT pNtStub, PSUPDRVNTPROTECT pNtVm, bool fCallerChecks)
3279{
3280 if ( fCallerChecks
3281 && pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubParent
3282 && pNtVm->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3283 && pNtVm->u.pParent == pNtStub
3284 && pNtStub->u.pChild == pNtVm)
3285 {
3286 /* Fine, reset the CSRSS hack (fixes ViRobot APT Shield 2.0 issue). */
3287 pNtVm->fFirstProcessCreateHandle = true;
3288 return;
3289 }
3290
3291 LogRel(("vboxdrv: Misdetected vm stub; hParentPid=%p hChildPid=%p\n", pNtStub->AvlCore.Key, pNtVm->AvlCore.Key));
3292 if (pNtStub->enmProcessKind != kSupDrvNtProtectKind_VmProcessConfirmed)
3293 supdrvNtProtectUnprotectDeadProcess(pNtVm->AvlCore.Key);
3294}
3295
3296
3297/**
3298 * Old style callback (since forever).
3299 *
3300 * @param hParentPid The parent PID.
3301 * @param hNewPid The PID of the new child.
3302 * @param fCreated TRUE if it's a creation notification,
3303 * FALSE if termination.
3304 * @remarks ASSUMES this arrives before the handle creation callback.
3305 */
3306static VOID __stdcall
3307supdrvNtProtectCallback_ProcessCreateNotify(HANDLE hParentPid, HANDLE hNewPid, BOOLEAN fCreated)
3308{
3309 /*
3310 * Is it a new process that needs protection?
3311 */
3312 if (fCreated)
3313 {
3314 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
3315 if (pNtStub)
3316 {
3317 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
3318 if (!pNtVm)
3319 {
3320 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hNewPid))
3321 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
3322 }
3323 else
3324 {
3325 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm, true);
3326 supdrvNtProtectRelease(pNtVm);
3327 }
3328 supdrvNtProtectRelease(pNtStub);
3329 }
3330 }
3331 /*
3332 * Process termination, do clean ups.
3333 */
3334 else
3335 {
3336 supdrvNtProtectUnprotectDeadProcess(hNewPid);
3337 supdrvNtErrorInfoCleanupProcess(hNewPid);
3338 }
3339}
3340
3341
3342/**
3343 * New style callback (Vista SP1+ / w2k8).
3344 *
3345 * @param pNewProcess The new process.
3346 * @param hNewPid The PID of the new process.
3347 * @param pInfo Process creation details. NULL if process
3348 * termination notification.
3349 * @remarks ASSUMES this arrives before the handle creation callback.
3350 */
3351static VOID __stdcall
3352supdrvNtProtectCallback_ProcessCreateNotifyEx(PEPROCESS pNewProcess, HANDLE hNewPid, PPS_CREATE_NOTIFY_INFO pInfo)
3353{
3354 RT_NOREF1(pNewProcess);
3355
3356 /*
3357 * Is it a new process that needs protection?
3358 */
3359 if (pInfo)
3360 {
3361 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(pInfo->CreatingThreadId.UniqueProcess);
3362
3363 Log(("vboxdrv/NewProcessEx: ctx=%04zx/%p pid=%04zx ppid=%04zx ctor=%04zx/%04zx rcNt=%#x %.*ls\n",
3364 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3365 hNewPid, pInfo->ParentProcessId,
3366 pInfo->CreatingThreadId.UniqueProcess, pInfo->CreatingThreadId.UniqueThread, pInfo->CreationStatus,
3367 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? (size_t)pInfo->ImageFileName->Length / 2 : 0,
3368 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? pInfo->ImageFileName->Buffer : NULL));
3369
3370 if (pNtStub)
3371 {
3372 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
3373 if (!pNtVm)
3374 {
3375 /* Parent must be creator. */
3376 if (pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId)
3377 {
3378 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, pInfo->ParentProcessId, hNewPid))
3379 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
3380 }
3381 }
3382 else
3383 {
3384 /* Parent must be creator (as above). */
3385 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm,
3386 pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId);
3387 supdrvNtProtectRelease(pNtVm);
3388 }
3389 supdrvNtProtectRelease(pNtStub);
3390 }
3391 }
3392 /*
3393 * Process termination, do clean ups.
3394 */
3395 else
3396 {
3397 supdrvNtProtectUnprotectDeadProcess(hNewPid);
3398 supdrvNtErrorInfoCleanupProcess(hNewPid);
3399 }
3400}
3401
3402/** @} */
3403
3404
3405/** @name Process Handle Callbacks.
3406 * @{ */
3407
3408/** Process rights that we allow for handles to stub and VM processes. */
3409# define SUPDRV_NT_ALLOW_PROCESS_RIGHTS \
3410 ( PROCESS_TERMINATE \
3411 | PROCESS_VM_READ \
3412 | PROCESS_QUERY_INFORMATION \
3413 | PROCESS_QUERY_LIMITED_INFORMATION \
3414 | PROCESS_SUSPEND_RESUME \
3415 | DELETE \
3416 | READ_CONTROL \
3417 | SYNCHRONIZE)
3418
3419/** Evil process rights. */
3420# define SUPDRV_NT_EVIL_PROCESS_RIGHTS \
3421 ( PROCESS_CREATE_THREAD \
3422 | PROCESS_SET_SESSIONID /*?*/ \
3423 | PROCESS_VM_OPERATION \
3424 | PROCESS_VM_WRITE \
3425 | PROCESS_DUP_HANDLE \
3426 | PROCESS_CREATE_PROCESS /*?*/ \
3427 | PROCESS_SET_QUOTA /*?*/ \
3428 | PROCESS_SET_INFORMATION \
3429 | PROCESS_SET_LIMITED_INFORMATION /*?*/ \
3430 | 0)
3431AssertCompile((SUPDRV_NT_ALLOW_PROCESS_RIGHTS & SUPDRV_NT_EVIL_PROCESS_RIGHTS) == 0);
3432
3433
3434static OB_PREOP_CALLBACK_STATUS __stdcall
3435supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
3436{
3437 Assert(pvUser == NULL); RT_NOREF1(pvUser);
3438 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3439 Assert(pOpInfo->ObjectType == *PsProcessType);
3440
3441 /*
3442 * Protected? Kludge required for NtOpenProcess calls comming in before
3443 * the create process hook triggers on Windows 8.1 (possibly others too).
3444 */
3445 HANDLE hObjPid = PsGetProcessId((PEPROCESS)pOpInfo->Object);
3446 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hObjPid);
3447 if (!pNtProtect)
3448 {
3449 HANDLE hParentPid = PsGetProcessInheritedFromUniqueProcessId((PEPROCESS)pOpInfo->Object);
3450 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
3451 if (pNtStub)
3452 {
3453 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hObjPid))
3454 {
3455 supdrvNtProtectProtectNewStubChild(pNtStub, hObjPid);
3456 pNtProtect = supdrvNtProtectLookup(hObjPid);
3457 }
3458 supdrvNtProtectRelease(pNtStub);
3459 }
3460 }
3461 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
3462 if (pNtProtect)
3463 {
3464 /*
3465 * Ok, it's a protected process. Strip rights as required or possible.
3466 */
3467 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
3468 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOW_PROCESS_RIGHTS;
3469
3470 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
3471 {
3472 /* Don't restrict the process accessing itself. */
3473 if ((PEPROCESS)pOpInfo->Object == PsGetCurrentProcess())
3474 {
3475 pOpInfo->CallContext = NULL; /* don't assert */
3476 pNtProtect->fFirstProcessCreateHandle = false;
3477
3478 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s\n",
3479 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3480 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3481 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3482 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3483 }
3484#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3485 /* Allow debuggers full access. */
3486 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
3487 {
3488 pOpInfo->CallContext = NULL; /* don't assert */
3489 pNtProtect->fFirstProcessCreateHandle = false;
3490
3491 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
3492 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3493 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3494 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3495 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3496 }
3497#endif
3498 else
3499 {
3500 ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->CreateHandleInformation.DesiredAccess;
3501
3502 /* Special case 1 on Vista, 7 & 8:
3503 The CreateProcess code passes the handle over to CSRSS.EXE
3504 and the code inBaseSrvCreateProcess will duplicate the
3505 handle with 0x1fffff as access mask. NtDuplicateObject will
3506 fail this call before it ever gets down here.
3507
3508 Special case 2 on 8.1:
3509 The CreateProcess code requires additional rights for
3510 something, we'll drop these in the stub code. */
3511 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3512 && pNtProtect->fFirstProcessCreateHandle
3513 && pOpInfo->KernelHandle == 0
3514 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess())
3515 && ExGetPreviousMode() != KernelMode)
3516 {
3517 if ( !pOpInfo->KernelHandle
3518 && fDesiredAccess == s_fCsrssStupidDesires)
3519 {
3520 if (g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3))
3521 fAllowedRights |= s_fCsrssStupidDesires;
3522 else
3523 fAllowedRights = fAllowedRights
3524 | PROCESS_VM_OPERATION
3525 | PROCESS_VM_WRITE
3526 | PROCESS_SET_INFORMATION
3527 | PROCESS_SET_LIMITED_INFORMATION
3528 | 0;
3529 pOpInfo->CallContext = NULL; /* don't assert this. */
3530 }
3531 pNtProtect->fFirstProcessCreateHandle = false;
3532 }
3533
3534 /* Special case 3 on 8.1:
3535 The interaction between the CreateProcess code and CSRSS.EXE
3536 has changed to the better with Windows 8.1. CSRSS.EXE no
3537 longer duplicates the process (thread too) handle, but opens
3538 it, thus allowing us to do our job. */
3539 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3)
3540 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3541 && pNtProtect->fCsrssFirstProcessCreateHandle
3542 && pOpInfo->KernelHandle == 0
3543 && ExGetPreviousMode() == UserMode
3544 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3545 {
3546 pNtProtect->fCsrssFirstProcessCreateHandle = false;
3547 if (fDesiredAccess == s_fCsrssStupidDesires)
3548 {
3549 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
3550 PROCESS_CREATE_PROCESS */
3551 fAllowedRights = fAllowedRights
3552 | PROCESS_VM_OPERATION
3553 | PROCESS_VM_WRITE
3554 | PROCESS_DUP_HANDLE /* Needed for CreateProcess/VBoxTestOGL. */
3555 | 0;
3556 pOpInfo->CallContext = NULL; /* don't assert this. */
3557 }
3558 }
3559
3560 /* Special case 4, Windows 7, Vista, possibly 8, but not 8.1:
3561 The Themes service requires PROCESS_DUP_HANDLE access to our
3562 process or we won't get any menus and dialogs will be half
3563 unreadable. This is _very_ unfortunate and more work will
3564 go into making this more secure. */
3565 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)
3566 && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
3567 && fDesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
3568 && pNtProtect->fThemesFirstProcessCreateHandle
3569 && pOpInfo->KernelHandle == 0
3570 && ExGetPreviousMode() == UserMode
3571 && supdrvNtProtectIsFrigginThemesService(pNtProtect, PsGetCurrentProcess()) )
3572 {
3573 pNtProtect->fThemesFirstProcessCreateHandle = true; /* Only once! */
3574 fAllowedRights |= PROCESS_DUP_HANDLE;
3575 pOpInfo->CallContext = NULL; /* don't assert this. */
3576 }
3577
3578 /* Special case 6a, Windows 10+: AudioDG.exe opens the process with the
3579 PROCESS_SET_LIMITED_INFORMATION right. It seems like it need it for
3580 some myserious and weirdly placed cpu set management of our process.
3581 I'd love to understand what that's all about...
3582 Currently playing safe and only grand this right, however limited, to
3583 audiodg.exe. */
3584 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
3585 && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
3586 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
3587 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
3588 )
3589 && pOpInfo->KernelHandle == 0
3590 && ExGetPreviousMode() == UserMode
3591 && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
3592 {
3593 fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
3594 pOpInfo->CallContext = NULL; /* don't assert this. */
3595 }
3596
3597 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p/pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
3598 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3599 fDesiredAccess, pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3600 fAllowedRights, fDesiredAccess & fAllowedRights,
3601 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode() ));
3602
3603 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
3604 }
3605 }
3606 else
3607 {
3608 /* Don't restrict the process accessing itself. */
3609 if ( (PEPROCESS)pOpInfo->Object == PsGetCurrentProcess()
3610 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pOpInfo->Object)
3611 {
3612 Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
3613 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3614 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3615 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3616 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3617 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3618 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3619 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3620
3621 pOpInfo->CallContext = NULL; /* don't assert */
3622 }
3623 else
3624 {
3625 ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess;
3626
3627 /* Special case 5 on Vista, 7 & 8:
3628 This is the CSRSS.EXE end of special case #1. */
3629 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
3630 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3631 && pNtProtect->cCsrssFirstProcessDuplicateHandle > 0
3632 && pOpInfo->KernelHandle == 0
3633 && fDesiredAccess == s_fCsrssStupidDesires
3634 && pNtProtect->hParentPid
3635 == PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess)
3636 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
3637 && ExGetPreviousMode() == UserMode
3638 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()))
3639 {
3640 if (ASMAtomicDecS32(&pNtProtect->cCsrssFirstProcessDuplicateHandle) >= 0)
3641 {
3642 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
3643 PROCESS_CREATE_PROCESS, PROCESS_DUP_HANDLE */
3644 fAllowedRights = fAllowedRights
3645 | PROCESS_VM_OPERATION
3646 | PROCESS_VM_WRITE
3647 | PROCESS_DUP_HANDLE /* Needed for launching VBoxTestOGL. */
3648 | 0;
3649 pOpInfo->CallContext = NULL; /* don't assert this. */
3650 }
3651 }
3652
3653 /* Special case 6b, Windows 10+: AudioDG.exe duplicates the handle it opened above. */
3654 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
3655 && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
3656 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
3657 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
3658 )
3659 && pOpInfo->KernelHandle == 0
3660 && ExGetPreviousMode() == UserMode
3661 && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
3662 {
3663 fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
3664 pOpInfo->CallContext = NULL; /* don't assert this. */
3665 }
3666
3667 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
3668 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3669 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3670 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3671 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3672 fDesiredAccess,
3673 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3674 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3675
3676 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
3677 }
3678 }
3679 supdrvNtProtectRelease(pNtProtect);
3680 }
3681
3682 return OB_PREOP_SUCCESS;
3683}
3684
3685
3686static VOID __stdcall
3687supdrvNtProtectCallback_ProcessHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
3688{
3689 Assert(pvUser == NULL); RT_NOREF1(pvUser);
3690 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3691 Assert(pOpInfo->ObjectType == *PsProcessType);
3692
3693 if ( pOpInfo->CallContext
3694 && NT_SUCCESS(pOpInfo->ReturnStatus))
3695 {
3696 ACCESS_MASK const fGrantedAccess = pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE
3697 ? pOpInfo->Parameters->CreateHandleInformation.GrantedAccess
3698 : pOpInfo->Parameters->DuplicateHandleInformation.GrantedAccess;
3699 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOW_PROCESS_RIGHTS
3700 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
3701 | PROCESS_UNKNOWN_4000 /* Seen set on win 8.1 */
3702 /*| PROCESS_UNKNOWN_8000 */ ) )
3703 || pOpInfo->KernelHandle,
3704 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
3705 fGrantedAccess, SUPDRV_NT_ALLOW_PROCESS_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOW_PROCESS_RIGHTS));
3706 }
3707}
3708
3709# undef SUPDRV_NT_ALLOW_PROCESS_RIGHTS
3710
3711/** @} */
3712
3713
3714/** @name Thread Handle Callbacks
3715 * @{ */
3716
3717/* From ntifs.h */
3718extern "C" NTKERNELAPI PEPROCESS __stdcall IoThreadToProcess(PETHREAD);
3719
3720/** Thread rights that we allow for handles to stub and VM processes. */
3721# define SUPDRV_NT_ALLOWED_THREAD_RIGHTS \
3722 ( THREAD_TERMINATE \
3723 | THREAD_GET_CONTEXT \
3724 | THREAD_QUERY_INFORMATION \
3725 | THREAD_QUERY_LIMITED_INFORMATION \
3726 | DELETE \
3727 | READ_CONTROL \
3728 | SYNCHRONIZE)
3729/** @todo consider THREAD_SET_LIMITED_INFORMATION & THREAD_RESUME */
3730
3731/** Evil thread rights.
3732 * @remarks THREAD_RESUME is not included as it seems to be forced upon us by
3733 * Windows 8.1, at least for some processes. We dont' actively
3734 * allow it though, just tollerate it when forced to. */
3735# define SUPDRV_NT_EVIL_THREAD_RIGHTS \
3736 ( THREAD_SUSPEND_RESUME \
3737 | THREAD_SET_CONTEXT \
3738 | THREAD_SET_INFORMATION \
3739 | THREAD_SET_LIMITED_INFORMATION /*?*/ \
3740 | THREAD_SET_THREAD_TOKEN /*?*/ \
3741 | THREAD_IMPERSONATE /*?*/ \
3742 | THREAD_DIRECT_IMPERSONATION /*?*/ \
3743 /*| THREAD_RESUME - see remarks. */ \
3744 | 0)
3745AssertCompile((SUPDRV_NT_EVIL_THREAD_RIGHTS & SUPDRV_NT_ALLOWED_THREAD_RIGHTS) == 0);
3746
3747
3748static OB_PREOP_CALLBACK_STATUS __stdcall
3749supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
3750{
3751 Assert(pvUser == NULL); RT_NOREF1(pvUser);
3752 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3753 Assert(pOpInfo->ObjectType == *PsThreadType);
3754
3755 PEPROCESS pProcess = IoThreadToProcess((PETHREAD)pOpInfo->Object);
3756 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(PsGetProcessId(pProcess));
3757 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
3758 if (pNtProtect)
3759 {
3760 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
3761 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOWED_THREAD_RIGHTS;
3762
3763 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
3764 {
3765 /* Don't restrict the process accessing its own threads. */
3766 if (pProcess == PsGetCurrentProcess())
3767 {
3768 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] self\n",
3769 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3770 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3771 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind));
3772 pOpInfo->CallContext = NULL; /* don't assert */
3773 pNtProtect->fFirstThreadCreateHandle = false;
3774 }
3775#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3776 /* Allow debuggers full access. */
3777 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
3778 {
3779 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
3780 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3781 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3782 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3783 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3784 pOpInfo->CallContext = NULL; /* don't assert */
3785 }
3786#endif
3787 else
3788 {
3789 /* Special case 1 on Vista, 7, 8:
3790 The CreateProcess code passes the handle over to CSRSS.EXE
3791 and the code inBaseSrvCreateProcess will duplicate the
3792 handle with 0x1fffff as access mask. NtDuplicateObject will
3793 fail this call before it ever gets down here. */
3794 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
3795 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3796 && pNtProtect->fFirstThreadCreateHandle
3797 && pOpInfo->KernelHandle == 0
3798 && ExGetPreviousMode() == UserMode
3799 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess()) )
3800 {
3801 if ( !pOpInfo->KernelHandle
3802 && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
3803 {
3804 fAllowedRights |= s_fCsrssStupidDesires;
3805 pOpInfo->CallContext = NULL; /* don't assert this. */
3806 }
3807 pNtProtect->fFirstThreadCreateHandle = false;
3808 }
3809
3810 /* Special case 2 on 8.1, possibly also Vista, 7, 8:
3811 When creating a process like VBoxTestOGL from the VM process,
3812 CSRSS.EXE will try talk to the calling thread and, it
3813 appears, impersonate it. We unfortunately need to allow
3814 this or there will be no 3D support. Typical DbgPrint:
3815 "SXS: BasepCreateActCtx() Calling csrss server failed. Status = 0xc00000a5" */
3816 SUPDRVNTPROTECTKIND enmProcessKind;
3817 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
3818 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
3819 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3820 && pOpInfo->KernelHandle == 0
3821 && ExGetPreviousMode() == UserMode
3822 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3823 {
3824 fAllowedRights |= THREAD_IMPERSONATE;
3825 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
3826 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
3827 pOpInfo->CallContext = NULL; /* don't assert this. */
3828 }
3829
3830 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
3831 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3832 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3833 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
3834 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess & fAllowedRights,
3835 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode()));
3836
3837 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
3838 }
3839 }
3840 else
3841 {
3842 /* Don't restrict the process accessing its own threads. */
3843 if ( pProcess == PsGetCurrentProcess()
3844 && (PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pProcess)
3845 {
3846 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] self\n",
3847 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3848 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3849 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3850 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3851 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3852 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3853 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3854 pOpInfo->CallContext = NULL; /* don't assert */
3855 }
3856 else
3857 {
3858 /* Special case 3 on Vista, 7, 8:
3859 This is the follow up to special case 1. */
3860 SUPDRVNTPROTECTKIND enmProcessKind;
3861 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
3862 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
3863 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3864 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
3865 && pOpInfo->KernelHandle == 0
3866 && ExGetPreviousMode() == UserMode
3867 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3868 {
3869 fAllowedRights |= THREAD_IMPERSONATE;
3870 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
3871 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
3872 pOpInfo->CallContext = NULL; /* don't assert this. */
3873 }
3874
3875 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s\n",
3876 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3877 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3878 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3879 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3880 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3881 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
3882 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess & fAllowedRights,
3883 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3884
3885 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
3886 }
3887 }
3888
3889 supdrvNtProtectRelease(pNtProtect);
3890 }
3891
3892 return OB_PREOP_SUCCESS;
3893}
3894
3895
3896static VOID __stdcall
3897supdrvNtProtectCallback_ThreadHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
3898{
3899 Assert(pvUser == NULL); RT_NOREF1(pvUser);
3900 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3901 Assert(pOpInfo->ObjectType == *PsThreadType);
3902
3903 if ( pOpInfo->CallContext
3904 && NT_SUCCESS(pOpInfo->ReturnStatus))
3905 {
3906 ACCESS_MASK const fGrantedAccess = pOpInfo->Parameters->CreateHandleInformation.GrantedAccess;
3907 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOWED_THREAD_RIGHTS
3908 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
3909 | THREAD_RESUME /* This seems to be force upon us too with 8.1. */
3910 ) )
3911 || pOpInfo->KernelHandle,
3912 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
3913 fGrantedAccess, SUPDRV_NT_ALLOWED_THREAD_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOWED_THREAD_RIGHTS));
3914 }
3915}
3916
3917# undef SUPDRV_NT_ALLOWED_THREAD_RIGHTS
3918
3919/** @} */
3920
3921
3922/**
3923 * Creates a new process protection structure.
3924 *
3925 * @returns VBox status code.
3926 * @param ppNtProtect Where to return the pointer to the structure
3927 * on success.
3928 * @param hPid The process ID of the process to protect.
3929 * @param enmProcessKind The kind of process we're protecting.
3930 * @param fLink Whether to link the structure into the tree.
3931 */
3932static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid, SUPDRVNTPROTECTKIND enmProcessKind, bool fLink)
3933{
3934 AssertReturn(g_hNtProtectLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
3935
3936 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)RTMemAllocZ(sizeof(*pNtProtect));
3937 if (!pNtProtect)
3938 return VERR_NO_MEMORY;
3939
3940 pNtProtect->AvlCore.Key = hPid;
3941 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC;
3942 pNtProtect->cRefs = 1;
3943 pNtProtect->enmProcessKind = enmProcessKind;
3944 pNtProtect->hParentPid = NULL;
3945 pNtProtect->hOpenTid = NULL;
3946 pNtProtect->hCsrssPid = NULL;
3947 pNtProtect->pCsrssProcess = NULL;
3948
3949 if (fLink)
3950 {
3951 RTSpinlockAcquire(g_hNtProtectLock);
3952 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtProtect->AvlCore);
3953 pNtProtect->fInTree = fSuccess;
3954 RTSpinlockRelease(g_hNtProtectLock);
3955
3956 if (!fSuccess)
3957 {
3958 /* Duplicate entry, fail. */
3959 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC_DEAD;
3960 LogRel(("supdrvNtProtectCreate: Duplicate (%#x).\n", pNtProtect->AvlCore.Key));
3961 RTMemFree(pNtProtect);
3962 return VERR_DUPLICATE;
3963 }
3964 }
3965
3966 *ppNtProtect = pNtProtect;
3967 return VINF_SUCCESS;
3968}
3969
3970
3971/**
3972 * Releases a reference to a NT protection structure.
3973 *
3974 * @param pNtProtect The NT protection structure.
3975 */
3976static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
3977{
3978 if (!pNtProtect)
3979 return;
3980 AssertReturnVoid(pNtProtect->u32Magic == SUPDRVNTPROTECT_MAGIC);
3981
3982 RTSpinlockAcquire(g_hNtProtectLock);
3983 uint32_t cRefs = ASMAtomicDecU32(&pNtProtect->cRefs);
3984 if (cRefs != 0)
3985 RTSpinlockRelease(g_hNtProtectLock);
3986 else
3987 {
3988 /*
3989 * That was the last reference. Remove it from the tree, invalidate it
3990 * and free the resources associated with it. Also, release any
3991 * child/parent references related to this protection structure.
3992 */
3993 ASMAtomicWriteU32(&pNtProtect->u32Magic, SUPDRVNTPROTECT_MAGIC_DEAD);
3994 if (pNtProtect->fInTree)
3995 {
3996 PSUPDRVNTPROTECT pRemoved = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pNtProtect->AvlCore.Key);
3997 Assert(pRemoved == pNtProtect); RT_NOREF_PV(pRemoved);
3998 pNtProtect->fInTree = false;
3999 }
4000
4001 PSUPDRVNTPROTECT pChild = NULL;
4002 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent)
4003 {
4004 pChild = pNtProtect->u.pChild;
4005 if (pChild)
4006 {
4007 pNtProtect->u.pChild = NULL;
4008 pChild->u.pParent = NULL;
4009 pChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4010 uint32_t cChildRefs = ASMAtomicDecU32(&pChild->cRefs);
4011 if (!cChildRefs)
4012 {
4013 Assert(pChild->fInTree);
4014 if (pChild->fInTree)
4015 {
4016 PSUPDRVNTPROTECT pRemovedChild = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pChild->AvlCore.Key);
4017 Assert(pRemovedChild == pChild); RT_NOREF_PV(pRemovedChild);
4018 pChild->fInTree = false;
4019 }
4020 }
4021 else
4022 pChild = NULL;
4023 }
4024 }
4025 else
4026 AssertRelease(pNtProtect->enmProcessKind != kSupDrvNtProtectKind_VmProcessUnconfirmed);
4027
4028 RTSpinlockRelease(g_hNtProtectLock);
4029
4030 if (pNtProtect->pCsrssProcess)
4031 {
4032 ObDereferenceObject(pNtProtect->pCsrssProcess);
4033 pNtProtect->pCsrssProcess = NULL;
4034 }
4035
4036 RTMemFree(pNtProtect);
4037 if (pChild)
4038 RTMemFree(pChild);
4039 }
4040}
4041
4042
4043/**
4044 * Looks up a PID in the NT protect tree.
4045 *
4046 * @returns Pointer to a NT protection structure (with a referenced) on success,
4047 * NULL if not found.
4048 * @param hPid The process ID.
4049 */
4050static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid)
4051{
4052 RTSpinlockAcquire(g_hNtProtectLock);
4053 PSUPDRVNTPROTECT pFound = (PSUPDRVNTPROTECT)RTAvlPVGet(&g_NtProtectTree, hPid);
4054 if (pFound)
4055 ASMAtomicIncU32(&pFound->cRefs);
4056 RTSpinlockRelease(g_hNtProtectLock);
4057 return pFound;
4058}
4059
4060
4061/**
4062 * Validates a few facts about the stub process when the VM process opens
4063 * vboxdrv.
4064 *
4065 * This makes sure the stub process is still around and that it has neither
4066 * debugger nor extra threads in it.
4067 *
4068 * @returns VBox status code.
4069 * @param pNtProtect The unconfirmed VM process currently trying to
4070 * open vboxdrv.
4071 * @param pErrInfo Additional error information.
4072 */
4073static int supdrvNtProtectVerifyStubForVmProcess(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
4074{
4075 /*
4076 * Grab a reference to the parent stub process.
4077 */
4078 SUPDRVNTPROTECTKIND enmStub = kSupDrvNtProtectKind_Invalid;
4079 PSUPDRVNTPROTECT pNtStub = NULL;
4080 RTSpinlockAcquire(g_hNtProtectLock);
4081 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4082 {
4083 pNtStub = pNtProtect->u.pParent; /* weak reference. */
4084 if (pNtStub)
4085 {
4086 enmStub = pNtStub->enmProcessKind;
4087 if (enmStub == kSupDrvNtProtectKind_StubParent)
4088 {
4089 uint32_t cRefs = ASMAtomicIncU32(&pNtStub->cRefs);
4090 Assert(cRefs > 0 && cRefs < 1024); RT_NOREF_PV(cRefs);
4091 }
4092 else
4093 pNtStub = NULL;
4094 }
4095 }
4096 RTSpinlockRelease(g_hNtProtectLock);
4097
4098 /*
4099 * We require the stub process to be present.
4100 */
4101 if (!pNtStub)
4102 return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND, "Missing stub process (enmStub=%d).", enmStub);
4103
4104 /*
4105 * Open the parent process and thread so we can check for debuggers and unwanted threads.
4106 */
4107 int rc;
4108 PEPROCESS pStubProcess;
4109 NTSTATUS rcNt = PsLookupProcessByProcessId(pNtStub->AvlCore.Key, &pStubProcess);
4110 if (NT_SUCCESS(rcNt))
4111 {
4112 HANDLE hStubProcess;
4113 rcNt = ObOpenObjectByPointer(pStubProcess, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
4114 0 /*DesiredAccess*/, *PsProcessType, KernelMode, &hStubProcess);
4115 if (NT_SUCCESS(rcNt))
4116 {
4117 PETHREAD pStubThread;
4118 rcNt = PsLookupThreadByThreadId(pNtStub->hOpenTid, &pStubThread);
4119 if (NT_SUCCESS(rcNt))
4120 {
4121 HANDLE hStubThread;
4122 rcNt = ObOpenObjectByPointer(pStubThread, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
4123 0 /*DesiredAccess*/, *PsThreadType, KernelMode, &hStubThread);
4124 if (NT_SUCCESS(rcNt))
4125 {
4126 /*
4127 * Do some simple sanity checking.
4128 */
4129 rc = supHardNtVpDebugger(hStubProcess, pErrInfo);
4130 if (RT_SUCCESS(rc))
4131 rc = supHardNtVpThread(hStubProcess, hStubThread, pErrInfo);
4132
4133 /* Clean up. */
4134 rcNt = NtClose(hStubThread); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
4135 }
4136 else
4137 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_OPEN_ERROR,
4138 "Error opening stub thread %p (tid %p, pid %p): %#x",
4139 pStubThread, pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
4140 }
4141 else
4142 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_NOT_FOUND,
4143 "Failed to locate thread %p in %p: %#x", pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
4144 rcNt = NtClose(hStubProcess); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
4145 }
4146 else
4147 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_OPEN_ERROR,
4148 "Error opening stub process %p (pid %p): %#x", pStubProcess, pNtStub->AvlCore.Key, rcNt);
4149 ObDereferenceObject(pStubProcess);
4150 }
4151 else
4152 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND,
4153 "Failed to locate stub process %p: %#x", pNtStub->AvlCore.Key, rcNt);
4154
4155 supdrvNtProtectRelease(pNtStub);
4156 return rc;
4157}
4158
4159
4160/**
4161 * Worker for supdrvNtProtectVerifyProcess that verifies the handles to a VM
4162 * process and its thread.
4163 *
4164 * @returns VBox status code.
4165 * @param pNtProtect The NT protect structure for getting information
4166 * about special processes.
4167 * @param pErrInfo Where to return additional error details.
4168 */
4169static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
4170{
4171 /*
4172 * What to protect.
4173 */
4174 PEPROCESS pProtectedProcess = PsGetCurrentProcess();
4175 HANDLE hProtectedPid = PsGetProcessId(pProtectedProcess);
4176 PETHREAD pProtectedThread = PsGetCurrentThread();
4177 AssertReturn(pNtProtect->AvlCore.Key == hProtectedPid, VERR_INTERNAL_ERROR_5);
4178
4179 /*
4180 * Take a snapshot of all the handles in the system.
4181 * Note! The 32 bytes on the size of to counteract the allocation header
4182 * that rtR0MemAllocEx slaps on everything.
4183 */
4184 uint32_t cbBuf = _256K - 32;
4185 uint8_t *pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
4186 ULONG cbNeeded = cbBuf;
4187 NTSTATUS rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
4188 if (!NT_SUCCESS(rcNt))
4189 {
4190 while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
4191 && cbNeeded > cbBuf
4192 && cbBuf <= 32U*_1M)
4193 {
4194 cbBuf = RT_ALIGN_32(cbNeeded + _4K, _64K) - 32;
4195 RTMemFree(pbBuf);
4196 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
4197 if (!pbBuf)
4198 return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Error allocating %zu bytes for querying handles.", cbBuf);
4199 rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
4200 }
4201 if (!NT_SUCCESS(rcNt))
4202 {
4203 RTMemFree(pbBuf);
4204 return RTErrInfoSetF(pErrInfo, RTErrConvertFromNtStatus(rcNt),
4205 "NtQuerySystemInformation/SystemExtendedHandleInformation failed: %#x\n", rcNt);
4206 }
4207 }
4208
4209 /*
4210 * Walk the information and look for handles to the two objects we're protecting.
4211 */
4212 int rc = VINF_SUCCESS;
4213# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4214 HANDLE idLastDebugger = (HANDLE)~(uintptr_t)0;
4215# endif
4216
4217 uint32_t cCsrssProcessHandles = 0;
4218 uint32_t cSystemProcessHandles = 0;
4219 uint32_t cEvilProcessHandles = 0;
4220 uint32_t cBenignProcessHandles = 0;
4221
4222 uint32_t cCsrssThreadHandles = 0;
4223 uint32_t cEvilThreadHandles = 0;
4224 uint32_t cBenignThreadHandles = 0;
4225
4226 SYSTEM_HANDLE_INFORMATION_EX const *pInfo = (SYSTEM_HANDLE_INFORMATION_EX const *)pbBuf;
4227 ULONG_PTR i = pInfo->NumberOfHandles;
4228 AssertRelease(RT_OFFSETOF(SYSTEM_HANDLE_INFORMATION_EX, Handles[i]) == cbNeeded);
4229 while (i-- > 0)
4230 {
4231 const char *pszType;
4232 SYSTEM_HANDLE_ENTRY_INFO_EX const *pHandleInfo = &pInfo->Handles[i];
4233 if (pHandleInfo->Object == pProtectedProcess)
4234 {
4235 /* Handles within the protected process are fine. */
4236 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_PROCESS_RIGHTS)
4237 || pHandleInfo->UniqueProcessId == hProtectedPid)
4238 {
4239 cBenignProcessHandles++;
4240 continue;
4241 }
4242
4243 /* CSRSS is allowed to have one evil process handle.
4244 See the special cases in the hook code. */
4245 if ( cCsrssProcessHandles < 1
4246 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
4247 {
4248 cCsrssProcessHandles++;
4249 continue;
4250 }
4251
4252 /* The system process is allowed having two open process handle in
4253 Windows 8.1 and later, and one in earlier. This is probably a
4254 little overly paranoid as I think we can safely trust the
4255 system process... */
4256 if ( cSystemProcessHandles < (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3) ? UINT32_C(2) : UINT32_C(1))
4257 && pHandleInfo->UniqueProcessId == PsGetProcessId(PsInitialSystemProcess))
4258 {
4259 cSystemProcessHandles++;
4260 continue;
4261 }
4262
4263 cEvilProcessHandles++;
4264 pszType = "process";
4265 }
4266 else if (pHandleInfo->Object == pProtectedThread)
4267 {
4268 /* Handles within the protected process is fine. */
4269 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_THREAD_RIGHTS)
4270 || pHandleInfo->UniqueProcessId == hProtectedPid)
4271 {
4272 cBenignThreadHandles++;
4273 continue;
4274 }
4275
4276 /* CSRSS is allowed to have one evil handle to the primary thread
4277 for LPC purposes. See the hook for special case. */
4278 if ( cCsrssThreadHandles < 1
4279 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
4280 {
4281 cCsrssThreadHandles++;
4282 continue;
4283 }
4284
4285 cEvilThreadHandles++;
4286 pszType = "thread";
4287 }
4288 else
4289 continue;
4290
4291# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4292 /* Ignore whitelisted debuggers. */
4293 if (pHandleInfo->UniqueProcessId == idLastDebugger)
4294 continue;
4295 PEPROCESS pDbgProc;
4296 NTSTATUS rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pDbgProc);
4297 if (NT_SUCCESS(rcNt))
4298 {
4299 bool fIsDebugger = supdrvNtProtectIsWhitelistedDebugger(pDbgProc);
4300 ObDereferenceObject(pDbgProc);
4301 if (fIsDebugger)
4302 {
4303 idLastDebugger = pHandleInfo->UniqueProcessId;
4304 continue;
4305 }
4306 }
4307# endif
4308
4309 /* Found evil handle. Currently ignoring on pre-Vista. */
4310# ifndef VBOX_WITH_VISTA_NO_SP
4311 if ( g_uNtVerCombined >= SUP_NT_VER_VISTA
4312# else
4313 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0)
4314# endif
4315 || g_pfnObRegisterCallbacks)
4316 {
4317 LogRel(("vboxdrv: Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s\n",
4318 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
4319 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType));
4320 rc = RTErrInfoAddF(pErrInfo, VERR_SUPDRV_HARDENING_EVIL_HANDLE,
4321 *pErrInfo->pszMsg
4322 ? "\nFound evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s"
4323 : "Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s",
4324 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
4325 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType);
4326
4327 /* Try add the process name. */
4328 PEPROCESS pOffendingProcess;
4329 rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pOffendingProcess);
4330 if (NT_SUCCESS(rcNt))
4331 {
4332 const char *pszName = (const char *)PsGetProcessImageFileName(pOffendingProcess);
4333 if (pszName && *pszName)
4334 rc = RTErrInfoAddF(pErrInfo, rc, " [%s]", pszName);
4335
4336 ObDereferenceObject(pOffendingProcess);
4337 }
4338 }
4339 }
4340
4341 RTMemFree(pbBuf);
4342 return rc;
4343}
4344
4345
4346/**
4347 * Checks if the current process checks out as a VM process stub.
4348 *
4349 * @returns VBox status code.
4350 * @param pNtProtect The NT protect structure. This is upgraded to a
4351 * final protection kind (state) on success.
4352 */
4353static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
4354{
4355 AssertReturn(PsGetProcessId(PsGetCurrentProcess()) == pNtProtect->AvlCore.Key, VERR_INTERNAL_ERROR_3);
4356
4357 /*
4358 * Do the verification. The handle restriction checks are only preformed
4359 * on VM processes.
4360 */
4361 int rc = VINF_SUCCESS;
4362 PSUPDRVNTERRORINFO pErrorInfo = (PSUPDRVNTERRORINFO)RTMemAllocZ(sizeof(*pErrorInfo));
4363 if (RT_SUCCESS(rc))
4364 {
4365 pErrorInfo->hProcessId = PsGetCurrentProcessId();
4366 pErrorInfo->hThreadId = PsGetCurrentThreadId();
4367 RTERRINFO ErrInfo;
4368 RTErrInfoInit(&ErrInfo, pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo));
4369
4370 if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
4371 rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect, &ErrInfo);
4372 if (RT_SUCCESS(rc))
4373 {
4374 rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY, 0 /*fFlags*/,
4375 NULL /*pcFixes*/, &ErrInfo);
4376 if (RT_SUCCESS(rc) && pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
4377 rc = supdrvNtProtectVerifyStubForVmProcess(pNtProtect, &ErrInfo);
4378 }
4379 }
4380 else
4381 rc = VERR_NO_MEMORY;
4382
4383 /*
4384 * Upgrade and return.
4385 */
4386 HANDLE hOpenTid = PsGetCurrentThreadId();
4387 RTSpinlockAcquire(g_hNtProtectLock);
4388
4389 /* Stub process verficiation is pretty much straight forward. */
4390 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
4391 {
4392 pNtProtect->enmProcessKind = RT_SUCCESS(rc) ? kSupDrvNtProtectKind_StubSpawning : kSupDrvNtProtectKind_StubDead;
4393 pNtProtect->hOpenTid = hOpenTid;
4394 }
4395 /* The VM process verification is a little bit more complicated
4396 because we need to drop the parent process reference as well. */
4397 else if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4398 {
4399 AssertRelease(pNtProtect->cRefs >= 2); /* Parent + Caller */
4400 PSUPDRVNTPROTECT pParent = pNtProtect->u.pParent;
4401 AssertRelease(pParent);
4402 AssertRelease(pParent->u.pParent == pNtProtect);
4403 AssertRelease(pParent->enmProcessKind == kSupDrvNtProtectKind_StubParent);
4404 pParent->u.pParent = NULL;
4405
4406 pNtProtect->u.pParent = NULL;
4407 ASMAtomicDecU32(&pNtProtect->cRefs);
4408
4409 if (RT_SUCCESS(rc))
4410 {
4411 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessConfirmed;
4412 pNtProtect->hOpenTid = hOpenTid;
4413 }
4414 else
4415 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4416 }
4417
4418 /* Since the stub and VM processes are only supposed to have one thread,
4419 we're not supposed to be subject to any races from within the processes.
4420
4421 There is a race between VM process verification and the stub process
4422 exiting, though. We require the stub process to be alive until the new
4423 VM process has made it thru the validation. So, when the stub
4424 terminates the notification handler will change the state of both stub
4425 and VM process to dead.
4426
4427 Also, I'm not entirely certain where the process
4428 termination notification is triggered from, so that can theorically
4429 create a race in both cases. */
4430 else
4431 {
4432 AssertReleaseMsg( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubDead
4433 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessDead,
4434 ("enmProcessKind=%d rc=%Rrc\n", pNtProtect->enmProcessKind, rc));
4435 if (RT_SUCCESS(rc))
4436 rc = VERR_INVALID_STATE; /* There should be no races here. */
4437 }
4438
4439 RTSpinlockRelease(g_hNtProtectLock);
4440
4441 /*
4442 * Free error info on success, keep it on failure.
4443 */
4444 if (RT_SUCCESS(rc))
4445 RTMemFree(pErrorInfo);
4446 else if (pErrorInfo)
4447 {
4448 pErrorInfo->cchErrorInfo = (uint32_t)strlen(pErrorInfo->szErrorInfo);
4449 if (!pErrorInfo->cchErrorInfo)
4450 pErrorInfo->cchErrorInfo = (uint32_t)RTStrPrintf(pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo),
4451 "supdrvNtProtectVerifyProcess: rc=%d", rc);
4452 RTLogWriteDebugger(pErrorInfo->szErrorInfo, pErrorInfo->cchErrorInfo);
4453
4454 int rc2 = RTSemMutexRequest(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
4455 if (RT_SUCCESS(rc2))
4456 {
4457 pErrorInfo->uCreatedMsTs = RTTimeMilliTS();
4458
4459 /* Free old entries. */
4460 PSUPDRVNTERRORINFO pCur;
4461 while ( (pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL
4462 && (int64_t)(pErrorInfo->uCreatedMsTs - pCur->uCreatedMsTs) > 60000 /*60sec*/)
4463 {
4464 RTListNodeRemove(&pCur->ListEntry);
4465 RTMemFree(pCur);
4466 }
4467
4468 /* Insert our new entry. */
4469 RTListAppend(&g_ErrorInfoHead, &pErrorInfo->ListEntry);
4470
4471 RTSemMutexRelease(g_hErrorInfoLock);
4472 }
4473 else
4474 RTMemFree(pErrorInfo);
4475 }
4476
4477 return rc;
4478}
4479
4480
4481# ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
4482
4483/**
4484 * Checks if the current process is being debugged.
4485 * @return @c true if debugged, @c false if not.
4486 */
4487static bool supdrvNtIsDebuggerAttached(void)
4488{
4489 return PsIsProcessBeingDebugged(PsGetCurrentProcess()) != FALSE;
4490}
4491
4492# endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
4493
4494
4495/**
4496 * Terminates the hardening bits.
4497 */
4498static void supdrvNtProtectTerm(void)
4499{
4500 /*
4501 * Stop intercepting process and thread handle creation calls.
4502 */
4503 if (g_pvObCallbacksCookie)
4504 {
4505 g_pfnObUnRegisterCallbacks(g_pvObCallbacksCookie);
4506 g_pvObCallbacksCookie = NULL;
4507 }
4508
4509 /*
4510 * Stop intercepting process creation and termination notifications.
4511 */
4512 NTSTATUS rcNt;
4513 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
4514 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
4515 else
4516 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
4517 AssertMsg(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt));
4518
4519 Assert(g_NtProtectTree == NULL);
4520
4521 /*
4522 * Clean up globals.
4523 */
4524 RTSpinlockDestroy(g_hNtProtectLock);
4525 g_NtProtectTree = NIL_RTSPINLOCK;
4526
4527 RTSemMutexDestroy(g_hErrorInfoLock);
4528 g_hErrorInfoLock = NIL_RTSEMMUTEX;
4529
4530 PSUPDRVNTERRORINFO pCur;
4531 while ((pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL)
4532 {
4533 RTListNodeRemove(&pCur->ListEntry);
4534 RTMemFree(pCur);
4535 }
4536
4537 supHardenedWinTermImageVerifier();
4538}
4539
4540# ifdef RT_ARCH_X86
4541DECLASM(void) supdrvNtQueryVirtualMemory_0xAF(void);
4542DECLASM(void) supdrvNtQueryVirtualMemory_0xB0(void);
4543DECLASM(void) supdrvNtQueryVirtualMemory_0xB1(void);
4544DECLASM(void) supdrvNtQueryVirtualMemory_0xB2(void);
4545DECLASM(void) supdrvNtQueryVirtualMemory_0xB3(void);
4546DECLASM(void) supdrvNtQueryVirtualMemory_0xB4(void);
4547DECLASM(void) supdrvNtQueryVirtualMemory_0xB5(void);
4548DECLASM(void) supdrvNtQueryVirtualMemory_0xB6(void);
4549DECLASM(void) supdrvNtQueryVirtualMemory_0xB7(void);
4550DECLASM(void) supdrvNtQueryVirtualMemory_0xB8(void);
4551DECLASM(void) supdrvNtQueryVirtualMemory_0xB9(void);
4552DECLASM(void) supdrvNtQueryVirtualMemory_0xBA(void);
4553DECLASM(void) supdrvNtQueryVirtualMemory_0xBB(void);
4554DECLASM(void) supdrvNtQueryVirtualMemory_0xBC(void);
4555DECLASM(void) supdrvNtQueryVirtualMemory_0xBD(void);
4556DECLASM(void) supdrvNtQueryVirtualMemory_0xBE(void);
4557# elif defined(RT_ARCH_AMD64)
4558DECLASM(void) supdrvNtQueryVirtualMemory_0x1F(void);
4559DECLASM(void) supdrvNtQueryVirtualMemory_0x20(void);
4560DECLASM(void) supdrvNtQueryVirtualMemory_0x21(void);
4561DECLASM(void) supdrvNtQueryVirtualMemory_0x22(void);
4562DECLASM(void) supdrvNtQueryVirtualMemory_0x23(void);
4563extern "C" NTSYSAPI NTSTATUS NTAPI ZwRequestWaitReplyPort(HANDLE, PVOID, PVOID);
4564# endif
4565
4566
4567/**
4568 * Initalizes the hardening bits.
4569 *
4570 * @returns NT status code.
4571 */
4572static NTSTATUS supdrvNtProtectInit(void)
4573{
4574 /*
4575 * Initialize the globals.
4576 */
4577
4578 /* The NT version. */
4579 ULONG uMajor, uMinor, uBuild;
4580 PsGetVersion(&uMajor, &uMinor, &uBuild, NULL);
4581 g_uNtVerCombined = SUP_MAKE_NT_VER_COMBINED(uMajor, uMinor, uBuild, 0, 0);
4582
4583 /* Resolve methods we want but isn't available everywhere. */
4584 UNICODE_STRING RoutineName;
4585
4586 RtlInitUnicodeString(&RoutineName, L"ObGetObjectType");
4587 g_pfnObGetObjectType = (PFNOBGETOBJECTTYPE)MmGetSystemRoutineAddress(&RoutineName);
4588
4589 RtlInitUnicodeString(&RoutineName, L"ObRegisterCallbacks");
4590 g_pfnObRegisterCallbacks = (PFNOBREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
4591
4592 RtlInitUnicodeString(&RoutineName, L"ObUnRegisterCallbacks");
4593 g_pfnObUnRegisterCallbacks = (PFNOBUNREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
4594
4595 RtlInitUnicodeString(&RoutineName, L"PsSetCreateProcessNotifyRoutineEx");
4596 g_pfnPsSetCreateProcessNotifyRoutineEx = (PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)MmGetSystemRoutineAddress(&RoutineName);
4597
4598 RtlInitUnicodeString(&RoutineName, L"PsReferenceProcessFilePointer");
4599 g_pfnPsReferenceProcessFilePointer = (PFNPSREFERENCEPROCESSFILEPOINTER)MmGetSystemRoutineAddress(&RoutineName);
4600
4601 RtlInitUnicodeString(&RoutineName, L"PsIsProtectedProcessLight");
4602 g_pfnPsIsProtectedProcessLight = (PFNPSISPROTECTEDPROCESSLIGHT)MmGetSystemRoutineAddress(&RoutineName);
4603
4604 RtlInitUnicodeString(&RoutineName, L"ZwAlpcCreatePort");
4605 g_pfnZwAlpcCreatePort = (PFNZWALPCCREATEPORT)MmGetSystemRoutineAddress(&RoutineName);
4606
4607 RtlInitUnicodeString(&RoutineName, L"ZwQueryVirtualMemory"); /* Yes, using Zw version here. */
4608 g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)MmGetSystemRoutineAddress(&RoutineName);
4609 if (!g_pfnNtQueryVirtualMemory && g_uNtVerCombined < SUP_NT_VER_VISTA)
4610 {
4611 /* XP & W2K3 doesn't have this function exported, so we've cooked up a
4612 few alternative in the assembly helper file that uses the code in
4613 ZwReadFile with a different eax value. We figure the syscall number
4614 by inspecting ZwQueryVolumeInformationFile as it's the next number. */
4615# ifdef RT_ARCH_X86
4616 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwQueryVolumeInformationFile;
4617 if (*pbCode == 0xb8) /* mov eax, dword */
4618 switch (*(uint32_t const *)&pbCode[1])
4619 {
4620 case 0xb0: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xAF; break; /* just in case */
4621 case 0xb1: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB0; break; /* just in case */
4622 case 0xb2: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB1; break; /* just in case */
4623 case 0xb3: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* XP SP3 */
4624 case 0xb4: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* just in case */
4625 case 0xb5: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB3; break; /* just in case */
4626 case 0xb6: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB4; break; /* just in case */
4627 case 0xb7: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB5; break; /* just in case */
4628 case 0xb8: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB6; break; /* just in case */
4629 case 0xb9: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB7; break; /* just in case */
4630 case 0xba: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB8; break; /* just in case */
4631 case 0xbb: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBA; break; /* W2K3 R2 SP2 */
4632 case 0xbc: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBB; break; /* just in case */
4633 case 0xbd: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBC; break; /* just in case */
4634 case 0xbe: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBD; break; /* just in case */
4635 case 0xbf: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBE; break; /* just in case */
4636 }
4637# elif defined(RT_ARCH_AMD64)
4638 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwRequestWaitReplyPort;
4639 if ( pbCode[ 0] == 0x48 /* mov rax, rsp */
4640 && pbCode[ 1] == 0x8b
4641 && pbCode[ 2] == 0xc4
4642 && pbCode[ 3] == 0xfa /* cli */
4643 && pbCode[ 4] == 0x48 /* sub rsp, 10h */
4644 && pbCode[ 5] == 0x83
4645 && pbCode[ 6] == 0xec
4646 && pbCode[ 7] == 0x10
4647 && pbCode[ 8] == 0x50 /* push rax */
4648 && pbCode[ 9] == 0x9c /* pushfq */
4649 && pbCode[10] == 0x6a /* push 10 */
4650 && pbCode[11] == 0x10
4651 && pbCode[12] == 0x48 /* lea rax, [nt!KiServiceLinkage] */
4652 && pbCode[13] == 0x8d
4653 && pbCode[14] == 0x05
4654 && pbCode[19] == 0x50 /* push rax */
4655 && pbCode[20] == 0xb8 /* mov eax,1fh <- the syscall no. */
4656 /*&& pbCode[21] == 0x1f*/
4657 && pbCode[22] == 0x00
4658 && pbCode[23] == 0x00
4659 && pbCode[24] == 0x00
4660 && pbCode[25] == 0xe9 /* jmp KiServiceInternal */
4661 )
4662 {
4663 uint8_t const *pbKiServiceInternal = &pbCode[30] + *(int32_t const *)&pbCode[26];
4664 uint8_t const *pbKiServiceLinkage = &pbCode[19] + *(int32_t const *)&pbCode[15];
4665 if (*pbKiServiceLinkage == 0xc3)
4666 {
4667 g_pfnKiServiceInternal = (PFNRT)pbKiServiceInternal;
4668 g_pfnKiServiceLinkage = (PFNRT)pbKiServiceLinkage;
4669 switch (pbCode[21])
4670 {
4671 case 0x1e: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x1F; break;
4672 case 0x1f: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x20; break;
4673 case 0x20: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x21; break;
4674 case 0x21: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x22; break;
4675 case 0x22: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x23; break;
4676 }
4677 }
4678 }
4679# endif
4680 }
4681 if (!g_pfnNtQueryVirtualMemory)
4682 {
4683 LogRel(("vboxdrv: Cannot locate ZwQueryVirtualMemory in ntoskrnl, nor were we able to cook up a replacement.\n"));
4684 return STATUS_PROCEDURE_NOT_FOUND;
4685 }
4686
4687# ifdef VBOX_STRICT
4688 if ( g_uNtVerCombined >= SUP_NT_VER_W70
4689 && ( g_pfnObGetObjectType == NULL
4690 || g_pfnZwAlpcCreatePort == NULL) )
4691 {
4692 LogRel(("vboxdrv: g_pfnObGetObjectType=%p g_pfnZwAlpcCreatePort=%p.\n", g_pfnObGetObjectType, g_pfnZwAlpcCreatePort));
4693 return STATUS_PROCEDURE_NOT_FOUND;
4694 }
4695# endif
4696
4697 /* LPC object type. */
4698 g_pAlpcPortObjectType1 = *LpcPortObjectType;
4699
4700 /* The spinlock protecting our structures. */
4701 int rc = RTSpinlockCreate(&g_hNtProtectLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "NtProtectLock");
4702 if (RT_FAILURE(rc))
4703 return VBoxDrvNtErr2NtStatus(rc);
4704 g_NtProtectTree = NULL;
4705
4706 NTSTATUS rcNt;
4707
4708 /* The mutex protecting the error information. */
4709 RTListInit(&g_ErrorInfoHead);
4710 rc = RTSemMutexCreate(&g_hErrorInfoLock);
4711 if (RT_SUCCESS(rc))
4712 {
4713 /* Image stuff + certificates. */
4714 rc = supHardenedWinInitImageVerifier(NULL);
4715 if (RT_SUCCESS(rc))
4716 {
4717 /*
4718 * Intercept process creation and termination.
4719 */
4720 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
4721 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
4722 else
4723 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
4724 if (NT_SUCCESS(rcNt))
4725 {
4726 /*
4727 * Intercept process and thread handle creation calls.
4728 * The preferred method is only available on Vista SP1+.
4729 */
4730 if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
4731 {
4732 static OB_OPERATION_REGISTRATION s_aObOperations[] =
4733 {
4734 {
4735 0, /* PsProcessType - imported, need runtime init, better do it explicitly. */
4736 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
4737 supdrvNtProtectCallback_ProcessHandlePre,
4738 supdrvNtProtectCallback_ProcessHandlePost,
4739 },
4740 {
4741 0, /* PsThreadType - imported, need runtime init, better do it explicitly. */
4742 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
4743 supdrvNtProtectCallback_ThreadHandlePre,
4744 supdrvNtProtectCallback_ThreadHandlePost,
4745 },
4746 };
4747 s_aObOperations[0].ObjectType = PsProcessType;
4748 s_aObOperations[1].ObjectType = PsThreadType;
4749
4750 static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
4751 {
4752 /* .Version = */ OB_FLT_REGISTRATION_VERSION,
4753 /* .OperationRegistrationCount = */ RT_ELEMENTS(s_aObOperations),
4754 /* .Altitude.Length = */ 0,
4755 /* .Altitude.MaximumLength = */ 0,
4756 /* .Altitude.Buffer = */ NULL,
4757 /* .RegistrationContext = */ NULL,
4758 /* .OperationRegistration = */ &s_aObOperations[0]
4759 };
4760 static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
4761 {
4762 L"48596.98940", L"46935.19485", L"49739.39704", L"40334.74976",
4763 L"66667.98940", L"69888.19485", L"69889.39704", L"60364.74976",
4764 L"85780.98940", L"88978.19485", L"89939.39704", L"80320.74976",
4765 L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
4766 };
4767
4768 rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
4769 for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
4770 {
4771 s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
4772 s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
4773 s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
4774
4775 rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
4776 if (NT_SUCCESS(rcNt))
4777 {
4778 /*
4779 * Happy ending.
4780 */
4781 return STATUS_SUCCESS;
4782 }
4783 }
4784 LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
4785 g_pvObCallbacksCookie = NULL;
4786 }
4787 else
4788 {
4789 /*
4790 * For the time being, we do not implement extra process
4791 * protection on pre-Vista-SP1 systems as they are lacking
4792 * necessary KPIs. XP is end of life, we do not wish to
4793 * spend more time on it, so we don't put up a fuss there.
4794 * Vista users without SP1 can install SP1 (or later), darn it,
4795 * so refuse to load.
4796 */
4797 /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
4798 * stuff to a couple of object types. */
4799# ifndef VBOX_WITH_VISTA_NO_SP
4800 if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
4801# else
4802 if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
4803# endif
4804 {
4805 DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
4806 rcNt = STATUS_SXS_VERSION_CONFLICT;
4807 }
4808 else
4809 {
4810 Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
4811 return rcNt = STATUS_SUCCESS;
4812 }
4813 g_pvObCallbacksCookie = NULL;
4814 }
4815
4816 /*
4817 * Drop process create/term notifications.
4818 */
4819 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
4820 g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
4821 else
4822 PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
4823 }
4824 else
4825 LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
4826 g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
4827 supHardenedWinTermImageVerifier();
4828 }
4829 else
4830 rcNt = VBoxDrvNtErr2NtStatus(rc);
4831
4832 RTSemMutexDestroy(g_hErrorInfoLock);
4833 g_hErrorInfoLock = NIL_RTSEMMUTEX;
4834 }
4835 else
4836 rcNt = VBoxDrvNtErr2NtStatus(rc);
4837
4838 RTSpinlockDestroy(g_hNtProtectLock);
4839 g_NtProtectTree = NIL_RTSPINLOCK;
4840 return rcNt;
4841}
4842
4843#endif /* VBOX_WITH_HARDENING */
4844
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use