VirtualBox

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

Last change on this file since 67954 was 67954, checked in by vboxsync, 7 years ago

win/SUPDrv-win*: Changed SUPR0Printf from directly passing the parameters to DbgPrint to format into a stack buffer like the rest. Fixed garbage caused by using in SUPR0Printf calls.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 193.5 KB
Line 
1/* $Id: SUPDrv-win.cpp 67954 2017-07-13 21:06:09Z 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/**
2467 * Alternative version of SUPR0Printf for Windows.
2468 *
2469 * @returns 0.
2470 * @param pszFormat The format string.
2471 */
2472SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
2473{
2474 va_list va;
2475 char szMsg[384];
2476
2477 va_start(va, pszFormat);
2478 size_t cch = RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
2479 szMsg[sizeof(szMsg) - 1] = '\0';
2480 va_end(va);
2481
2482 RTLogWriteDebugger(szMsg, cch);
2483 return 0;
2484}
2485
2486
2487SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
2488{
2489 return 0;
2490}
2491
2492
2493#ifdef VBOX_WITH_HARDENING
2494
2495/** @name Identifying Special Processes: CSRSS.EXE
2496 * @{ */
2497
2498
2499/**
2500 * Checks if the process is a system32 process by the given name.
2501 *
2502 * @returns true / false.
2503 * @param pProcess The process to check.
2504 * @param pszName The lower case process name (no path!).
2505 */
2506static bool supdrvNtProtectIsSystem32ProcessMatch(PEPROCESS pProcess, const char *pszName)
2507{
2508 Assert(strlen(pszName) < 16); /* see buffer below */
2509
2510 /*
2511 * This test works on XP+.
2512 */
2513 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
2514 if (!pszImageFile)
2515 return false;
2516
2517 if (RTStrICmp(pszImageFile, pszName) != 0)
2518 return false;
2519
2520 /*
2521 * This test requires a Vista+ API.
2522 */
2523 if (g_pfnPsReferenceProcessFilePointer)
2524 {
2525 PFILE_OBJECT pFile = NULL;
2526 NTSTATUS rcNt = g_pfnPsReferenceProcessFilePointer(pProcess, &pFile);
2527 if (!NT_SUCCESS(rcNt))
2528 return false;
2529
2530 union
2531 {
2532 OBJECT_NAME_INFORMATION Info;
2533 uint8_t abBuffer[sizeof(g_System32NtPath) + 16 * sizeof(WCHAR)];
2534 } Buf;
2535 ULONG cbIgn;
2536 rcNt = ObQueryNameString(pFile, &Buf.Info, sizeof(Buf) - sizeof(WCHAR), &cbIgn);
2537 ObDereferenceObject(pFile);
2538 if (!NT_SUCCESS(rcNt))
2539 return false;
2540
2541 /* Terminate the name. */
2542 PRTUTF16 pwszName = Buf.Info.Name.Buffer;
2543 pwszName[Buf.Info.Name.Length / sizeof(RTUTF16)] = '\0';
2544
2545 /* Match the name against the system32 directory path. */
2546 uint32_t cbSystem32 = g_System32NtPath.UniStr.Length;
2547 if (Buf.Info.Name.Length < cbSystem32)
2548 return false;
2549 if (memcmp(pwszName, g_System32NtPath.UniStr.Buffer, cbSystem32))
2550 return false;
2551 pwszName += cbSystem32 / sizeof(RTUTF16);
2552 if (*pwszName++ != '\\')
2553 return false;
2554
2555 /* Compare the name. */
2556 const char *pszRight = pszName;
2557 for (;;)
2558 {
2559 WCHAR wchLeft = *pwszName++;
2560 char chRight = *pszRight++;
2561 Assert(chRight == RT_C_TO_LOWER(chRight));
2562
2563 if ( wchLeft != chRight
2564 && RT_C_TO_LOWER(wchLeft) != chRight)
2565 return false;
2566 if (!chRight)
2567 break;
2568 }
2569 }
2570
2571 return true;
2572}
2573
2574
2575/**
2576 * Checks if the current process is likely to be CSRSS.
2577 *
2578 * @returns true/false.
2579 * @param pProcess The process.
2580 */
2581static bool supdrvNtProtectIsCsrssByProcess(PEPROCESS pProcess)
2582{
2583 /*
2584 * On Windows 8.1 CSRSS.EXE is a protected process.
2585 */
2586 if (g_pfnPsIsProtectedProcessLight)
2587 {
2588 if (!g_pfnPsIsProtectedProcessLight(pProcess))
2589 return false;
2590 }
2591
2592 /*
2593 * The name tests.
2594 */
2595 if (!supdrvNtProtectIsSystem32ProcessMatch(pProcess, "csrss.exe"))
2596 return false;
2597
2598 /** @todo Could extend the CSRSS.EXE check with that the TokenUser of the
2599 * current process must be "NT AUTHORITY\SYSTEM" (S-1-5-18). */
2600
2601 return true;
2602}
2603
2604
2605/**
2606 * Helper for supdrvNtProtectGetAlpcPortObjectType that tries out a name.
2607 *
2608 * @returns true if done, false if not.
2609 * @param pwszPortNm The port path.
2610 * @param ppObjType The object type return variable, updated when
2611 * returning true.
2612 */
2613static bool supdrvNtProtectGetAlpcPortObjectType2(PCRTUTF16 pwszPortNm, POBJECT_TYPE *ppObjType)
2614{
2615 bool fDone = false;
2616
2617 UNICODE_STRING UniStrPortNm;
2618 UniStrPortNm.Buffer = (WCHAR *)pwszPortNm;
2619 UniStrPortNm.Length = (USHORT)(RTUtf16Len(pwszPortNm) * sizeof(WCHAR));
2620 UniStrPortNm.MaximumLength = UniStrPortNm.Length + sizeof(WCHAR);
2621
2622 OBJECT_ATTRIBUTES ObjAttr;
2623 InitializeObjectAttributes(&ObjAttr, &UniStrPortNm, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
2624
2625 HANDLE hPort;
2626 NTSTATUS rcNt = g_pfnZwAlpcCreatePort(&hPort, &ObjAttr, NULL /*pPortAttribs*/);
2627 if (NT_SUCCESS(rcNt))
2628 {
2629 PVOID pvObject;
2630 rcNt = ObReferenceObjectByHandle(hPort, 0 /*DesiredAccess*/, NULL /*pObjectType*/,
2631 KernelMode, &pvObject, NULL /*pHandleInfo*/);
2632 if (NT_SUCCESS(rcNt))
2633 {
2634 POBJECT_TYPE pObjType = g_pfnObGetObjectType(pvObject);
2635 if (pObjType)
2636 {
2637 SUPR0Printf("vboxdrv: ALPC Port Object Type %p (vs %p)\n", pObjType, *ppObjType);
2638 *ppObjType = pObjType;
2639 fDone = true;
2640 }
2641 ObDereferenceObject(pvObject);
2642 }
2643 NtClose(hPort);
2644 }
2645 return fDone;
2646}
2647
2648
2649/**
2650 * Attempts to retrieve the ALPC Port object type.
2651 *
2652 * We've had at least three reports that using LpcPortObjectType when trying to
2653 * get at the ApiPort object results in STATUS_OBJECT_TYPE_MISMATCH errors.
2654 * It's not known who has modified LpcPortObjectType or AlpcPortObjectType (not
2655 * exported) so that it differs from the actual ApiPort type, or maybe this
2656 * unknown entity is intercepting our attempt to reference the port and
2657 * tries to mislead us. The paranoid explanataion is of course that some evil
2658 * root kit like software is messing with the OS, however, it's possible that
2659 * this is valid kernel behavior that 99.8% of our users and 100% of the
2660 * developers are not triggering for some reason.
2661 *
2662 * The code here creates an ALPC port object and gets it's type. It will cache
2663 * the result in g_pAlpcPortObjectType2 on success.
2664 *
2665 * @returns Object type.
2666 * @param uSessionId The session id.
2667 * @param pszSessionId The session id formatted as a string.
2668 */
2669static POBJECT_TYPE supdrvNtProtectGetAlpcPortObjectType(uint32_t uSessionId, const char *pszSessionId)
2670{
2671 POBJECT_TYPE pObjType = *LpcPortObjectType;
2672
2673 if ( g_pfnZwAlpcCreatePort
2674 && g_pfnObGetObjectType)
2675 {
2676 int rc;
2677 ssize_t cchTmp; NOREF(cchTmp);
2678 char szTmp[16];
2679 RTUTF16 wszPortNm[128];
2680 size_t offRand;
2681
2682 /*
2683 * First attempt is in the session directory.
2684 */
2685 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
2686 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
2687 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\VBoxDrv-");
2688 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
2689 Assert(cchTmp > 0);
2690 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2691 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
2692 offRand = RTUtf16Len(wszPortNm);
2693 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
2694 Assert(cchTmp > 0);
2695 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2696 AssertRCSuccess(rc);
2697
2698 bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2699 if (!fDone)
2700 {
2701 wszPortNm[offRand] = '\0';
2702 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0); Assert(cchTmp > 0);
2703 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2704 AssertRCSuccess(rc);
2705
2706 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2707 }
2708 if (!fDone)
2709 {
2710 /*
2711 * Try base names.
2712 */
2713 if (uSessionId == 0)
2714 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
2715 else
2716 {
2717 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
2718 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
2719 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
2720 }
2721 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
2722 Assert(cchTmp > 0);
2723 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2724 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
2725 offRand = RTUtf16Len(wszPortNm);
2726 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
2727 Assert(cchTmp > 0);
2728 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2729 AssertRCSuccess(rc);
2730
2731 bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2732 if (!fDone)
2733 {
2734 wszPortNm[offRand] = '\0';
2735 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
2736 Assert(cchTmp > 0);
2737 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2738 AssertRCSuccess(rc);
2739
2740 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2741 }
2742 }
2743
2744 /* Cache the result in g_pAlpcPortObjectType2. */
2745 if ( g_pAlpcPortObjectType2 == NULL
2746 && pObjType != g_pAlpcPortObjectType1
2747 && fDone)
2748 g_pAlpcPortObjectType2 = pObjType;
2749
2750 }
2751
2752 return pObjType;
2753}
2754
2755
2756/**
2757 * Called in the context of VBoxDrvNtCreate to determin the CSRSS for the
2758 * current process.
2759 *
2760 * The Client/Server Runtime Subsystem (CSRSS) process needs to be allowed some
2761 * additional access right so we need to make 101% sure we correctly identify
2762 * the CSRSS process a process is associated with.
2763 *
2764 * @returns IPRT status code.
2765 * @param pNtProtect The NT protected process structure. The
2766 * hCsrssPid member will be updated on success.
2767 */
2768static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect)
2769{
2770 Assert(pNtProtect->AvlCore.Key == PsGetCurrentProcessId());
2771 Assert(pNtProtect->pCsrssProcess == NULL);
2772 Assert(pNtProtect->hCsrssPid == NULL);
2773
2774 /*
2775 * We'll try use the ApiPort LPC object for the session we're in to track
2776 * down the CSRSS process. So, we start by constructing a path to it.
2777 */
2778 int rc;
2779 uint32_t uSessionId = PsGetProcessSessionId(PsGetCurrentProcess());
2780 char szSessionId[16];
2781 WCHAR wszApiPort[48];
2782 if (uSessionId == 0)
2783 {
2784 szSessionId[0] = '0';
2785 szSessionId[1] = '\0';
2786 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
2787 }
2788 else
2789 {
2790 ssize_t cchTmp = RTStrFormatU32(szSessionId, sizeof(szSessionId), uSessionId, 10, 0, 0, 0);
2791 AssertReturn(cchTmp > 0, (int)cchTmp);
2792 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Sessions\\");
2793 if (RT_SUCCESS(rc))
2794 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), szSessionId);
2795 if (RT_SUCCESS(rc))
2796 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
2797 }
2798 AssertRCReturn(rc, rc);
2799
2800 UNICODE_STRING ApiPortStr;
2801 ApiPortStr.Buffer = wszApiPort;
2802 ApiPortStr.Length = (USHORT)(RTUtf16Len(wszApiPort) * sizeof(RTUTF16));
2803 ApiPortStr.MaximumLength = ApiPortStr.Length + sizeof(RTUTF16);
2804
2805 /*
2806 * The object cannot be opened, but we can reference it by name.
2807 */
2808 void *pvApiPortObj = NULL;
2809 NTSTATUS rcNt = ObReferenceObjectByName(&ApiPortStr,
2810 0,
2811 NULL /*pAccessState*/,
2812 STANDARD_RIGHTS_READ,
2813 g_pAlpcPortObjectType1,
2814 KernelMode,
2815 NULL /*pvParseContext*/,
2816 &pvApiPortObj);
2817 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
2818 && g_pAlpcPortObjectType2 != NULL)
2819 rcNt = ObReferenceObjectByName(&ApiPortStr,
2820 0,
2821 NULL /*pAccessState*/,
2822 STANDARD_RIGHTS_READ,
2823 g_pAlpcPortObjectType2,
2824 KernelMode,
2825 NULL /*pvParseContext*/,
2826 &pvApiPortObj);
2827 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
2828 && g_pfnObGetObjectType
2829 && g_pfnZwAlpcCreatePort)
2830 rcNt = ObReferenceObjectByName(&ApiPortStr,
2831 0,
2832 NULL /*pAccessState*/,
2833 STANDARD_RIGHTS_READ,
2834 supdrvNtProtectGetAlpcPortObjectType(uSessionId, szSessionId),
2835 KernelMode,
2836 NULL /*pvParseContext*/,
2837 &pvApiPortObj);
2838 if (!NT_SUCCESS(rcNt))
2839 {
2840 SUPR0Printf("vboxdrv: Error opening '%ls': %#x\n", wszApiPort, rcNt);
2841 return rcNt == STATUS_OBJECT_TYPE_MISMATCH ? VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE : VERR_SUPDRV_APIPORT_OPEN_ERROR;
2842 }
2843
2844 /*
2845 * Query the processes in the system so we can locate CSRSS.EXE candidates.
2846 * Note! Attempts at using SystemSessionProcessInformation failed with
2847 * STATUS_ACCESS_VIOLATION.
2848 * Note! The 32 bytes on the size of to counteract the allocation header
2849 * that rtR0MemAllocEx slaps on everything.
2850 */
2851 ULONG cbNeeded = _64K - 32;
2852 uint32_t cbBuf;
2853 uint8_t *pbBuf = NULL;
2854 do
2855 {
2856 cbBuf = RT_ALIGN(cbNeeded + _4K, _64K) - 32;
2857 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
2858 if (!pbBuf)
2859 break;
2860
2861 cbNeeded = 0;
2862#if 0 /* doesn't work. */
2863 SYSTEM_SESSION_PROCESS_INFORMATION Req;
2864 Req.SessionId = uSessionId;
2865 Req.BufferLength = cbBuf;
2866 Req.Buffer = pbBuf;
2867 rcNt = NtQuerySystemInformation(SystemSessionProcessInformation, &Req, sizeof(Req), &cbNeeded);
2868#else
2869 rcNt = NtQuerySystemInformation(SystemProcessInformation, pbBuf, cbBuf, &cbNeeded);
2870#endif
2871 if (NT_SUCCESS(rcNt))
2872 break;
2873
2874 RTMemFree(pbBuf);
2875 pbBuf = NULL;
2876 } while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
2877 && cbNeeded > cbBuf
2878 && cbNeeded < 32U*_1M);
2879
2880 if ( pbBuf
2881 && NT_SUCCESS(rcNt)
2882 && cbNeeded >= sizeof(SYSTEM_PROCESS_INFORMATION))
2883 {
2884 /*
2885 * Walk the returned data and look for the process associated with the
2886 * ApiPort object. The ApiPort object keeps the EPROCESS address of
2887 * the owner process (i.e. CSRSS) relatively early in the structure. On
2888 * 64-bit windows 8.1 it's at offset 0x18. So, obtain the EPROCESS
2889 * pointer to likely CSRSS processes and check for a match in the first
2890 * 0x40 bytes of the ApiPort object.
2891 */
2892 rc = VERR_SUPDRV_CSRSS_NOT_FOUND;
2893 for (uint32_t offBuf = 0; offBuf <= cbNeeded - sizeof(SYSTEM_PROCESS_INFORMATION);)
2894 {
2895 PRTNT_SYSTEM_PROCESS_INFORMATION pProcInfo = (PRTNT_SYSTEM_PROCESS_INFORMATION)&pbBuf[offBuf];
2896 if ( pProcInfo->ProcessName.Length == 9 * sizeof(WCHAR)
2897 && pProcInfo->NumberOfThreads > 2 /* Very low guess. */
2898 && pProcInfo->HandleCount > 32 /* Very low guess, I hope. */
2899 && (uintptr_t)pProcInfo->ProcessName.Buffer - (uintptr_t)pbBuf < cbNeeded
2900 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[0]) == 'c'
2901 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[1]) == 's'
2902 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[2]) == 'r'
2903 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[3]) == 's'
2904 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[4]) == 's'
2905 && pProcInfo->ProcessName.Buffer[5] == '.'
2906 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[6]) == 'e'
2907 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[7]) == 'x'
2908 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[8]) == 'e' )
2909 {
2910
2911 /* Get the process structure and perform some more thorough
2912 process checks. */
2913 PEPROCESS pProcess;
2914 rcNt = PsLookupProcessByProcessId(pProcInfo->UniqueProcessId, &pProcess);
2915 if (NT_SUCCESS(rcNt))
2916 {
2917 if (supdrvNtProtectIsCsrssByProcess(pProcess))
2918 {
2919 if (PsGetProcessSessionId(pProcess) == uSessionId)
2920 {
2921 /* Final test, check the ApiPort.
2922 Note! The old LPC (pre Vista) objects has the PID
2923 much earlier in the structure. Might be
2924 worth looking for it instead. */
2925 bool fThatsIt = false;
2926 __try
2927 {
2928 PEPROCESS *ppPortProc = (PEPROCESS *)pvApiPortObj;
2929 uint32_t cTests = g_uNtVerCombined >= SUP_NT_VER_VISTA ? 16 : 38; /* ALPC since Vista. */
2930 do
2931 {
2932 fThatsIt = *ppPortProc == pProcess;
2933 ppPortProc++;
2934 } while (!fThatsIt && --cTests > 0);
2935 }
2936 __except(EXCEPTION_EXECUTE_HANDLER)
2937 {
2938 fThatsIt = false;
2939 }
2940 if (fThatsIt)
2941 {
2942 /* Ok, we found it! Keep the process structure
2943 reference as well as the PID so we can
2944 safely identify it later on. */
2945 pNtProtect->hCsrssPid = pProcInfo->UniqueProcessId;
2946 pNtProtect->pCsrssProcess = pProcess;
2947 rc = VINF_SUCCESS;
2948 break;
2949 }
2950 }
2951 }
2952
2953 ObDereferenceObject(pProcess);
2954 }
2955 }
2956
2957 /* Advance. */
2958 if (!pProcInfo->NextEntryOffset)
2959 break;
2960 offBuf += pProcInfo->NextEntryOffset;
2961 }
2962 }
2963 else
2964 rc = VERR_SUPDRV_SESSION_PROCESS_ENUM_ERROR;
2965 RTMemFree(pbBuf);
2966 ObDereferenceObject(pvApiPortObj);
2967 return rc;
2968}
2969
2970
2971/**
2972 * Checks that the given process is the CSRSS process associated with protected
2973 * process.
2974 *
2975 * @returns true / false.
2976 * @param pNtProtect The NT protection structure.
2977 * @param pCsrss The process structure of the alleged CSRSS.EXE
2978 * process.
2979 */
2980static bool supdrvNtProtectIsAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pCsrss)
2981{
2982 if (pNtProtect->pCsrssProcess == pCsrss)
2983 {
2984 if (pNtProtect->hCsrssPid == PsGetProcessId(pCsrss))
2985 {
2986 return true;
2987 }
2988 }
2989 return false;
2990}
2991
2992
2993/**
2994 * Checks if the given process is the stupid themes service.
2995 *
2996 * The caller does some screening of access masks and what not. We do the rest.
2997 *
2998 * @returns true / false.
2999 * @param pNtProtect The NT protection structure.
3000 * @param pAnnoyingProcess The process structure of an process that might
3001 * happen to be the annoying themes process.
3002 */
3003static bool supdrvNtProtectIsFrigginThemesService(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pAnnoyingProcess)
3004{
3005 RT_NOREF1(pNtProtect);
3006
3007 /*
3008 * Check the process name.
3009 */
3010 if (!supdrvNtProtectIsSystem32ProcessMatch(pAnnoyingProcess, "svchost.exe"))
3011 return false;
3012
3013 /** @todo Come up with more checks. */
3014
3015 return true;
3016}
3017
3018
3019#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3020/**
3021 * Checks if the given process is one of the whitelisted debuggers.
3022 *
3023 * @returns true / false.
3024 * @param pProcess The process to check.
3025 */
3026static bool supdrvNtProtectIsWhitelistedDebugger(PEPROCESS pProcess)
3027{
3028 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
3029 if (!pszImageFile)
3030 return false;
3031
3032 if (pszImageFile[0] == 'w' || pszImageFile[0] == 'W')
3033 {
3034 if (RTStrICmp(pszImageFile, "windbg.exe") == 0)
3035 return true;
3036 if (RTStrICmp(pszImageFile, "werfault.exe") == 0)
3037 return true;
3038 if (RTStrICmp(pszImageFile, "werfaultsecure.exe") == 0)
3039 return true;
3040 }
3041 else if (pszImageFile[0] == 'd' || pszImageFile[0] == 'D')
3042 {
3043 if (RTStrICmp(pszImageFile, "drwtsn32.exe") == 0)
3044 return true;
3045 if (RTStrICmp(pszImageFile, "dwwin.exe") == 0)
3046 return true;
3047 }
3048
3049 return false;
3050}
3051#endif /* VBOX_WITHOUT_DEBUGGER_CHECKS */
3052
3053
3054/** @} */
3055
3056
3057/** @name Process Creation Callbacks.
3058 * @{ */
3059
3060
3061/**
3062 * Cleans up VBoxDrv or VBoxDrvStub error info not collected by the dead process.
3063 *
3064 * @param hProcessId The ID of the dead process.
3065 */
3066static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId)
3067{
3068 int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
3069 if (RT_SUCCESS(rc))
3070 {
3071 PSUPDRVNTERRORINFO pCur, pNext;
3072 RTListForEachSafe(&g_ErrorInfoHead, pCur, pNext, SUPDRVNTERRORINFO, ListEntry)
3073 {
3074 if (pCur->hProcessId == hProcessId)
3075 {
3076 RTListNodeRemove(&pCur->ListEntry);
3077 RTMemFree(pCur);
3078 }
3079 }
3080 RTSemMutexRelease(g_hErrorInfoLock);
3081 }
3082}
3083
3084
3085/**
3086 * Common worker used by the process creation hooks as well as the process
3087 * handle creation hooks to check if a VM process is being created.
3088 *
3089 * @returns true if likely to be a VM process, false if not.
3090 * @param pNtStub The NT protection structure for the possible
3091 * stub process.
3092 * @param hParentPid The parent pid.
3093 * @param hChildPid The child pid.
3094 */
3095static bool supdrvNtProtectIsSpawningStubProcess(PSUPDRVNTPROTECT pNtStub, HANDLE hParentPid, HANDLE hChildPid)
3096{
3097 bool fRc = false;
3098 if (pNtStub->AvlCore.Key == hParentPid) /* paranoia */
3099 {
3100 if (pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
3101 {
3102 /* Compare short names. */
3103 PEPROCESS pStubProcess;
3104 NTSTATUS rcNt = PsLookupProcessByProcessId(hParentPid, &pStubProcess);
3105 if (NT_SUCCESS(rcNt))
3106 {
3107 PEPROCESS pChildProcess;
3108 rcNt = PsLookupProcessByProcessId(hChildPid, &pChildProcess);
3109 if (NT_SUCCESS(rcNt))
3110 {
3111 const char *pszStub = (const char *)PsGetProcessImageFileName(pStubProcess);
3112 const char *pszChild = (const char *)PsGetProcessImageFileName(pChildProcess);
3113 fRc = pszStub != NULL
3114 && pszChild != NULL
3115 && strcmp(pszStub, pszChild) == 0;
3116
3117 /** @todo check that the full image names matches. */
3118
3119 ObDereferenceObject(pChildProcess);
3120 }
3121 ObDereferenceObject(pStubProcess);
3122 }
3123 }
3124 }
3125 return fRc;
3126}
3127
3128
3129/**
3130 * Common code used by the notifies to protect a child process.
3131 *
3132 * @returns VBox status code.
3133 * @param pNtStub The NT protect structure for the parent.
3134 * @param hChildPid The child pid.
3135 */
3136static int supdrvNtProtectProtectNewStubChild(PSUPDRVNTPROTECT pNtParent, HANDLE hChildPid)
3137{
3138 /*
3139 * Create a child protection struction.
3140 */
3141 PSUPDRVNTPROTECT pNtChild;
3142 int rc = supdrvNtProtectCreate(&pNtChild, hChildPid, kSupDrvNtProtectKind_VmProcessUnconfirmed, false /*fLink*/);
3143 if (RT_SUCCESS(rc))
3144 {
3145 pNtChild->fFirstProcessCreateHandle = true;
3146 pNtChild->fFirstThreadCreateHandle = true;
3147 pNtChild->fCsrssFirstProcessCreateHandle = true;
3148 pNtChild->cCsrssFirstProcessDuplicateHandle = ARCH_BITS == 32 ? 2 : 1;
3149 pNtChild->fThemesFirstProcessCreateHandle = true;
3150 pNtChild->hParentPid = pNtParent->AvlCore.Key;
3151 pNtChild->hCsrssPid = pNtParent->hCsrssPid;
3152 pNtChild->pCsrssProcess = pNtParent->pCsrssProcess;
3153 if (pNtChild->pCsrssProcess)
3154 ObReferenceObject(pNtChild->pCsrssProcess);
3155
3156 /*
3157 * Take the spinlock, recheck parent conditions and link things.
3158 */
3159 RTSpinlockAcquire(g_hNtProtectLock);
3160 if (pNtParent->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
3161 {
3162 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtChild->AvlCore);
3163 if (fSuccess)
3164 {
3165 pNtChild->fInTree = true;
3166 pNtParent->u.pChild = pNtChild; /* Parent keeps the initial reference. */
3167 pNtParent->enmProcessKind = kSupDrvNtProtectKind_StubParent;
3168 pNtChild->u.pParent = pNtParent;
3169
3170 RTSpinlockRelease(g_hNtProtectLock);
3171 return VINF_SUCCESS;
3172 }
3173
3174 rc = VERR_INTERNAL_ERROR_2;
3175 }
3176 else
3177 rc = VERR_WRONG_ORDER;
3178 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3179 RTSpinlockRelease(g_hNtProtectLock);
3180
3181 supdrvNtProtectRelease(pNtChild);
3182 }
3183 return rc;
3184}
3185
3186
3187/**
3188 * Common process termination code.
3189 *
3190 * Transitions protected process to the dead states, protecting against handle
3191 * PID reuse (esp. with unconfirmed VM processes) and handle cleanup issues.
3192 *
3193 * @param hDeadPid The PID of the dead process.
3194 */
3195static void supdrvNtProtectUnprotectDeadProcess(HANDLE hDeadPid)
3196{
3197 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hDeadPid);
3198 if (pNtProtect)
3199 {
3200 PSUPDRVNTPROTECT pNtChild = NULL;
3201
3202 RTSpinlockAcquire(g_hNtProtectLock);
3203
3204 /*
3205 * If this is an unconfirmed VM process, we must release the reference
3206 * the parent structure holds.
3207 */
3208 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3209 {
3210 PSUPDRVNTPROTECT pNtParent = pNtProtect->u.pParent;
3211 AssertRelease(pNtParent); AssertRelease(pNtParent->u.pChild == pNtProtect);
3212 pNtParent->u.pChild = NULL;
3213 pNtProtect->u.pParent = NULL;
3214 pNtChild = pNtProtect;
3215 }
3216 /*
3217 * If this is a stub exitting before the VM process gets confirmed,
3218 * release the protection of the potential VM process as this is not
3219 * the prescribed behavior.
3220 */
3221 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
3222 && pNtProtect->u.pChild)
3223 {
3224 pNtChild = pNtProtect->u.pChild;
3225 pNtProtect->u.pChild = NULL;
3226 pNtChild->u.pParent = NULL;
3227 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3228 }
3229
3230 /*
3231 * Transition it to the dead state to prevent it from opening the
3232 * support driver again or be posthumously abused as a vm process parent.
3233 */
3234 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3235 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessConfirmed)
3236 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3237 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
3238 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubSpawning
3239 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
3240 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_StubDead;
3241
3242 RTSpinlockRelease(g_hNtProtectLock);
3243
3244 supdrvNtProtectRelease(pNtProtect);
3245 supdrvNtProtectRelease(pNtChild);
3246
3247 /*
3248 * Do session cleanups.
3249 */
3250 AssertReturnVoid((HANDLE)(uintptr_t)RTProcSelf() == hDeadPid);
3251 if (g_pDevObjSys)
3252 {
3253 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
3254 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, (RTPROCESS)(uintptr_t)hDeadPid,
3255 RTR0ProcHandleSelf(), NULL);
3256 if (pSession)
3257 {
3258 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
3259 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
3260 }
3261 }
3262 }
3263}
3264
3265
3266/**
3267 * Common worker for the process creation callback that verifies a new child
3268 * being created by the handle creation callback code.
3269 *
3270 * @param pNtStub The parent.
3271 * @param pNtVm The child.
3272 * @param fCallerChecks The result of any additional tests the caller made.
3273 * This is in order to avoid duplicating the failure
3274 * path code.
3275 */
3276static void supdrvNtProtectVerifyNewChildProtection(PSUPDRVNTPROTECT pNtStub, PSUPDRVNTPROTECT pNtVm, bool fCallerChecks)
3277{
3278 if ( fCallerChecks
3279 && pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubParent
3280 && pNtVm->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3281 && pNtVm->u.pParent == pNtStub
3282 && pNtStub->u.pChild == pNtVm)
3283 {
3284 /* Fine, reset the CSRSS hack (fixes ViRobot APT Shield 2.0 issue). */
3285 pNtVm->fFirstProcessCreateHandle = true;
3286 return;
3287 }
3288
3289 LogRel(("vboxdrv: Misdetected vm stub; hParentPid=%p hChildPid=%p\n", pNtStub->AvlCore.Key, pNtVm->AvlCore.Key));
3290 if (pNtStub->enmProcessKind != kSupDrvNtProtectKind_VmProcessConfirmed)
3291 supdrvNtProtectUnprotectDeadProcess(pNtVm->AvlCore.Key);
3292}
3293
3294
3295/**
3296 * Old style callback (since forever).
3297 *
3298 * @param hParentPid The parent PID.
3299 * @param hNewPid The PID of the new child.
3300 * @param fCreated TRUE if it's a creation notification,
3301 * FALSE if termination.
3302 * @remarks ASSUMES this arrives before the handle creation callback.
3303 */
3304static VOID __stdcall
3305supdrvNtProtectCallback_ProcessCreateNotify(HANDLE hParentPid, HANDLE hNewPid, BOOLEAN fCreated)
3306{
3307 /*
3308 * Is it a new process that needs protection?
3309 */
3310 if (fCreated)
3311 {
3312 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
3313 if (pNtStub)
3314 {
3315 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
3316 if (!pNtVm)
3317 {
3318 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hNewPid))
3319 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
3320 }
3321 else
3322 {
3323 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm, true);
3324 supdrvNtProtectRelease(pNtVm);
3325 }
3326 supdrvNtProtectRelease(pNtStub);
3327 }
3328 }
3329 /*
3330 * Process termination, do clean ups.
3331 */
3332 else
3333 {
3334 supdrvNtProtectUnprotectDeadProcess(hNewPid);
3335 supdrvNtErrorInfoCleanupProcess(hNewPid);
3336 }
3337}
3338
3339
3340/**
3341 * New style callback (Vista SP1+ / w2k8).
3342 *
3343 * @param pNewProcess The new process.
3344 * @param hNewPid The PID of the new process.
3345 * @param pInfo Process creation details. NULL if process
3346 * termination notification.
3347 * @remarks ASSUMES this arrives before the handle creation callback.
3348 */
3349static VOID __stdcall
3350supdrvNtProtectCallback_ProcessCreateNotifyEx(PEPROCESS pNewProcess, HANDLE hNewPid, PPS_CREATE_NOTIFY_INFO pInfo)
3351{
3352 RT_NOREF1(pNewProcess);
3353
3354 /*
3355 * Is it a new process that needs protection?
3356 */
3357 if (pInfo)
3358 {
3359 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(pInfo->CreatingThreadId.UniqueProcess);
3360
3361 Log(("vboxdrv/NewProcessEx: ctx=%04zx/%p pid=%04zx ppid=%04zx ctor=%04zx/%04zx rcNt=%#x %.*ls\n",
3362 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3363 hNewPid, pInfo->ParentProcessId,
3364 pInfo->CreatingThreadId.UniqueProcess, pInfo->CreatingThreadId.UniqueThread, pInfo->CreationStatus,
3365 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? (size_t)pInfo->ImageFileName->Length / 2 : 0,
3366 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? pInfo->ImageFileName->Buffer : NULL));
3367
3368 if (pNtStub)
3369 {
3370 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
3371 if (!pNtVm)
3372 {
3373 /* Parent must be creator. */
3374 if (pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId)
3375 {
3376 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, pInfo->ParentProcessId, hNewPid))
3377 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
3378 }
3379 }
3380 else
3381 {
3382 /* Parent must be creator (as above). */
3383 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm,
3384 pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId);
3385 supdrvNtProtectRelease(pNtVm);
3386 }
3387 supdrvNtProtectRelease(pNtStub);
3388 }
3389 }
3390 /*
3391 * Process termination, do clean ups.
3392 */
3393 else
3394 {
3395 supdrvNtProtectUnprotectDeadProcess(hNewPid);
3396 supdrvNtErrorInfoCleanupProcess(hNewPid);
3397 }
3398}
3399
3400/** @} */
3401
3402
3403/** @name Process Handle Callbacks.
3404 * @{ */
3405
3406/** Process rights that we allow for handles to stub and VM processes. */
3407# define SUPDRV_NT_ALLOW_PROCESS_RIGHTS \
3408 ( PROCESS_TERMINATE \
3409 | PROCESS_VM_READ \
3410 | PROCESS_QUERY_INFORMATION \
3411 | PROCESS_QUERY_LIMITED_INFORMATION \
3412 | PROCESS_SUSPEND_RESUME \
3413 | DELETE \
3414 | READ_CONTROL \
3415 | SYNCHRONIZE)
3416
3417/** Evil process rights. */
3418# define SUPDRV_NT_EVIL_PROCESS_RIGHTS \
3419 ( PROCESS_CREATE_THREAD \
3420 | PROCESS_SET_SESSIONID /*?*/ \
3421 | PROCESS_VM_OPERATION \
3422 | PROCESS_VM_WRITE \
3423 | PROCESS_DUP_HANDLE \
3424 | PROCESS_CREATE_PROCESS /*?*/ \
3425 | PROCESS_SET_QUOTA /*?*/ \
3426 | PROCESS_SET_INFORMATION \
3427 | PROCESS_SET_LIMITED_INFORMATION /*?*/ \
3428 | 0)
3429AssertCompile((SUPDRV_NT_ALLOW_PROCESS_RIGHTS & SUPDRV_NT_EVIL_PROCESS_RIGHTS) == 0);
3430
3431
3432static OB_PREOP_CALLBACK_STATUS __stdcall
3433supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
3434{
3435 Assert(pvUser == NULL); RT_NOREF1(pvUser);
3436 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3437 Assert(pOpInfo->ObjectType == *PsProcessType);
3438
3439 /*
3440 * Protected? Kludge required for NtOpenProcess calls comming in before
3441 * the create process hook triggers on Windows 8.1 (possibly others too).
3442 */
3443 HANDLE hObjPid = PsGetProcessId((PEPROCESS)pOpInfo->Object);
3444 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hObjPid);
3445 if (!pNtProtect)
3446 {
3447 HANDLE hParentPid = PsGetProcessInheritedFromUniqueProcessId((PEPROCESS)pOpInfo->Object);
3448 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
3449 if (pNtStub)
3450 {
3451 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hObjPid))
3452 {
3453 supdrvNtProtectProtectNewStubChild(pNtStub, hObjPid);
3454 pNtProtect = supdrvNtProtectLookup(hObjPid);
3455 }
3456 supdrvNtProtectRelease(pNtStub);
3457 }
3458 }
3459 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
3460 if (pNtProtect)
3461 {
3462 /*
3463 * Ok, it's a protected process. Strip rights as required or possible.
3464 */
3465 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
3466 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOW_PROCESS_RIGHTS;
3467
3468 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
3469 {
3470 /* Don't restrict the process accessing itself. */
3471 if ((PEPROCESS)pOpInfo->Object == PsGetCurrentProcess())
3472 {
3473 pOpInfo->CallContext = NULL; /* don't assert */
3474 pNtProtect->fFirstProcessCreateHandle = false;
3475
3476 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s\n",
3477 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3478 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3479 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3480 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3481 }
3482#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3483 /* Allow debuggers full access. */
3484 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
3485 {
3486 pOpInfo->CallContext = NULL; /* don't assert */
3487 pNtProtect->fFirstProcessCreateHandle = false;
3488
3489 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
3490 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3491 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3492 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3493 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3494 }
3495#endif
3496 else
3497 {
3498 ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->CreateHandleInformation.DesiredAccess;
3499
3500 /* Special case 1 on Vista, 7 & 8:
3501 The CreateProcess code passes the handle over to CSRSS.EXE
3502 and the code inBaseSrvCreateProcess will duplicate the
3503 handle with 0x1fffff as access mask. NtDuplicateObject will
3504 fail this call before it ever gets down here.
3505
3506 Special case 2 on 8.1:
3507 The CreateProcess code requires additional rights for
3508 something, we'll drop these in the stub code. */
3509 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3510 && pNtProtect->fFirstProcessCreateHandle
3511 && pOpInfo->KernelHandle == 0
3512 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess())
3513 && ExGetPreviousMode() != KernelMode)
3514 {
3515 if ( !pOpInfo->KernelHandle
3516 && fDesiredAccess == s_fCsrssStupidDesires)
3517 {
3518 if (g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3))
3519 fAllowedRights |= s_fCsrssStupidDesires;
3520 else
3521 fAllowedRights = fAllowedRights
3522 | PROCESS_VM_OPERATION
3523 | PROCESS_VM_WRITE
3524 | PROCESS_SET_INFORMATION
3525 | PROCESS_SET_LIMITED_INFORMATION
3526 | 0;
3527 pOpInfo->CallContext = NULL; /* don't assert this. */
3528 }
3529 pNtProtect->fFirstProcessCreateHandle = false;
3530 }
3531
3532 /* Special case 3 on 8.1:
3533 The interaction between the CreateProcess code and CSRSS.EXE
3534 has changed to the better with Windows 8.1. CSRSS.EXE no
3535 longer duplicates the process (thread too) handle, but opens
3536 it, thus allowing us to do our job. */
3537 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3)
3538 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3539 && pNtProtect->fCsrssFirstProcessCreateHandle
3540 && pOpInfo->KernelHandle == 0
3541 && ExGetPreviousMode() == UserMode
3542 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3543 {
3544 pNtProtect->fCsrssFirstProcessCreateHandle = false;
3545 if (fDesiredAccess == s_fCsrssStupidDesires)
3546 {
3547 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
3548 PROCESS_CREATE_PROCESS */
3549 fAllowedRights = fAllowedRights
3550 | PROCESS_VM_OPERATION
3551 | PROCESS_VM_WRITE
3552 | PROCESS_DUP_HANDLE /* Needed for CreateProcess/VBoxTestOGL. */
3553 | 0;
3554 pOpInfo->CallContext = NULL; /* don't assert this. */
3555 }
3556 }
3557
3558 /* Special case 4, Windows 7, Vista, possibly 8, but not 8.1:
3559 The Themes service requires PROCESS_DUP_HANDLE access to our
3560 process or we won't get any menus and dialogs will be half
3561 unreadable. This is _very_ unfortunate and more work will
3562 go into making this more secure. */
3563 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)
3564 && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
3565 && fDesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
3566 && pNtProtect->fThemesFirstProcessCreateHandle
3567 && pOpInfo->KernelHandle == 0
3568 && ExGetPreviousMode() == UserMode
3569 && supdrvNtProtectIsFrigginThemesService(pNtProtect, PsGetCurrentProcess()) )
3570 {
3571 pNtProtect->fThemesFirstProcessCreateHandle = true; /* Only once! */
3572 fAllowedRights |= PROCESS_DUP_HANDLE;
3573 pOpInfo->CallContext = NULL; /* don't assert this. */
3574 }
3575
3576 /* Special case 6a, Windows 10+: AudioDG.exe opens the process with the
3577 PROCESS_SET_LIMITED_INFORMATION right. It seems like it need it for
3578 some myserious and weirdly placed cpu set management of our process.
3579 I'd love to understand what that's all about...
3580 Currently playing safe and only grand this right, however limited, to
3581 audiodg.exe. */
3582 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
3583 && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
3584 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
3585 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
3586 )
3587 && pOpInfo->KernelHandle == 0
3588 && ExGetPreviousMode() == UserMode
3589 && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
3590 {
3591 fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
3592 pOpInfo->CallContext = NULL; /* don't assert this. */
3593 }
3594
3595 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p/pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
3596 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3597 fDesiredAccess, pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3598 fAllowedRights, fDesiredAccess & fAllowedRights,
3599 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode() ));
3600
3601 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
3602 }
3603 }
3604 else
3605 {
3606 /* Don't restrict the process accessing itself. */
3607 if ( (PEPROCESS)pOpInfo->Object == PsGetCurrentProcess()
3608 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pOpInfo->Object)
3609 {
3610 Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
3611 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3612 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3613 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3614 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3615 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3616 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3617 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3618
3619 pOpInfo->CallContext = NULL; /* don't assert */
3620 }
3621 else
3622 {
3623 ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess;
3624
3625 /* Special case 5 on Vista, 7 & 8:
3626 This is the CSRSS.EXE end of special case #1. */
3627 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
3628 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3629 && pNtProtect->cCsrssFirstProcessDuplicateHandle > 0
3630 && pOpInfo->KernelHandle == 0
3631 && fDesiredAccess == s_fCsrssStupidDesires
3632 && pNtProtect->hParentPid
3633 == PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess)
3634 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
3635 && ExGetPreviousMode() == UserMode
3636 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()))
3637 {
3638 if (ASMAtomicDecS32(&pNtProtect->cCsrssFirstProcessDuplicateHandle) >= 0)
3639 {
3640 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
3641 PROCESS_CREATE_PROCESS, PROCESS_DUP_HANDLE */
3642 fAllowedRights = fAllowedRights
3643 | PROCESS_VM_OPERATION
3644 | PROCESS_VM_WRITE
3645 | PROCESS_DUP_HANDLE /* Needed for launching VBoxTestOGL. */
3646 | 0;
3647 pOpInfo->CallContext = NULL; /* don't assert this. */
3648 }
3649 }
3650
3651 /* Special case 6b, Windows 10+: AudioDG.exe duplicates the handle it opened above. */
3652 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
3653 && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
3654 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
3655 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
3656 )
3657 && pOpInfo->KernelHandle == 0
3658 && ExGetPreviousMode() == UserMode
3659 && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
3660 {
3661 fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
3662 pOpInfo->CallContext = NULL; /* don't assert this. */
3663 }
3664
3665 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
3666 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3667 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3668 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3669 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3670 fDesiredAccess,
3671 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3672 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3673
3674 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
3675 }
3676 }
3677 supdrvNtProtectRelease(pNtProtect);
3678 }
3679
3680 return OB_PREOP_SUCCESS;
3681}
3682
3683
3684static VOID __stdcall
3685supdrvNtProtectCallback_ProcessHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
3686{
3687 Assert(pvUser == NULL); RT_NOREF1(pvUser);
3688 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3689 Assert(pOpInfo->ObjectType == *PsProcessType);
3690
3691 if ( pOpInfo->CallContext
3692 && NT_SUCCESS(pOpInfo->ReturnStatus))
3693 {
3694 ACCESS_MASK const fGrantedAccess = pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE
3695 ? pOpInfo->Parameters->CreateHandleInformation.GrantedAccess
3696 : pOpInfo->Parameters->DuplicateHandleInformation.GrantedAccess;
3697 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOW_PROCESS_RIGHTS
3698 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
3699 | PROCESS_UNKNOWN_4000 /* Seen set on win 8.1 */
3700 /*| PROCESS_UNKNOWN_8000 */ ) )
3701 || pOpInfo->KernelHandle,
3702 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
3703 fGrantedAccess, SUPDRV_NT_ALLOW_PROCESS_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOW_PROCESS_RIGHTS));
3704 }
3705}
3706
3707# undef SUPDRV_NT_ALLOW_PROCESS_RIGHTS
3708
3709/** @} */
3710
3711
3712/** @name Thread Handle Callbacks
3713 * @{ */
3714
3715/* From ntifs.h */
3716extern "C" NTKERNELAPI PEPROCESS __stdcall IoThreadToProcess(PETHREAD);
3717
3718/** Thread rights that we allow for handles to stub and VM processes. */
3719# define SUPDRV_NT_ALLOWED_THREAD_RIGHTS \
3720 ( THREAD_TERMINATE \
3721 | THREAD_GET_CONTEXT \
3722 | THREAD_QUERY_INFORMATION \
3723 | THREAD_QUERY_LIMITED_INFORMATION \
3724 | DELETE \
3725 | READ_CONTROL \
3726 | SYNCHRONIZE)
3727/** @todo consider THREAD_SET_LIMITED_INFORMATION & THREAD_RESUME */
3728
3729/** Evil thread rights.
3730 * @remarks THREAD_RESUME is not included as it seems to be forced upon us by
3731 * Windows 8.1, at least for some processes. We dont' actively
3732 * allow it though, just tollerate it when forced to. */
3733# define SUPDRV_NT_EVIL_THREAD_RIGHTS \
3734 ( THREAD_SUSPEND_RESUME \
3735 | THREAD_SET_CONTEXT \
3736 | THREAD_SET_INFORMATION \
3737 | THREAD_SET_LIMITED_INFORMATION /*?*/ \
3738 | THREAD_SET_THREAD_TOKEN /*?*/ \
3739 | THREAD_IMPERSONATE /*?*/ \
3740 | THREAD_DIRECT_IMPERSONATION /*?*/ \
3741 /*| THREAD_RESUME - see remarks. */ \
3742 | 0)
3743AssertCompile((SUPDRV_NT_EVIL_THREAD_RIGHTS & SUPDRV_NT_ALLOWED_THREAD_RIGHTS) == 0);
3744
3745
3746static OB_PREOP_CALLBACK_STATUS __stdcall
3747supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
3748{
3749 Assert(pvUser == NULL); RT_NOREF1(pvUser);
3750 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3751 Assert(pOpInfo->ObjectType == *PsThreadType);
3752
3753 PEPROCESS pProcess = IoThreadToProcess((PETHREAD)pOpInfo->Object);
3754 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(PsGetProcessId(pProcess));
3755 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
3756 if (pNtProtect)
3757 {
3758 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
3759 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOWED_THREAD_RIGHTS;
3760
3761 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
3762 {
3763 /* Don't restrict the process accessing its own threads. */
3764 if (pProcess == PsGetCurrentProcess())
3765 {
3766 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] self\n",
3767 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3768 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3769 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind));
3770 pOpInfo->CallContext = NULL; /* don't assert */
3771 pNtProtect->fFirstThreadCreateHandle = false;
3772 }
3773#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3774 /* Allow debuggers full access. */
3775 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
3776 {
3777 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
3778 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3779 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3780 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3781 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3782 pOpInfo->CallContext = NULL; /* don't assert */
3783 }
3784#endif
3785 else
3786 {
3787 /* Special case 1 on Vista, 7, 8:
3788 The CreateProcess code passes the handle over to CSRSS.EXE
3789 and the code inBaseSrvCreateProcess will duplicate the
3790 handle with 0x1fffff as access mask. NtDuplicateObject will
3791 fail this call before it ever gets down here. */
3792 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
3793 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3794 && pNtProtect->fFirstThreadCreateHandle
3795 && pOpInfo->KernelHandle == 0
3796 && ExGetPreviousMode() == UserMode
3797 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess()) )
3798 {
3799 if ( !pOpInfo->KernelHandle
3800 && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
3801 {
3802 fAllowedRights |= s_fCsrssStupidDesires;
3803 pOpInfo->CallContext = NULL; /* don't assert this. */
3804 }
3805 pNtProtect->fFirstThreadCreateHandle = false;
3806 }
3807
3808 /* Special case 2 on 8.1, possibly also Vista, 7, 8:
3809 When creating a process like VBoxTestOGL from the VM process,
3810 CSRSS.EXE will try talk to the calling thread and, it
3811 appears, impersonate it. We unfortunately need to allow
3812 this or there will be no 3D support. Typical DbgPrint:
3813 "SXS: BasepCreateActCtx() Calling csrss server failed. Status = 0xc00000a5" */
3814 SUPDRVNTPROTECTKIND enmProcessKind;
3815 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
3816 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
3817 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3818 && pOpInfo->KernelHandle == 0
3819 && ExGetPreviousMode() == UserMode
3820 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3821 {
3822 fAllowedRights |= THREAD_IMPERSONATE;
3823 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
3824 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
3825 pOpInfo->CallContext = NULL; /* don't assert this. */
3826 }
3827
3828 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
3829 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3830 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3831 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
3832 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess & fAllowedRights,
3833 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode()));
3834
3835 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
3836 }
3837 }
3838 else
3839 {
3840 /* Don't restrict the process accessing its own threads. */
3841 if ( pProcess == PsGetCurrentProcess()
3842 && (PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pProcess)
3843 {
3844 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] self\n",
3845 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3846 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3847 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3848 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3849 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3850 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3851 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3852 pOpInfo->CallContext = NULL; /* don't assert */
3853 }
3854 else
3855 {
3856 /* Special case 3 on Vista, 7, 8:
3857 This is the follow up to special case 1. */
3858 SUPDRVNTPROTECTKIND enmProcessKind;
3859 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
3860 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
3861 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3862 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
3863 && pOpInfo->KernelHandle == 0
3864 && ExGetPreviousMode() == UserMode
3865 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3866 {
3867 fAllowedRights |= THREAD_IMPERSONATE;
3868 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
3869 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
3870 pOpInfo->CallContext = NULL; /* don't assert this. */
3871 }
3872
3873 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s\n",
3874 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3875 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3876 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3877 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3878 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3879 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
3880 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess & fAllowedRights,
3881 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3882
3883 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
3884 }
3885 }
3886
3887 supdrvNtProtectRelease(pNtProtect);
3888 }
3889
3890 return OB_PREOP_SUCCESS;
3891}
3892
3893
3894static VOID __stdcall
3895supdrvNtProtectCallback_ThreadHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
3896{
3897 Assert(pvUser == NULL); RT_NOREF1(pvUser);
3898 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3899 Assert(pOpInfo->ObjectType == *PsThreadType);
3900
3901 if ( pOpInfo->CallContext
3902 && NT_SUCCESS(pOpInfo->ReturnStatus))
3903 {
3904 ACCESS_MASK const fGrantedAccess = pOpInfo->Parameters->CreateHandleInformation.GrantedAccess;
3905 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOWED_THREAD_RIGHTS
3906 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
3907 | THREAD_RESUME /* This seems to be force upon us too with 8.1. */
3908 ) )
3909 || pOpInfo->KernelHandle,
3910 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
3911 fGrantedAccess, SUPDRV_NT_ALLOWED_THREAD_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOWED_THREAD_RIGHTS));
3912 }
3913}
3914
3915# undef SUPDRV_NT_ALLOWED_THREAD_RIGHTS
3916
3917/** @} */
3918
3919
3920/**
3921 * Creates a new process protection structure.
3922 *
3923 * @returns VBox status code.
3924 * @param ppNtProtect Where to return the pointer to the structure
3925 * on success.
3926 * @param hPid The process ID of the process to protect.
3927 * @param enmProcessKind The kind of process we're protecting.
3928 * @param fLink Whether to link the structure into the tree.
3929 */
3930static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid, SUPDRVNTPROTECTKIND enmProcessKind, bool fLink)
3931{
3932 AssertReturn(g_hNtProtectLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
3933
3934 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)RTMemAllocZ(sizeof(*pNtProtect));
3935 if (!pNtProtect)
3936 return VERR_NO_MEMORY;
3937
3938 pNtProtect->AvlCore.Key = hPid;
3939 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC;
3940 pNtProtect->cRefs = 1;
3941 pNtProtect->enmProcessKind = enmProcessKind;
3942 pNtProtect->hParentPid = NULL;
3943 pNtProtect->hOpenTid = NULL;
3944 pNtProtect->hCsrssPid = NULL;
3945 pNtProtect->pCsrssProcess = NULL;
3946
3947 if (fLink)
3948 {
3949 RTSpinlockAcquire(g_hNtProtectLock);
3950 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtProtect->AvlCore);
3951 pNtProtect->fInTree = fSuccess;
3952 RTSpinlockRelease(g_hNtProtectLock);
3953
3954 if (!fSuccess)
3955 {
3956 /* Duplicate entry, fail. */
3957 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC_DEAD;
3958 LogRel(("supdrvNtProtectCreate: Duplicate (%#x).\n", pNtProtect->AvlCore.Key));
3959 RTMemFree(pNtProtect);
3960 return VERR_DUPLICATE;
3961 }
3962 }
3963
3964 *ppNtProtect = pNtProtect;
3965 return VINF_SUCCESS;
3966}
3967
3968
3969/**
3970 * Releases a reference to a NT protection structure.
3971 *
3972 * @param pNtProtect The NT protection structure.
3973 */
3974static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
3975{
3976 if (!pNtProtect)
3977 return;
3978 AssertReturnVoid(pNtProtect->u32Magic == SUPDRVNTPROTECT_MAGIC);
3979
3980 RTSpinlockAcquire(g_hNtProtectLock);
3981 uint32_t cRefs = ASMAtomicDecU32(&pNtProtect->cRefs);
3982 if (cRefs != 0)
3983 RTSpinlockRelease(g_hNtProtectLock);
3984 else
3985 {
3986 /*
3987 * That was the last reference. Remove it from the tree, invalidate it
3988 * and free the resources associated with it. Also, release any
3989 * child/parent references related to this protection structure.
3990 */
3991 ASMAtomicWriteU32(&pNtProtect->u32Magic, SUPDRVNTPROTECT_MAGIC_DEAD);
3992 if (pNtProtect->fInTree)
3993 {
3994 PSUPDRVNTPROTECT pRemoved = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pNtProtect->AvlCore.Key);
3995 Assert(pRemoved == pNtProtect); RT_NOREF_PV(pRemoved);
3996 pNtProtect->fInTree = false;
3997 }
3998
3999 PSUPDRVNTPROTECT pChild = NULL;
4000 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent)
4001 {
4002 pChild = pNtProtect->u.pChild;
4003 if (pChild)
4004 {
4005 pNtProtect->u.pChild = NULL;
4006 pChild->u.pParent = NULL;
4007 pChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4008 uint32_t cChildRefs = ASMAtomicDecU32(&pChild->cRefs);
4009 if (!cChildRefs)
4010 {
4011 Assert(pChild->fInTree);
4012 if (pChild->fInTree)
4013 {
4014 PSUPDRVNTPROTECT pRemovedChild = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pChild->AvlCore.Key);
4015 Assert(pRemovedChild == pChild); RT_NOREF_PV(pRemovedChild);
4016 pChild->fInTree = false;
4017 }
4018 }
4019 else
4020 pChild = NULL;
4021 }
4022 }
4023 else
4024 AssertRelease(pNtProtect->enmProcessKind != kSupDrvNtProtectKind_VmProcessUnconfirmed);
4025
4026 RTSpinlockRelease(g_hNtProtectLock);
4027
4028 if (pNtProtect->pCsrssProcess)
4029 {
4030 ObDereferenceObject(pNtProtect->pCsrssProcess);
4031 pNtProtect->pCsrssProcess = NULL;
4032 }
4033
4034 RTMemFree(pNtProtect);
4035 if (pChild)
4036 RTMemFree(pChild);
4037 }
4038}
4039
4040
4041/**
4042 * Looks up a PID in the NT protect tree.
4043 *
4044 * @returns Pointer to a NT protection structure (with a referenced) on success,
4045 * NULL if not found.
4046 * @param hPid The process ID.
4047 */
4048static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid)
4049{
4050 RTSpinlockAcquire(g_hNtProtectLock);
4051 PSUPDRVNTPROTECT pFound = (PSUPDRVNTPROTECT)RTAvlPVGet(&g_NtProtectTree, hPid);
4052 if (pFound)
4053 ASMAtomicIncU32(&pFound->cRefs);
4054 RTSpinlockRelease(g_hNtProtectLock);
4055 return pFound;
4056}
4057
4058
4059/**
4060 * Validates a few facts about the stub process when the VM process opens
4061 * vboxdrv.
4062 *
4063 * This makes sure the stub process is still around and that it has neither
4064 * debugger nor extra threads in it.
4065 *
4066 * @returns VBox status code.
4067 * @param pNtProtect The unconfirmed VM process currently trying to
4068 * open vboxdrv.
4069 * @param pErrInfo Additional error information.
4070 */
4071static int supdrvNtProtectVerifyStubForVmProcess(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
4072{
4073 /*
4074 * Grab a reference to the parent stub process.
4075 */
4076 SUPDRVNTPROTECTKIND enmStub = kSupDrvNtProtectKind_Invalid;
4077 PSUPDRVNTPROTECT pNtStub = NULL;
4078 RTSpinlockAcquire(g_hNtProtectLock);
4079 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4080 {
4081 pNtStub = pNtProtect->u.pParent; /* weak reference. */
4082 if (pNtStub)
4083 {
4084 enmStub = pNtStub->enmProcessKind;
4085 if (enmStub == kSupDrvNtProtectKind_StubParent)
4086 {
4087 uint32_t cRefs = ASMAtomicIncU32(&pNtStub->cRefs);
4088 Assert(cRefs > 0 && cRefs < 1024); RT_NOREF_PV(cRefs);
4089 }
4090 else
4091 pNtStub = NULL;
4092 }
4093 }
4094 RTSpinlockRelease(g_hNtProtectLock);
4095
4096 /*
4097 * We require the stub process to be present.
4098 */
4099 if (!pNtStub)
4100 return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND, "Missing stub process (enmStub=%d).", enmStub);
4101
4102 /*
4103 * Open the parent process and thread so we can check for debuggers and unwanted threads.
4104 */
4105 int rc;
4106 PEPROCESS pStubProcess;
4107 NTSTATUS rcNt = PsLookupProcessByProcessId(pNtStub->AvlCore.Key, &pStubProcess);
4108 if (NT_SUCCESS(rcNt))
4109 {
4110 HANDLE hStubProcess;
4111 rcNt = ObOpenObjectByPointer(pStubProcess, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
4112 0 /*DesiredAccess*/, *PsProcessType, KernelMode, &hStubProcess);
4113 if (NT_SUCCESS(rcNt))
4114 {
4115 PETHREAD pStubThread;
4116 rcNt = PsLookupThreadByThreadId(pNtStub->hOpenTid, &pStubThread);
4117 if (NT_SUCCESS(rcNt))
4118 {
4119 HANDLE hStubThread;
4120 rcNt = ObOpenObjectByPointer(pStubThread, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
4121 0 /*DesiredAccess*/, *PsThreadType, KernelMode, &hStubThread);
4122 if (NT_SUCCESS(rcNt))
4123 {
4124 /*
4125 * Do some simple sanity checking.
4126 */
4127 rc = supHardNtVpDebugger(hStubProcess, pErrInfo);
4128 if (RT_SUCCESS(rc))
4129 rc = supHardNtVpThread(hStubProcess, hStubThread, pErrInfo);
4130
4131 /* Clean up. */
4132 rcNt = NtClose(hStubThread); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
4133 }
4134 else
4135 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_OPEN_ERROR,
4136 "Error opening stub thread %p (tid %p, pid %p): %#x",
4137 pStubThread, pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
4138 }
4139 else
4140 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_NOT_FOUND,
4141 "Failed to locate thread %p in %p: %#x", pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
4142 rcNt = NtClose(hStubProcess); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
4143 }
4144 else
4145 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_OPEN_ERROR,
4146 "Error opening stub process %p (pid %p): %#x", pStubProcess, pNtStub->AvlCore.Key, rcNt);
4147 ObDereferenceObject(pStubProcess);
4148 }
4149 else
4150 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND,
4151 "Failed to locate stub process %p: %#x", pNtStub->AvlCore.Key, rcNt);
4152
4153 supdrvNtProtectRelease(pNtStub);
4154 return rc;
4155}
4156
4157
4158/**
4159 * Worker for supdrvNtProtectVerifyProcess that verifies the handles to a VM
4160 * process and its thread.
4161 *
4162 * @returns VBox status code.
4163 * @param pNtProtect The NT protect structure for getting information
4164 * about special processes.
4165 * @param pErrInfo Where to return additional error details.
4166 */
4167static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
4168{
4169 /*
4170 * What to protect.
4171 */
4172 PEPROCESS pProtectedProcess = PsGetCurrentProcess();
4173 HANDLE hProtectedPid = PsGetProcessId(pProtectedProcess);
4174 PETHREAD pProtectedThread = PsGetCurrentThread();
4175 AssertReturn(pNtProtect->AvlCore.Key == hProtectedPid, VERR_INTERNAL_ERROR_5);
4176
4177 /*
4178 * Take a snapshot of all the handles in the system.
4179 * Note! The 32 bytes on the size of to counteract the allocation header
4180 * that rtR0MemAllocEx slaps on everything.
4181 */
4182 uint32_t cbBuf = _256K - 32;
4183 uint8_t *pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
4184 ULONG cbNeeded = cbBuf;
4185 NTSTATUS rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
4186 if (!NT_SUCCESS(rcNt))
4187 {
4188 while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
4189 && cbNeeded > cbBuf
4190 && cbBuf <= 32U*_1M)
4191 {
4192 cbBuf = RT_ALIGN_32(cbNeeded + _4K, _64K) - 32;
4193 RTMemFree(pbBuf);
4194 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
4195 if (!pbBuf)
4196 return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Error allocating %zu bytes for querying handles.", cbBuf);
4197 rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
4198 }
4199 if (!NT_SUCCESS(rcNt))
4200 {
4201 RTMemFree(pbBuf);
4202 return RTErrInfoSetF(pErrInfo, RTErrConvertFromNtStatus(rcNt),
4203 "NtQuerySystemInformation/SystemExtendedHandleInformation failed: %#x\n", rcNt);
4204 }
4205 }
4206
4207 /*
4208 * Walk the information and look for handles to the two objects we're protecting.
4209 */
4210 int rc = VINF_SUCCESS;
4211# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4212 HANDLE idLastDebugger = (HANDLE)~(uintptr_t)0;
4213# endif
4214
4215 uint32_t cCsrssProcessHandles = 0;
4216 uint32_t cSystemProcessHandles = 0;
4217 uint32_t cEvilProcessHandles = 0;
4218 uint32_t cBenignProcessHandles = 0;
4219
4220 uint32_t cCsrssThreadHandles = 0;
4221 uint32_t cEvilThreadHandles = 0;
4222 uint32_t cBenignThreadHandles = 0;
4223
4224 SYSTEM_HANDLE_INFORMATION_EX const *pInfo = (SYSTEM_HANDLE_INFORMATION_EX const *)pbBuf;
4225 ULONG_PTR i = pInfo->NumberOfHandles;
4226 AssertRelease(RT_OFFSETOF(SYSTEM_HANDLE_INFORMATION_EX, Handles[i]) == cbNeeded);
4227 while (i-- > 0)
4228 {
4229 const char *pszType;
4230 SYSTEM_HANDLE_ENTRY_INFO_EX const *pHandleInfo = &pInfo->Handles[i];
4231 if (pHandleInfo->Object == pProtectedProcess)
4232 {
4233 /* Handles within the protected process are fine. */
4234 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_PROCESS_RIGHTS)
4235 || pHandleInfo->UniqueProcessId == hProtectedPid)
4236 {
4237 cBenignProcessHandles++;
4238 continue;
4239 }
4240
4241 /* CSRSS is allowed to have one evil process handle.
4242 See the special cases in the hook code. */
4243 if ( cCsrssProcessHandles < 1
4244 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
4245 {
4246 cCsrssProcessHandles++;
4247 continue;
4248 }
4249
4250 /* The system process is allowed having two open process handle in
4251 Windows 8.1 and later, and one in earlier. This is probably a
4252 little overly paranoid as I think we can safely trust the
4253 system process... */
4254 if ( cSystemProcessHandles < (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3) ? UINT32_C(2) : UINT32_C(1))
4255 && pHandleInfo->UniqueProcessId == PsGetProcessId(PsInitialSystemProcess))
4256 {
4257 cSystemProcessHandles++;
4258 continue;
4259 }
4260
4261 cEvilProcessHandles++;
4262 pszType = "process";
4263 }
4264 else if (pHandleInfo->Object == pProtectedThread)
4265 {
4266 /* Handles within the protected process is fine. */
4267 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_THREAD_RIGHTS)
4268 || pHandleInfo->UniqueProcessId == hProtectedPid)
4269 {
4270 cBenignThreadHandles++;
4271 continue;
4272 }
4273
4274 /* CSRSS is allowed to have one evil handle to the primary thread
4275 for LPC purposes. See the hook for special case. */
4276 if ( cCsrssThreadHandles < 1
4277 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
4278 {
4279 cCsrssThreadHandles++;
4280 continue;
4281 }
4282
4283 cEvilThreadHandles++;
4284 pszType = "thread";
4285 }
4286 else
4287 continue;
4288
4289# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4290 /* Ignore whitelisted debuggers. */
4291 if (pHandleInfo->UniqueProcessId == idLastDebugger)
4292 continue;
4293 PEPROCESS pDbgProc;
4294 NTSTATUS rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pDbgProc);
4295 if (NT_SUCCESS(rcNt))
4296 {
4297 bool fIsDebugger = supdrvNtProtectIsWhitelistedDebugger(pDbgProc);
4298 ObDereferenceObject(pDbgProc);
4299 if (fIsDebugger)
4300 {
4301 idLastDebugger = pHandleInfo->UniqueProcessId;
4302 continue;
4303 }
4304 }
4305# endif
4306
4307 /* Found evil handle. Currently ignoring on pre-Vista. */
4308# ifndef VBOX_WITH_VISTA_NO_SP
4309 if ( g_uNtVerCombined >= SUP_NT_VER_VISTA
4310# else
4311 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0)
4312# endif
4313 || g_pfnObRegisterCallbacks)
4314 {
4315 LogRel(("vboxdrv: Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s\n",
4316 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
4317 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType));
4318 rc = RTErrInfoAddF(pErrInfo, VERR_SUPDRV_HARDENING_EVIL_HANDLE,
4319 *pErrInfo->pszMsg
4320 ? "\nFound evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s"
4321 : "Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s",
4322 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
4323 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType);
4324
4325 /* Try add the process name. */
4326 PEPROCESS pOffendingProcess;
4327 rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pOffendingProcess);
4328 if (NT_SUCCESS(rcNt))
4329 {
4330 const char *pszName = (const char *)PsGetProcessImageFileName(pOffendingProcess);
4331 if (pszName && *pszName)
4332 rc = RTErrInfoAddF(pErrInfo, rc, " [%s]", pszName);
4333
4334 ObDereferenceObject(pOffendingProcess);
4335 }
4336 }
4337 }
4338
4339 RTMemFree(pbBuf);
4340 return rc;
4341}
4342
4343
4344/**
4345 * Checks if the current process checks out as a VM process stub.
4346 *
4347 * @returns VBox status code.
4348 * @param pNtProtect The NT protect structure. This is upgraded to a
4349 * final protection kind (state) on success.
4350 */
4351static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
4352{
4353 AssertReturn(PsGetProcessId(PsGetCurrentProcess()) == pNtProtect->AvlCore.Key, VERR_INTERNAL_ERROR_3);
4354
4355 /*
4356 * Do the verification. The handle restriction checks are only preformed
4357 * on VM processes.
4358 */
4359 int rc = VINF_SUCCESS;
4360 PSUPDRVNTERRORINFO pErrorInfo = (PSUPDRVNTERRORINFO)RTMemAllocZ(sizeof(*pErrorInfo));
4361 if (RT_SUCCESS(rc))
4362 {
4363 pErrorInfo->hProcessId = PsGetCurrentProcessId();
4364 pErrorInfo->hThreadId = PsGetCurrentThreadId();
4365 RTERRINFO ErrInfo;
4366 RTErrInfoInit(&ErrInfo, pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo));
4367
4368 if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
4369 rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect, &ErrInfo);
4370 if (RT_SUCCESS(rc))
4371 {
4372 rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY, 0 /*fFlags*/,
4373 NULL /*pcFixes*/, &ErrInfo);
4374 if (RT_SUCCESS(rc) && pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
4375 rc = supdrvNtProtectVerifyStubForVmProcess(pNtProtect, &ErrInfo);
4376 }
4377 }
4378 else
4379 rc = VERR_NO_MEMORY;
4380
4381 /*
4382 * Upgrade and return.
4383 */
4384 HANDLE hOpenTid = PsGetCurrentThreadId();
4385 RTSpinlockAcquire(g_hNtProtectLock);
4386
4387 /* Stub process verficiation is pretty much straight forward. */
4388 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
4389 {
4390 pNtProtect->enmProcessKind = RT_SUCCESS(rc) ? kSupDrvNtProtectKind_StubSpawning : kSupDrvNtProtectKind_StubDead;
4391 pNtProtect->hOpenTid = hOpenTid;
4392 }
4393 /* The VM process verification is a little bit more complicated
4394 because we need to drop the parent process reference as well. */
4395 else if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4396 {
4397 AssertRelease(pNtProtect->cRefs >= 2); /* Parent + Caller */
4398 PSUPDRVNTPROTECT pParent = pNtProtect->u.pParent;
4399 AssertRelease(pParent);
4400 AssertRelease(pParent->u.pParent == pNtProtect);
4401 AssertRelease(pParent->enmProcessKind == kSupDrvNtProtectKind_StubParent);
4402 pParent->u.pParent = NULL;
4403
4404 pNtProtect->u.pParent = NULL;
4405 ASMAtomicDecU32(&pNtProtect->cRefs);
4406
4407 if (RT_SUCCESS(rc))
4408 {
4409 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessConfirmed;
4410 pNtProtect->hOpenTid = hOpenTid;
4411 }
4412 else
4413 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4414 }
4415
4416 /* Since the stub and VM processes are only supposed to have one thread,
4417 we're not supposed to be subject to any races from within the processes.
4418
4419 There is a race between VM process verification and the stub process
4420 exiting, though. We require the stub process to be alive until the new
4421 VM process has made it thru the validation. So, when the stub
4422 terminates the notification handler will change the state of both stub
4423 and VM process to dead.
4424
4425 Also, I'm not entirely certain where the process
4426 termination notification is triggered from, so that can theorically
4427 create a race in both cases. */
4428 else
4429 {
4430 AssertReleaseMsg( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubDead
4431 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessDead,
4432 ("enmProcessKind=%d rc=%Rrc\n", pNtProtect->enmProcessKind, rc));
4433 if (RT_SUCCESS(rc))
4434 rc = VERR_INVALID_STATE; /* There should be no races here. */
4435 }
4436
4437 RTSpinlockRelease(g_hNtProtectLock);
4438
4439 /*
4440 * Free error info on success, keep it on failure.
4441 */
4442 if (RT_SUCCESS(rc))
4443 RTMemFree(pErrorInfo);
4444 else if (pErrorInfo)
4445 {
4446 pErrorInfo->cchErrorInfo = (uint32_t)strlen(pErrorInfo->szErrorInfo);
4447 if (!pErrorInfo->cchErrorInfo)
4448 pErrorInfo->cchErrorInfo = (uint32_t)RTStrPrintf(pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo),
4449 "supdrvNtProtectVerifyProcess: rc=%d", rc);
4450 RTLogWriteDebugger(pErrorInfo->szErrorInfo, pErrorInfo->cchErrorInfo);
4451
4452 int rc2 = RTSemMutexRequest(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
4453 if (RT_SUCCESS(rc2))
4454 {
4455 pErrorInfo->uCreatedMsTs = RTTimeMilliTS();
4456
4457 /* Free old entries. */
4458 PSUPDRVNTERRORINFO pCur;
4459 while ( (pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL
4460 && (int64_t)(pErrorInfo->uCreatedMsTs - pCur->uCreatedMsTs) > 60000 /*60sec*/)
4461 {
4462 RTListNodeRemove(&pCur->ListEntry);
4463 RTMemFree(pCur);
4464 }
4465
4466 /* Insert our new entry. */
4467 RTListAppend(&g_ErrorInfoHead, &pErrorInfo->ListEntry);
4468
4469 RTSemMutexRelease(g_hErrorInfoLock);
4470 }
4471 else
4472 RTMemFree(pErrorInfo);
4473 }
4474
4475 return rc;
4476}
4477
4478
4479# ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
4480
4481/**
4482 * Checks if the current process is being debugged.
4483 * @return @c true if debugged, @c false if not.
4484 */
4485static bool supdrvNtIsDebuggerAttached(void)
4486{
4487 return PsIsProcessBeingDebugged(PsGetCurrentProcess()) != FALSE;
4488}
4489
4490# endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
4491
4492
4493/**
4494 * Terminates the hardening bits.
4495 */
4496static void supdrvNtProtectTerm(void)
4497{
4498 /*
4499 * Stop intercepting process and thread handle creation calls.
4500 */
4501 if (g_pvObCallbacksCookie)
4502 {
4503 g_pfnObUnRegisterCallbacks(g_pvObCallbacksCookie);
4504 g_pvObCallbacksCookie = NULL;
4505 }
4506
4507 /*
4508 * Stop intercepting process creation and termination notifications.
4509 */
4510 NTSTATUS rcNt;
4511 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
4512 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
4513 else
4514 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
4515 AssertMsg(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt));
4516
4517 Assert(g_NtProtectTree == NULL);
4518
4519 /*
4520 * Clean up globals.
4521 */
4522 RTSpinlockDestroy(g_hNtProtectLock);
4523 g_NtProtectTree = NIL_RTSPINLOCK;
4524
4525 RTSemMutexDestroy(g_hErrorInfoLock);
4526 g_hErrorInfoLock = NIL_RTSEMMUTEX;
4527
4528 PSUPDRVNTERRORINFO pCur;
4529 while ((pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL)
4530 {
4531 RTListNodeRemove(&pCur->ListEntry);
4532 RTMemFree(pCur);
4533 }
4534
4535 supHardenedWinTermImageVerifier();
4536}
4537
4538# ifdef RT_ARCH_X86
4539DECLASM(void) supdrvNtQueryVirtualMemory_0xAF(void);
4540DECLASM(void) supdrvNtQueryVirtualMemory_0xB0(void);
4541DECLASM(void) supdrvNtQueryVirtualMemory_0xB1(void);
4542DECLASM(void) supdrvNtQueryVirtualMemory_0xB2(void);
4543DECLASM(void) supdrvNtQueryVirtualMemory_0xB3(void);
4544DECLASM(void) supdrvNtQueryVirtualMemory_0xB4(void);
4545DECLASM(void) supdrvNtQueryVirtualMemory_0xB5(void);
4546DECLASM(void) supdrvNtQueryVirtualMemory_0xB6(void);
4547DECLASM(void) supdrvNtQueryVirtualMemory_0xB7(void);
4548DECLASM(void) supdrvNtQueryVirtualMemory_0xB8(void);
4549DECLASM(void) supdrvNtQueryVirtualMemory_0xB9(void);
4550DECLASM(void) supdrvNtQueryVirtualMemory_0xBA(void);
4551DECLASM(void) supdrvNtQueryVirtualMemory_0xBB(void);
4552DECLASM(void) supdrvNtQueryVirtualMemory_0xBC(void);
4553DECLASM(void) supdrvNtQueryVirtualMemory_0xBD(void);
4554DECLASM(void) supdrvNtQueryVirtualMemory_0xBE(void);
4555# elif defined(RT_ARCH_AMD64)
4556DECLASM(void) supdrvNtQueryVirtualMemory_0x1F(void);
4557DECLASM(void) supdrvNtQueryVirtualMemory_0x20(void);
4558DECLASM(void) supdrvNtQueryVirtualMemory_0x21(void);
4559DECLASM(void) supdrvNtQueryVirtualMemory_0x22(void);
4560DECLASM(void) supdrvNtQueryVirtualMemory_0x23(void);
4561extern "C" NTSYSAPI NTSTATUS NTAPI ZwRequestWaitReplyPort(HANDLE, PVOID, PVOID);
4562# endif
4563
4564
4565/**
4566 * Initalizes the hardening bits.
4567 *
4568 * @returns NT status code.
4569 */
4570static NTSTATUS supdrvNtProtectInit(void)
4571{
4572 /*
4573 * Initialize the globals.
4574 */
4575
4576 /* The NT version. */
4577 ULONG uMajor, uMinor, uBuild;
4578 PsGetVersion(&uMajor, &uMinor, &uBuild, NULL);
4579 g_uNtVerCombined = SUP_MAKE_NT_VER_COMBINED(uMajor, uMinor, uBuild, 0, 0);
4580
4581 /* Resolve methods we want but isn't available everywhere. */
4582 UNICODE_STRING RoutineName;
4583
4584 RtlInitUnicodeString(&RoutineName, L"ObGetObjectType");
4585 g_pfnObGetObjectType = (PFNOBGETOBJECTTYPE)MmGetSystemRoutineAddress(&RoutineName);
4586
4587 RtlInitUnicodeString(&RoutineName, L"ObRegisterCallbacks");
4588 g_pfnObRegisterCallbacks = (PFNOBREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
4589
4590 RtlInitUnicodeString(&RoutineName, L"ObUnRegisterCallbacks");
4591 g_pfnObUnRegisterCallbacks = (PFNOBUNREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
4592
4593 RtlInitUnicodeString(&RoutineName, L"PsSetCreateProcessNotifyRoutineEx");
4594 g_pfnPsSetCreateProcessNotifyRoutineEx = (PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)MmGetSystemRoutineAddress(&RoutineName);
4595
4596 RtlInitUnicodeString(&RoutineName, L"PsReferenceProcessFilePointer");
4597 g_pfnPsReferenceProcessFilePointer = (PFNPSREFERENCEPROCESSFILEPOINTER)MmGetSystemRoutineAddress(&RoutineName);
4598
4599 RtlInitUnicodeString(&RoutineName, L"PsIsProtectedProcessLight");
4600 g_pfnPsIsProtectedProcessLight = (PFNPSISPROTECTEDPROCESSLIGHT)MmGetSystemRoutineAddress(&RoutineName);
4601
4602 RtlInitUnicodeString(&RoutineName, L"ZwAlpcCreatePort");
4603 g_pfnZwAlpcCreatePort = (PFNZWALPCCREATEPORT)MmGetSystemRoutineAddress(&RoutineName);
4604
4605 RtlInitUnicodeString(&RoutineName, L"ZwQueryVirtualMemory"); /* Yes, using Zw version here. */
4606 g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)MmGetSystemRoutineAddress(&RoutineName);
4607 if (!g_pfnNtQueryVirtualMemory && g_uNtVerCombined < SUP_NT_VER_VISTA)
4608 {
4609 /* XP & W2K3 doesn't have this function exported, so we've cooked up a
4610 few alternative in the assembly helper file that uses the code in
4611 ZwReadFile with a different eax value. We figure the syscall number
4612 by inspecting ZwQueryVolumeInformationFile as it's the next number. */
4613# ifdef RT_ARCH_X86
4614 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwQueryVolumeInformationFile;
4615 if (*pbCode == 0xb8) /* mov eax, dword */
4616 switch (*(uint32_t const *)&pbCode[1])
4617 {
4618 case 0xb0: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xAF; break; /* just in case */
4619 case 0xb1: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB0; break; /* just in case */
4620 case 0xb2: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB1; break; /* just in case */
4621 case 0xb3: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* XP SP3 */
4622 case 0xb4: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* just in case */
4623 case 0xb5: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB3; break; /* just in case */
4624 case 0xb6: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB4; break; /* just in case */
4625 case 0xb7: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB5; break; /* just in case */
4626 case 0xb8: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB6; break; /* just in case */
4627 case 0xb9: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB7; break; /* just in case */
4628 case 0xba: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB8; break; /* just in case */
4629 case 0xbb: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBA; break; /* W2K3 R2 SP2 */
4630 case 0xbc: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBB; break; /* just in case */
4631 case 0xbd: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBC; break; /* just in case */
4632 case 0xbe: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBD; break; /* just in case */
4633 case 0xbf: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBE; break; /* just in case */
4634 }
4635# elif defined(RT_ARCH_AMD64)
4636 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwRequestWaitReplyPort;
4637 if ( pbCode[ 0] == 0x48 /* mov rax, rsp */
4638 && pbCode[ 1] == 0x8b
4639 && pbCode[ 2] == 0xc4
4640 && pbCode[ 3] == 0xfa /* cli */
4641 && pbCode[ 4] == 0x48 /* sub rsp, 10h */
4642 && pbCode[ 5] == 0x83
4643 && pbCode[ 6] == 0xec
4644 && pbCode[ 7] == 0x10
4645 && pbCode[ 8] == 0x50 /* push rax */
4646 && pbCode[ 9] == 0x9c /* pushfq */
4647 && pbCode[10] == 0x6a /* push 10 */
4648 && pbCode[11] == 0x10
4649 && pbCode[12] == 0x48 /* lea rax, [nt!KiServiceLinkage] */
4650 && pbCode[13] == 0x8d
4651 && pbCode[14] == 0x05
4652 && pbCode[19] == 0x50 /* push rax */
4653 && pbCode[20] == 0xb8 /* mov eax,1fh <- the syscall no. */
4654 /*&& pbCode[21] == 0x1f*/
4655 && pbCode[22] == 0x00
4656 && pbCode[23] == 0x00
4657 && pbCode[24] == 0x00
4658 && pbCode[25] == 0xe9 /* jmp KiServiceInternal */
4659 )
4660 {
4661 uint8_t const *pbKiServiceInternal = &pbCode[30] + *(int32_t const *)&pbCode[26];
4662 uint8_t const *pbKiServiceLinkage = &pbCode[19] + *(int32_t const *)&pbCode[15];
4663 if (*pbKiServiceLinkage == 0xc3)
4664 {
4665 g_pfnKiServiceInternal = (PFNRT)pbKiServiceInternal;
4666 g_pfnKiServiceLinkage = (PFNRT)pbKiServiceLinkage;
4667 switch (pbCode[21])
4668 {
4669 case 0x1e: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x1F; break;
4670 case 0x1f: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x20; break;
4671 case 0x20: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x21; break;
4672 case 0x21: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x22; break;
4673 case 0x22: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x23; break;
4674 }
4675 }
4676 }
4677# endif
4678 }
4679 if (!g_pfnNtQueryVirtualMemory)
4680 {
4681 LogRel(("vboxdrv: Cannot locate ZwQueryVirtualMemory in ntoskrnl, nor were we able to cook up a replacement.\n"));
4682 return STATUS_PROCEDURE_NOT_FOUND;
4683 }
4684
4685# ifdef VBOX_STRICT
4686 if ( g_uNtVerCombined >= SUP_NT_VER_W70
4687 && ( g_pfnObGetObjectType == NULL
4688 || g_pfnZwAlpcCreatePort == NULL) )
4689 {
4690 LogRel(("vboxdrv: g_pfnObGetObjectType=%p g_pfnZwAlpcCreatePort=%p.\n", g_pfnObGetObjectType, g_pfnZwAlpcCreatePort));
4691 return STATUS_PROCEDURE_NOT_FOUND;
4692 }
4693# endif
4694
4695 /* LPC object type. */
4696 g_pAlpcPortObjectType1 = *LpcPortObjectType;
4697
4698 /* The spinlock protecting our structures. */
4699 int rc = RTSpinlockCreate(&g_hNtProtectLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "NtProtectLock");
4700 if (RT_FAILURE(rc))
4701 return VBoxDrvNtErr2NtStatus(rc);
4702 g_NtProtectTree = NULL;
4703
4704 NTSTATUS rcNt;
4705
4706 /* The mutex protecting the error information. */
4707 RTListInit(&g_ErrorInfoHead);
4708 rc = RTSemMutexCreate(&g_hErrorInfoLock);
4709 if (RT_SUCCESS(rc))
4710 {
4711 /* Image stuff + certificates. */
4712 rc = supHardenedWinInitImageVerifier(NULL);
4713 if (RT_SUCCESS(rc))
4714 {
4715 /*
4716 * Intercept process creation and termination.
4717 */
4718 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
4719 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
4720 else
4721 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
4722 if (NT_SUCCESS(rcNt))
4723 {
4724 /*
4725 * Intercept process and thread handle creation calls.
4726 * The preferred method is only available on Vista SP1+.
4727 */
4728 if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
4729 {
4730 static OB_OPERATION_REGISTRATION s_aObOperations[] =
4731 {
4732 {
4733 0, /* PsProcessType - imported, need runtime init, better do it explicitly. */
4734 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
4735 supdrvNtProtectCallback_ProcessHandlePre,
4736 supdrvNtProtectCallback_ProcessHandlePost,
4737 },
4738 {
4739 0, /* PsThreadType - imported, need runtime init, better do it explicitly. */
4740 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
4741 supdrvNtProtectCallback_ThreadHandlePre,
4742 supdrvNtProtectCallback_ThreadHandlePost,
4743 },
4744 };
4745 s_aObOperations[0].ObjectType = PsProcessType;
4746 s_aObOperations[1].ObjectType = PsThreadType;
4747
4748 static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
4749 {
4750 /* .Version = */ OB_FLT_REGISTRATION_VERSION,
4751 /* .OperationRegistrationCount = */ RT_ELEMENTS(s_aObOperations),
4752 /* .Altitude.Length = */ 0,
4753 /* .Altitude.MaximumLength = */ 0,
4754 /* .Altitude.Buffer = */ NULL,
4755 /* .RegistrationContext = */ NULL,
4756 /* .OperationRegistration = */ &s_aObOperations[0]
4757 };
4758 static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
4759 {
4760 L"48596.98940", L"46935.19485", L"49739.39704", L"40334.74976",
4761 L"66667.98940", L"69888.19485", L"69889.39704", L"60364.74976",
4762 L"85780.98940", L"88978.19485", L"89939.39704", L"80320.74976",
4763 L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
4764 };
4765
4766 rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
4767 for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
4768 {
4769 s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
4770 s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
4771 s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
4772
4773 rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
4774 if (NT_SUCCESS(rcNt))
4775 {
4776 /*
4777 * Happy ending.
4778 */
4779 return STATUS_SUCCESS;
4780 }
4781 }
4782 LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
4783 g_pvObCallbacksCookie = NULL;
4784 }
4785 else
4786 {
4787 /*
4788 * For the time being, we do not implement extra process
4789 * protection on pre-Vista-SP1 systems as they are lacking
4790 * necessary KPIs. XP is end of life, we do not wish to
4791 * spend more time on it, so we don't put up a fuss there.
4792 * Vista users without SP1 can install SP1 (or later), darn it,
4793 * so refuse to load.
4794 */
4795 /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
4796 * stuff to a couple of object types. */
4797# ifndef VBOX_WITH_VISTA_NO_SP
4798 if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
4799# else
4800 if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
4801# endif
4802 {
4803 DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
4804 rcNt = STATUS_SXS_VERSION_CONFLICT;
4805 }
4806 else
4807 {
4808 Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
4809 return rcNt = STATUS_SUCCESS;
4810 }
4811 g_pvObCallbacksCookie = NULL;
4812 }
4813
4814 /*
4815 * Drop process create/term notifications.
4816 */
4817 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
4818 g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
4819 else
4820 PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
4821 }
4822 else
4823 LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
4824 g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
4825 supHardenedWinTermImageVerifier();
4826 }
4827 else
4828 rcNt = VBoxDrvNtErr2NtStatus(rc);
4829
4830 RTSemMutexDestroy(g_hErrorInfoLock);
4831 g_hErrorInfoLock = NIL_RTSEMMUTEX;
4832 }
4833 else
4834 rcNt = VBoxDrvNtErr2NtStatus(rc);
4835
4836 RTSpinlockDestroy(g_hNtProtectLock);
4837 g_NtProtectTree = NIL_RTSPINLOCK;
4838 return rcNt;
4839}
4840
4841#endif /* VBOX_WITH_HARDENING */
4842
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use