VirtualBox

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

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

HostDrivers/Support: add and use supdrvOSAreCpusOfflinedOnSuspend(). FreeBSD, Darwin, Solaris need verification.

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

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