VirtualBox

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

Last change on this file since 57303 was 57303, checked in by vboxsync, 10 years ago

SUPDrv-win.cpp: Workaround for AudioDG.exe on windows 10 wanting to do some new cpu set management for us, not sure what it is or what I think of it. We need audio though, so allow it for now. Also modified the SUPDRVNTPROTECT handling to make sure we don't try remove structures not in the tree, in case we fail early before it's inserted. Finally, shut up a signed comparisons warning.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette