VirtualBox

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

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

SUPDrv: nits

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

© 2023 Oracle
ContactPrivacy policyTerms of Use