VirtualBox

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

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

SUPDrv-win.cpp: Reverted r98598.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 178.7 KB
Line 
1/* $Id: SUPDrv-win.cpp 54502 2015-02-25 15:59:12Z 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 hardware TSC has been synchronized by the OS.
1659 */
1660bool VBOXCALL supdrvOSAreTscDeltasInSync(void)
1661{
1662 /* If IPRT didn't find KeIpiGenericCall we pretend windows(, the firmware,
1663 or whoever) always configures TSCs perfectly. */
1664 return !RTMpOnPairIsConcurrentExecSupported();
1665}
1666
1667
1668#define MY_SystemLoadGdiDriverInSystemSpaceInformation 54
1669#define MY_SystemUnloadGdiDriverInformation 27
1670
1671typedef struct MYSYSTEMGDIDRIVERINFO
1672{
1673 UNICODE_STRING Name; /**< In: image file name. */
1674 PVOID ImageAddress; /**< Out: the load address. */
1675 PVOID SectionPointer; /**< Out: section object. */
1676 PVOID EntryPointer; /**< Out: entry point address. */
1677 PVOID ExportSectionPointer; /**< Out: export directory/section. */
1678 ULONG ImageLength; /**< Out: SizeOfImage. */
1679} MYSYSTEMGDIDRIVERINFO;
1680
1681extern "C" __declspec(dllimport) NTSTATUS NTAPI ZwSetSystemInformation(ULONG, PVOID, ULONG);
1682
1683int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1684{
1685 pImage->pvNtSectionObj = NULL;
1686 pImage->hMemLock = NIL_RTR0MEMOBJ;
1687
1688#ifdef VBOX_WITHOUT_NATIVE_R0_LOADER
1689# ifndef RT_ARCH_X86
1690# error "VBOX_WITHOUT_NATIVE_R0_LOADER is only safe on x86."
1691# endif
1692 NOREF(pDevExt); NOREF(pszFilename); NOREF(pImage);
1693 return VERR_NOT_SUPPORTED;
1694
1695#else
1696 /*
1697 * Convert the filename from DOS UTF-8 to NT UTF-16.
1698 */
1699 size_t cwcFilename;
1700 int rc = RTStrCalcUtf16LenEx(pszFilename, RTSTR_MAX, &cwcFilename);
1701 if (RT_FAILURE(rc))
1702 return rc;
1703
1704 PRTUTF16 pwcsFilename = (PRTUTF16)RTMemTmpAlloc((4 + cwcFilename + 1) * sizeof(RTUTF16));
1705 if (!pwcsFilename)
1706 return VERR_NO_TMP_MEMORY;
1707
1708 pwcsFilename[0] = '\\';
1709 pwcsFilename[1] = '?';
1710 pwcsFilename[2] = '?';
1711 pwcsFilename[3] = '\\';
1712 PRTUTF16 pwcsTmp = &pwcsFilename[4];
1713 rc = RTStrToUtf16Ex(pszFilename, RTSTR_MAX, &pwcsTmp, cwcFilename + 1, NULL);
1714 if (RT_SUCCESS(rc))
1715 {
1716 /*
1717 * Try load it.
1718 */
1719 MYSYSTEMGDIDRIVERINFO Info;
1720 RtlInitUnicodeString(&Info.Name, pwcsFilename);
1721 Info.ImageAddress = NULL;
1722 Info.SectionPointer = NULL;
1723 Info.EntryPointer = NULL;
1724 Info.ExportSectionPointer = NULL;
1725 Info.ImageLength = 0;
1726
1727 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemLoadGdiDriverInSystemSpaceInformation, &Info, sizeof(Info));
1728 if (NT_SUCCESS(rcNt))
1729 {
1730 pImage->pvImage = Info.ImageAddress;
1731 pImage->pvNtSectionObj = Info.SectionPointer;
1732 Log(("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ls'\n",
1733 Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer));
1734# ifdef DEBUG_bird
1735 SUPR0Printf("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ws'\n",
1736 Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer);
1737# endif
1738 if (pImage->cbImageBits == Info.ImageLength)
1739 {
1740 /*
1741 * Lock down the entire image, just to be on the safe side.
1742 */
1743 rc = RTR0MemObjLockKernel(&pImage->hMemLock, pImage->pvImage, pImage->cbImageBits, RTMEM_PROT_READ);
1744 if (RT_FAILURE(rc))
1745 {
1746 pImage->hMemLock = NIL_RTR0MEMOBJ;
1747 supdrvOSLdrUnload(pDevExt, pImage);
1748 }
1749 }
1750 else
1751 {
1752 supdrvOSLdrUnload(pDevExt, pImage);
1753 rc = VERR_LDR_MISMATCH_NATIVE;
1754 }
1755 }
1756 else
1757 {
1758 Log(("rcNt=%#x '%ls'\n", rcNt, pwcsFilename));
1759 SUPR0Printf("VBoxDrv: rcNt=%x '%ws'\n", rcNt, pwcsFilename);
1760 switch (rcNt)
1761 {
1762 case /* 0xc0000003 */ STATUS_INVALID_INFO_CLASS:
1763# ifdef RT_ARCH_AMD64
1764 /* Unwind will crash and BSOD, so no fallback here! */
1765 rc = VERR_NOT_IMPLEMENTED;
1766# else
1767 /*
1768 * Use the old way of loading the modules.
1769 *
1770 * Note! We do *NOT* try class 26 because it will probably
1771 * not work correctly on terminal servers and such.
1772 */
1773 rc = VERR_NOT_SUPPORTED;
1774# endif
1775 break;
1776 case /* 0xc0000034 */ STATUS_OBJECT_NAME_NOT_FOUND:
1777 rc = VERR_MODULE_NOT_FOUND;
1778 break;
1779 case /* 0xC0000263 */ STATUS_DRIVER_ENTRYPOINT_NOT_FOUND:
1780 rc = VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND;
1781 break;
1782 case /* 0xC0000428 */ STATUS_INVALID_IMAGE_HASH:
1783 rc = VERR_LDR_IMAGE_HASH;
1784 break;
1785 case /* 0xC000010E */ STATUS_IMAGE_ALREADY_LOADED:
1786 Log(("WARNING: see @bugref{4853} for cause of this failure on Windows 7 x64\n"));
1787 rc = VERR_ALREADY_LOADED;
1788 break;
1789 default:
1790 rc = VERR_LDR_GENERAL_FAILURE;
1791 break;
1792 }
1793
1794 pImage->pvNtSectionObj = NULL;
1795 }
1796 }
1797
1798 RTMemTmpFree(pwcsFilename);
1799 NOREF(pDevExt);
1800 return rc;
1801#endif
1802}
1803
1804
1805void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1806{
1807 NOREF(pDevExt); NOREF(pImage);
1808}
1809
1810
1811int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
1812{
1813 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
1814 return VINF_SUCCESS;
1815}
1816
1817
1818/**
1819 * memcmp + log.
1820 *
1821 * @returns Same as memcmp.
1822 * @param pImage The image.
1823 * @param pbImageBits The image bits ring-3 uploads.
1824 * @param uRva The RVA to start comparing at.
1825 * @param cb The number of bytes to compare.
1826 */
1827static int supdrvNtCompare(PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, uint32_t uRva, uint32_t cb)
1828{
1829 int iDiff = memcmp((uint8_t const *)pImage->pvImage + uRva, pbImageBits + uRva, cb);
1830 if (iDiff)
1831 {
1832 uint32_t cbLeft = cb;
1833 const uint8_t *pbNativeBits = (const uint8_t *)pImage->pvImage;
1834 for (size_t off = uRva; cbLeft > 0; off++, cbLeft--)
1835 if (pbNativeBits[off] != pbImageBits[off])
1836 {
1837 char szBytes[128];
1838 RTStrPrintf(szBytes, sizeof(szBytes), "native: %.*Rhxs our: %.*Rhxs",
1839 RT_MIN(12, cbLeft), &pbNativeBits[off],
1840 RT_MIN(12, cbLeft), &pbImageBits[off]);
1841 SUPR0Printf("VBoxDrv: Mismatch at %#x of %s: %s\n", off, pImage->szName, szBytes);
1842 break;
1843 }
1844 }
1845 return iDiff;
1846}
1847
1848int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
1849{
1850 NOREF(pDevExt); NOREF(pReq);
1851 if (pImage->pvNtSectionObj)
1852 {
1853 /*
1854 * Usually, the entire image matches exactly.
1855 */
1856 if (!memcmp(pImage->pvImage, pbImageBits, pImage->cbImageBits))
1857 return VINF_SUCCESS;
1858
1859 /*
1860 * However, on Windows Server 2003 (sp2 x86) both import thunk tables
1861 * are fixed up and we typically get a mismatch in the INIT section.
1862 *
1863 * So, lets see if everything matches when excluding the
1864 * OriginalFirstThunk tables. To make life simpler, set the max number
1865 * of imports to 16 and just record and sort the locations that needs
1866 * to be excluded from the comparison.
1867 */
1868 IMAGE_NT_HEADERS const *pNtHdrs;
1869 pNtHdrs = (IMAGE_NT_HEADERS const *)(pbImageBits
1870 + ( *(uint16_t *)pbImageBits == IMAGE_DOS_SIGNATURE
1871 ? ((IMAGE_DOS_HEADER const *)pbImageBits)->e_lfanew
1872 : 0));
1873 if ( pNtHdrs->Signature == IMAGE_NT_SIGNATURE
1874 && pNtHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
1875 && pNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT
1876 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR)
1877 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress > sizeof(IMAGE_NT_HEADERS)
1878 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress < pImage->cbImageBits
1879 )
1880 {
1881 struct MyRegion
1882 {
1883 uint32_t uRva;
1884 uint32_t cb;
1885 } aExcludeRgns[16];
1886 unsigned cExcludeRgns = 0;
1887 uint32_t cImpsLeft = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
1888 / sizeof(IMAGE_IMPORT_DESCRIPTOR);
1889 IMAGE_IMPORT_DESCRIPTOR const *pImp;
1890 pImp = (IMAGE_IMPORT_DESCRIPTOR const *)(pbImageBits
1891 + pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
1892 while ( cImpsLeft-- > 0
1893 && cExcludeRgns < RT_ELEMENTS(aExcludeRgns))
1894 {
1895 uint32_t uRvaThunk = pImp->OriginalFirstThunk;
1896 if ( uRvaThunk > sizeof(IMAGE_NT_HEADERS)
1897 && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA)
1898 && uRvaThunk != pImp->FirstThunk)
1899 {
1900 /* Find the size of the thunk table. */
1901 IMAGE_THUNK_DATA const *paThunk = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk);
1902 uint32_t cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA);
1903 uint32_t cThunks = 0;
1904 while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
1905 cThunks++;
1906
1907 /* Ordered table insert. */
1908 unsigned i = 0;
1909 for (; i < cExcludeRgns; i++)
1910 if (uRvaThunk < aExcludeRgns[i].uRva)
1911 break;
1912 if (i != cExcludeRgns)
1913 memmove(&aExcludeRgns[i + 1], &aExcludeRgns[i], (cExcludeRgns - i) * sizeof(aExcludeRgns[0]));
1914 aExcludeRgns[i].uRva = uRvaThunk;
1915 aExcludeRgns[i].cb = cThunks * sizeof(IMAGE_THUNK_DATA);
1916 cExcludeRgns++;
1917 }
1918
1919 /* advance */
1920 pImp++;
1921 }
1922
1923 /*
1924 * Ok, do the comparison.
1925 */
1926 int iDiff = 0;
1927 uint32_t uRvaNext = 0;
1928 for (unsigned i = 0; !iDiff && i < cExcludeRgns; i++)
1929 {
1930 if (uRvaNext < aExcludeRgns[i].uRva)
1931 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, aExcludeRgns[i].uRva - uRvaNext);
1932 uRvaNext = aExcludeRgns[i].uRva + aExcludeRgns[i].cb;
1933 }
1934 if (!iDiff && uRvaNext < pImage->cbImageBits)
1935 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, pImage->cbImageBits - uRvaNext);
1936 if (!iDiff)
1937 return VINF_SUCCESS;
1938 }
1939 else
1940 supdrvNtCompare(pImage, pbImageBits, 0, pImage->cbImageBits);
1941 return VERR_LDR_MISMATCH_NATIVE;
1942 }
1943 return VERR_INTERNAL_ERROR_4;
1944}
1945
1946
1947void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1948{
1949 if (pImage->pvNtSectionObj)
1950 {
1951 if (pImage->hMemLock != NIL_RTR0MEMOBJ)
1952 {
1953 RTR0MemObjFree(pImage->hMemLock, false /*fFreeMappings*/);
1954 pImage->hMemLock = NIL_RTR0MEMOBJ;
1955 }
1956
1957 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemUnloadGdiDriverInformation,
1958 &pImage->pvNtSectionObj, sizeof(pImage->pvNtSectionObj));
1959 if (rcNt != STATUS_SUCCESS)
1960 SUPR0Printf("VBoxDrv: failed to unload '%s', rcNt=%#x\n", pImage->szName, rcNt);
1961 pImage->pvNtSectionObj = NULL;
1962 }
1963 NOREF(pDevExt);
1964}
1965
1966
1967#ifdef SUPDRV_WITH_MSR_PROBER
1968
1969#if 1
1970/** @todo make this selectable. */
1971# define AMD_MSR_PASSCODE 0x9c5a203a
1972#else
1973# define ASMRdMsrEx(a, b, c) ASMRdMsr(a)
1974# define ASMWrMsrEx(a, b, c) ASMWrMsr(a,c)
1975#endif
1976
1977
1978/**
1979 * Argument package used by supdrvOSMsrProberRead and supdrvOSMsrProberWrite.
1980 */
1981typedef struct SUPDRVNTMSPROBERARGS
1982{
1983 uint32_t uMsr;
1984 uint64_t uValue;
1985 bool fGp;
1986} SUPDRVNTMSPROBERARGS;
1987
1988/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberRead.} */
1989static DECLCALLBACK(void) supdrvNtMsProberReadOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1990{
1991 /*
1992 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
1993 * (At least on 32-bit XP.)
1994 */
1995 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
1996 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
1997 __try
1998 {
1999 pArgs->uValue = ASMRdMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE);
2000 pArgs->fGp = false;
2001 }
2002 __except(EXCEPTION_EXECUTE_HANDLER)
2003 {
2004 pArgs->fGp = true;
2005 pArgs->uValue = 0;
2006 }
2007 ASMSetFlags(fOldFlags);
2008}
2009
2010
2011int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
2012{
2013 SUPDRVNTMSPROBERARGS Args;
2014 Args.uMsr = uMsr;
2015 Args.uValue = 0;
2016 Args.fGp = true;
2017
2018 if (idCpu == NIL_RTCPUID)
2019 supdrvNtMsProberReadOnCpu(idCpu, &Args, NULL);
2020 else
2021 {
2022 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberReadOnCpu, &Args, NULL);
2023 if (RT_FAILURE(rc))
2024 return rc;
2025 }
2026
2027 if (Args.fGp)
2028 return VERR_ACCESS_DENIED;
2029 *puValue = Args.uValue;
2030 return VINF_SUCCESS;
2031}
2032
2033
2034/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberWrite.} */
2035static DECLCALLBACK(void) supdrvNtMsProberWriteOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2036{
2037 /*
2038 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
2039 * (At least on 32-bit XP.)
2040 */
2041 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
2042 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
2043 __try
2044 {
2045 ASMWrMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE, pArgs->uValue);
2046 pArgs->fGp = false;
2047 }
2048 __except(EXCEPTION_EXECUTE_HANDLER)
2049 {
2050 pArgs->fGp = true;
2051 }
2052 ASMSetFlags(fOldFlags);
2053}
2054
2055int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
2056{
2057 SUPDRVNTMSPROBERARGS Args;
2058 Args.uMsr = uMsr;
2059 Args.uValue = uValue;
2060 Args.fGp = true;
2061
2062 if (idCpu == NIL_RTCPUID)
2063 supdrvNtMsProberReadOnCpu(idCpu, &Args, NULL);
2064 else
2065 {
2066 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberReadOnCpu, &Args, NULL);
2067 if (RT_FAILURE(rc))
2068 return rc;
2069 }
2070
2071 if (Args.fGp)
2072 return VERR_ACCESS_DENIED;
2073 return VINF_SUCCESS;
2074}
2075
2076/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberModify.} */
2077static DECLCALLBACK(void) supdrvNtMsProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2078{
2079 PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
2080 register uint32_t uMsr = pReq->u.In.uMsr;
2081 bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
2082 uint64_t uBefore = 0;
2083 uint64_t uWritten = 0;
2084 uint64_t uAfter = 0;
2085 bool fBeforeGp = true;
2086 bool fModifyGp = true;
2087 bool fAfterGp = true;
2088 bool fRestoreGp = true;
2089 RTCCUINTREG fOldFlags;
2090
2091 /*
2092 * Do the job.
2093 */
2094 fOldFlags = ASMIntDisableFlags();
2095 ASMCompilerBarrier(); /* paranoia */
2096 if (!fFaster)
2097 ASMWriteBackAndInvalidateCaches();
2098
2099 __try
2100 {
2101 uBefore = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
2102 fBeforeGp = false;
2103 }
2104 __except(EXCEPTION_EXECUTE_HANDLER)
2105 {
2106 fBeforeGp = true;
2107 }
2108 if (!fBeforeGp)
2109 {
2110 register uint64_t uRestore = uBefore;
2111
2112 /* Modify. */
2113 uWritten = uRestore;
2114 uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
2115 uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
2116 __try
2117 {
2118 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uWritten);
2119 fModifyGp = false;
2120 }
2121 __except(EXCEPTION_EXECUTE_HANDLER)
2122 {
2123 fModifyGp = true;
2124 }
2125
2126 /* Read modified value. */
2127 __try
2128 {
2129 uAfter = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
2130 fAfterGp = false;
2131 }
2132 __except(EXCEPTION_EXECUTE_HANDLER)
2133 {
2134 fAfterGp = true;
2135 }
2136
2137 /* Restore original value. */
2138 __try
2139 {
2140 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uRestore);
2141 fRestoreGp = false;
2142 }
2143 __except(EXCEPTION_EXECUTE_HANDLER)
2144 {
2145 fRestoreGp = true;
2146 }
2147
2148 /* Invalid everything we can. */
2149 if (!fFaster)
2150 {
2151 ASMWriteBackAndInvalidateCaches();
2152 ASMReloadCR3();
2153 ASMNopPause();
2154 }
2155 }
2156
2157 ASMCompilerBarrier(); /* paranoia */
2158 ASMSetFlags(fOldFlags);
2159
2160 /*
2161 * Write out the results.
2162 */
2163 pReq->u.Out.uResults.Modify.uBefore = uBefore;
2164 pReq->u.Out.uResults.Modify.uWritten = uWritten;
2165 pReq->u.Out.uResults.Modify.uAfter = uAfter;
2166 pReq->u.Out.uResults.Modify.fBeforeGp = fBeforeGp;
2167 pReq->u.Out.uResults.Modify.fModifyGp = fModifyGp;
2168 pReq->u.Out.uResults.Modify.fAfterGp = fAfterGp;
2169 pReq->u.Out.uResults.Modify.fRestoreGp = fRestoreGp;
2170 RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
2171}
2172
2173
2174int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
2175{
2176 if (idCpu == NIL_RTCPUID)
2177 {
2178 supdrvNtMsProberModifyOnCpu(idCpu, pReq, NULL);
2179 return VINF_SUCCESS;
2180 }
2181 return RTMpOnSpecific(idCpu, supdrvNtMsProberModifyOnCpu, pReq, NULL);
2182}
2183
2184#endif /* SUPDRV_WITH_MSR_PROBER */
2185
2186
2187/**
2188 * Converts an IPRT error code to an nt status code.
2189 *
2190 * @returns corresponding nt status code.
2191 * @param rc IPRT error status code.
2192 */
2193static NTSTATUS VBoxDrvNtErr2NtStatus(int rc)
2194{
2195 switch (rc)
2196 {
2197 case VINF_SUCCESS: return STATUS_SUCCESS;
2198 case VERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
2199 case VERR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
2200 case VERR_INVALID_MAGIC: return STATUS_UNKNOWN_REVISION;
2201 case VERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
2202 case VERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
2203 case VERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
2204 case VERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
2205 case VERR_PERMISSION_DENIED: return STATUS_ACCESS_DENIED;
2206 case VERR_VERSION_MISMATCH: return STATUS_REVISION_MISMATCH;
2207 }
2208
2209 if (rc < 0)
2210 {
2211 if (((uint32_t)rc & UINT32_C(0xffff0000)) == UINT32_C(0xffff0000))
2212 return (NTSTATUS)( ((uint32_t)rc & UINT32_C(0xffff)) | SUP_NT_STATUS_BASE );
2213 }
2214 return STATUS_UNSUCCESSFUL;
2215}
2216
2217
2218#if 0 /* See alternative in SUPDrvA-win.asm */
2219/**
2220 * Alternative version of SUPR0Printf for Windows.
2221 *
2222 * @returns 0.
2223 * @param pszFormat The format string.
2224 */
2225SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
2226{
2227 va_list va;
2228 char szMsg[512];
2229
2230 va_start(va, pszFormat);
2231 size_t cch = RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
2232 szMsg[sizeof(szMsg) - 1] = '\0';
2233 va_end(va);
2234
2235 RTLogWriteDebugger(szMsg, cch);
2236 return 0;
2237}
2238#endif
2239
2240
2241/**
2242 * Returns configuration flags of the host kernel.
2243 */
2244SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
2245{
2246 return 0;
2247}
2248
2249
2250#ifdef VBOX_WITH_HARDENING
2251
2252/** @name Identifying Special Processes: CSRSS.EXE
2253 * @{ */
2254
2255
2256/**
2257 * Checks if the process is a system32 process by the given name.
2258 *
2259 * @returns true / false.
2260 * @param pProcess The process to check.
2261 * @param pszName The lower case process name (no path!).
2262 */
2263static bool supdrvNtProtectIsSystem32ProcessMatch(PEPROCESS pProcess, const char *pszName)
2264{
2265 Assert(strlen(pszName) < 16); /* see buffer below */
2266
2267 /*
2268 * This test works on XP+.
2269 */
2270 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
2271 if (!pszImageFile)
2272 return false;
2273
2274 if (RTStrICmp(pszImageFile, pszName) != 0)
2275 return false;
2276
2277 /*
2278 * This test requires a Vista+ API.
2279 */
2280 if (g_pfnPsReferenceProcessFilePointer)
2281 {
2282 PFILE_OBJECT pFile = NULL;
2283 NTSTATUS rcNt = g_pfnPsReferenceProcessFilePointer(pProcess, &pFile);
2284 if (!NT_SUCCESS(rcNt))
2285 return false;
2286
2287 union
2288 {
2289 OBJECT_NAME_INFORMATION Info;
2290 uint8_t abBuffer[sizeof(g_System32NtPath) + 16 * sizeof(WCHAR)];
2291 } Buf;
2292 ULONG cbIgn;
2293 rcNt = ObQueryNameString(pFile, &Buf.Info, sizeof(Buf) - sizeof(WCHAR), &cbIgn);
2294 ObDereferenceObject(pFile);
2295 if (!NT_SUCCESS(rcNt))
2296 return false;
2297
2298 /* Terminate the name. */
2299 PRTUTF16 pwszName = Buf.Info.Name.Buffer;
2300 pwszName[Buf.Info.Name.Length / sizeof(RTUTF16)] = '\0';
2301
2302 /* Match the name against the system32 directory path. */
2303 uint32_t cbSystem32 = g_System32NtPath.UniStr.Length;
2304 if (Buf.Info.Name.Length < cbSystem32)
2305 return false;
2306 if (memcmp(pwszName, g_System32NtPath.UniStr.Buffer, cbSystem32))
2307 return false;
2308 pwszName += cbSystem32 / sizeof(RTUTF16);
2309 if (*pwszName++ != '\\')
2310 return false;
2311
2312 /* Compare the name. */
2313 const char *pszRight = pszName;
2314 for (;;)
2315 {
2316 WCHAR wchLeft = *pwszName++;
2317 char chRight = *pszRight++;
2318 Assert(chRight == RT_C_TO_LOWER(chRight));
2319
2320 if ( wchLeft != chRight
2321 && RT_C_TO_LOWER(wchLeft) != chRight)
2322 return false;
2323 if (!chRight)
2324 break;
2325 }
2326 }
2327
2328 return true;
2329}
2330
2331
2332/**
2333 * Checks if the current process is likely to be CSRSS.
2334 *
2335 * @returns true/false.
2336 * @param pProcess The process.
2337 */
2338static bool supdrvNtProtectIsCsrssByProcess(PEPROCESS pProcess)
2339{
2340 /*
2341 * On Windows 8.1 CSRSS.EXE is a protected process.
2342 */
2343 if (g_pfnPsIsProtectedProcessLight)
2344 {
2345 if (!g_pfnPsIsProtectedProcessLight(pProcess))
2346 return false;
2347 }
2348
2349 /*
2350 * The name tests.
2351 */
2352 if (!supdrvNtProtectIsSystem32ProcessMatch(pProcess, "csrss.exe"))
2353 return false;
2354
2355 /** @todo Could extend the CSRSS.EXE check with that the TokenUser of the
2356 * current process must be "NT AUTHORITY\SYSTEM" (S-1-5-18). */
2357
2358 return true;
2359}
2360
2361
2362/**
2363 * Helper for supdrvNtProtectGetAlpcPortObjectType that tries out a name.
2364 *
2365 * @returns true if done, false if not.
2366 * @param pwszPortNm The port path.
2367 * @param ppObjType The object type return variable, updated when
2368 * returning true.
2369 */
2370static bool supdrvNtProtectGetAlpcPortObjectType2(PCRTUTF16 pwszPortNm, POBJECT_TYPE *ppObjType)
2371{
2372 bool fDone = false;
2373
2374 UNICODE_STRING UniStrPortNm;
2375 UniStrPortNm.Buffer = (WCHAR *)pwszPortNm;
2376 UniStrPortNm.Length = (USHORT)(RTUtf16Len(pwszPortNm) * sizeof(WCHAR));
2377 UniStrPortNm.MaximumLength = UniStrPortNm.Length + sizeof(WCHAR);
2378
2379 OBJECT_ATTRIBUTES ObjAttr;
2380 InitializeObjectAttributes(&ObjAttr, &UniStrPortNm, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
2381
2382 HANDLE hPort;
2383 NTSTATUS rcNt = g_pfnZwAlpcCreatePort(&hPort, &ObjAttr, NULL /*pPortAttribs*/);
2384 if (NT_SUCCESS(rcNt))
2385 {
2386 PVOID pvObject;
2387 rcNt = ObReferenceObjectByHandle(hPort, 0 /*DesiredAccess*/, NULL /*pObjectType*/,
2388 KernelMode, &pvObject, NULL /*pHandleInfo*/);
2389 if (NT_SUCCESS(rcNt))
2390 {
2391 POBJECT_TYPE pObjType = g_pfnObGetObjectType(pvObject);
2392 if (pObjType)
2393 {
2394 SUPR0Printf("vboxdrv: ALPC Port Object Type %p (vs %p)\n", pObjType, *ppObjType);
2395 *ppObjType = pObjType;
2396 fDone = true;
2397 }
2398 ObDereferenceObject(pvObject);
2399 }
2400 NtClose(hPort);
2401 }
2402 return fDone;
2403}
2404
2405
2406/**
2407 * Attempts to retrieve the ALPC Port object type.
2408 *
2409 * We've had at least three reports that using LpcPortObjectType when trying to
2410 * get at the ApiPort object results in STATUS_OBJECT_TYPE_MISMATCH errors.
2411 * It's not known who has modified LpcPortObjectType or AlpcPortObjectType (not
2412 * exported) so that it differs from the actual ApiPort type, or maybe this
2413 * unknown entity is intercepting our attempt to reference the port and
2414 * tries to mislead us. The paranoid explanataion is of course that some evil
2415 * root kit like software is messing with the OS, however, it's possible that
2416 * this is valid kernel behavior that 99.8% of our users and 100% of the
2417 * developers are not triggering for some reason.
2418 *
2419 * The code here creates an ALPC port object and gets it's type. It will cache
2420 * the result in g_pAlpcPortObjectType2 on success.
2421 *
2422 * @returns Object type.
2423 * @param uSessionId The session id.
2424 * @param pszSessionId The session id formatted as a string.
2425 */
2426static POBJECT_TYPE supdrvNtProtectGetAlpcPortObjectType(uint32_t uSessionId, const char *pszSessionId)
2427{
2428 POBJECT_TYPE pObjType = *LpcPortObjectType;
2429
2430 if ( g_pfnZwAlpcCreatePort
2431 && g_pfnObGetObjectType)
2432 {
2433 int rc;
2434 ssize_t cchTmp; NOREF(cchTmp);
2435 char szTmp[16];
2436 RTUTF16 wszPortNm[128];
2437 size_t offRand;
2438
2439 /*
2440 * First attempt is in the session directory.
2441 */
2442 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
2443 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
2444 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\VBoxDrv-");
2445 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
2446 Assert(cchTmp > 0);
2447 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2448 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
2449 offRand = RTUtf16Len(wszPortNm);
2450 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
2451 Assert(cchTmp > 0);
2452 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2453 AssertRCSuccess(rc);
2454
2455 bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2456 if (!fDone)
2457 {
2458 wszPortNm[offRand] = '\0';
2459 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0); Assert(cchTmp > 0);
2460 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2461 AssertRCSuccess(rc);
2462
2463 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2464 }
2465 if (!fDone)
2466 {
2467 /*
2468 * Try base names.
2469 */
2470 if (uSessionId == 0)
2471 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
2472 else
2473 {
2474 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
2475 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
2476 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
2477 }
2478 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
2479 Assert(cchTmp > 0);
2480 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2481 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
2482 offRand = RTUtf16Len(wszPortNm);
2483 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
2484 Assert(cchTmp > 0);
2485 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
2486 AssertRCSuccess(rc);
2487
2488 bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2489 if (!fDone)
2490 {
2491 wszPortNm[offRand] = '\0';
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 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
2498 }
2499 }
2500
2501 /* Cache the result in g_pAlpcPortObjectType2. */
2502 if ( g_pAlpcPortObjectType2 == NULL
2503 && pObjType != g_pAlpcPortObjectType1
2504 && fDone)
2505 g_pAlpcPortObjectType2 = pObjType;
2506
2507 }
2508
2509 return pObjType;
2510}
2511
2512
2513/**
2514 * Called in the context of VBoxDrvNtCreate to determin the CSRSS for the
2515 * current process.
2516 *
2517 * The Client/Server Runtime Subsystem (CSRSS) process needs to be allowed some
2518 * additional access right so we need to make 101% sure we correctly identify
2519 * the CSRSS process a process is associated with.
2520 *
2521 * @returns IPRT status code.
2522 * @param pNtProtect The NT protected process structure. The
2523 * hCsrssPid member will be updated on success.
2524 */
2525static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect)
2526{
2527 Assert(pNtProtect->AvlCore.Key == PsGetCurrentProcessId());
2528 Assert(pNtProtect->pCsrssProcess == NULL);
2529 Assert(pNtProtect->hCsrssPid == NULL);
2530
2531 /*
2532 * We'll try use the ApiPort LPC object for the session we're in to track
2533 * down the CSRSS process. So, we start by constructing a path to it.
2534 */
2535 int rc;
2536 uint32_t uSessionId = PsGetProcessSessionId(PsGetCurrentProcess());
2537 char szSessionId[16];
2538 WCHAR wszApiPort[48];
2539 if (uSessionId == 0)
2540 {
2541 szSessionId[0] = '0';
2542 szSessionId[1] = '\0';
2543 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
2544 }
2545 else
2546 {
2547 ssize_t cchTmp = RTStrFormatU32(szSessionId, sizeof(szSessionId), uSessionId, 10, 0, 0, 0);
2548 AssertReturn(cchTmp > 0, (int)cchTmp);
2549 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Sessions\\");
2550 if (RT_SUCCESS(rc))
2551 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), szSessionId);
2552 if (RT_SUCCESS(rc))
2553 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
2554 }
2555 AssertRCReturn(rc, rc);
2556
2557 UNICODE_STRING ApiPortStr;
2558 ApiPortStr.Buffer = wszApiPort;
2559 ApiPortStr.Length = (USHORT)(RTUtf16Len(wszApiPort) * sizeof(RTUTF16));
2560 ApiPortStr.MaximumLength = ApiPortStr.Length + sizeof(RTUTF16);
2561
2562 /*
2563 * The object cannot be opened, but we can reference it by name.
2564 */
2565 void *pvApiPortObj = NULL;
2566 NTSTATUS rcNt = ObReferenceObjectByName(&ApiPortStr,
2567 0,
2568 NULL /*pAccessState*/,
2569 STANDARD_RIGHTS_READ,
2570 g_pAlpcPortObjectType1,
2571 KernelMode,
2572 NULL /*pvParseContext*/,
2573 &pvApiPortObj);
2574 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
2575 && g_pAlpcPortObjectType2 != NULL)
2576 rcNt = ObReferenceObjectByName(&ApiPortStr,
2577 0,
2578 NULL /*pAccessState*/,
2579 STANDARD_RIGHTS_READ,
2580 g_pAlpcPortObjectType2,
2581 KernelMode,
2582 NULL /*pvParseContext*/,
2583 &pvApiPortObj);
2584 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
2585 && g_pfnObGetObjectType
2586 && g_pfnZwAlpcCreatePort)
2587 rcNt = ObReferenceObjectByName(&ApiPortStr,
2588 0,
2589 NULL /*pAccessState*/,
2590 STANDARD_RIGHTS_READ,
2591 supdrvNtProtectGetAlpcPortObjectType(uSessionId, szSessionId),
2592 KernelMode,
2593 NULL /*pvParseContext*/,
2594 &pvApiPortObj);
2595 if (!NT_SUCCESS(rcNt))
2596 {
2597 SUPR0Printf("vboxdrv: Error opening '%ls': %#x\n", wszApiPort, rcNt);
2598 return rcNt == STATUS_OBJECT_TYPE_MISMATCH ? VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE : VERR_SUPDRV_APIPORT_OPEN_ERROR;
2599 }
2600
2601 /*
2602 * Query the processes in the system so we can locate CSRSS.EXE candidates.
2603 * Note! Attempts at using SystemSessionProcessInformation failed with
2604 * STATUS_ACCESS_VIOLATION.
2605 * Note! The 32 bytes on the size of to counteract the allocation header
2606 * that rtR0MemAllocEx slaps on everything.
2607 */
2608 ULONG cbNeeded = _64K - 32;
2609 uint32_t cbBuf;
2610 uint8_t *pbBuf = NULL;
2611 do
2612 {
2613 cbBuf = RT_ALIGN(cbNeeded + _4K, _64K) - 32;
2614 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
2615 if (!pbBuf)
2616 break;
2617
2618 cbNeeded = 0;
2619#if 0 /* doesn't work. */
2620 SYSTEM_SESSION_PROCESS_INFORMATION Req;
2621 Req.SessionId = uSessionId;
2622 Req.BufferLength = cbBuf;
2623 Req.Buffer = pbBuf;
2624 rcNt = NtQuerySystemInformation(SystemSessionProcessInformation, &Req, sizeof(Req), &cbNeeded);
2625#else
2626 rcNt = NtQuerySystemInformation(SystemProcessInformation, pbBuf, cbBuf, &cbNeeded);
2627#endif
2628 if (NT_SUCCESS(rcNt))
2629 break;
2630
2631 RTMemFree(pbBuf);
2632 pbBuf = NULL;
2633 } while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
2634 && cbNeeded > cbBuf
2635 && cbNeeded < 32U*_1M);
2636
2637 if ( pbBuf
2638 && NT_SUCCESS(rcNt)
2639 && cbNeeded >= sizeof(SYSTEM_PROCESS_INFORMATION))
2640 {
2641 /*
2642 * Walk the returned data and look for the process associated with the
2643 * ApiPort object. The ApiPort object keeps the EPROCESS address of
2644 * the owner process (i.e. CSRSS) relatively early in the structure. On
2645 * 64-bit windows 8.1 it's at offset 0x18. So, obtain the EPROCESS
2646 * pointer to likely CSRSS processes and check for a match in the first
2647 * 0x40 bytes of the ApiPort object.
2648 */
2649 rc = VERR_SUPDRV_CSRSS_NOT_FOUND;
2650 for (uint32_t offBuf = 0; offBuf <= cbNeeded - sizeof(SYSTEM_PROCESS_INFORMATION);)
2651 {
2652 PRTNT_SYSTEM_PROCESS_INFORMATION pProcInfo = (PRTNT_SYSTEM_PROCESS_INFORMATION)&pbBuf[offBuf];
2653 if ( pProcInfo->ProcessName.Length == 9 * sizeof(WCHAR)
2654 && pProcInfo->NumberOfThreads > 2 /* Very low guess. */
2655 && pProcInfo->HandleCount > 32 /* Very low guess, I hope. */
2656 && (uintptr_t)pProcInfo->ProcessName.Buffer - (uintptr_t)pbBuf < cbNeeded
2657 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[0]) == 'c'
2658 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[1]) == 's'
2659 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[2]) == 'r'
2660 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[3]) == 's'
2661 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[4]) == 's'
2662 && pProcInfo->ProcessName.Buffer[5] == '.'
2663 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[6]) == 'e'
2664 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[7]) == 'x'
2665 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[8]) == 'e' )
2666 {
2667
2668 /* Get the process structure and perform some more thorough
2669 process checks. */
2670 PEPROCESS pProcess;
2671 rcNt = PsLookupProcessByProcessId(pProcInfo->UniqueProcessId, &pProcess);
2672 if (NT_SUCCESS(rcNt))
2673 {
2674 if (supdrvNtProtectIsCsrssByProcess(pProcess))
2675 {
2676 if (PsGetProcessSessionId(pProcess) == uSessionId)
2677 {
2678 /* Final test, check the ApiPort.
2679 Note! The old LPC (pre Vista) objects has the PID
2680 much earlier in the structure. Might be
2681 worth looking for it instead. */
2682 bool fThatsIt = false;
2683 __try
2684 {
2685 PEPROCESS *ppPortProc = (PEPROCESS *)pvApiPortObj;
2686 uint32_t cTests = g_uNtVerCombined >= SUP_NT_VER_VISTA ? 16 : 38; /* ALPC since Vista. */
2687 do
2688 {
2689 fThatsIt = *ppPortProc == pProcess;
2690 ppPortProc++;
2691 } while (!fThatsIt && --cTests > 0);
2692 }
2693 __except(EXCEPTION_EXECUTE_HANDLER)
2694 {
2695 fThatsIt = false;
2696 }
2697 if (fThatsIt)
2698 {
2699 /* Ok, we found it! Keep the process structure
2700 reference as well as the PID so we can
2701 safely identify it later on. */
2702 pNtProtect->hCsrssPid = pProcInfo->UniqueProcessId;
2703 pNtProtect->pCsrssProcess = pProcess;
2704 rc = VINF_SUCCESS;
2705 break;
2706 }
2707 }
2708 }
2709
2710 ObDereferenceObject(pProcess);
2711 }
2712 }
2713
2714 /* Advance. */
2715 if (!pProcInfo->NextEntryOffset)
2716 break;
2717 offBuf += pProcInfo->NextEntryOffset;
2718 }
2719 }
2720 else
2721 rc = VERR_SUPDRV_SESSION_PROCESS_ENUM_ERROR;
2722 RTMemFree(pbBuf);
2723 ObDereferenceObject(pvApiPortObj);
2724 return rc;
2725}
2726
2727
2728/**
2729 * Checks that the given process is the CSRSS process associated with protected
2730 * process.
2731 *
2732 * @returns true / false.
2733 * @param pNtProtect The NT protection structure.
2734 * @param pCsrss The process structure of the alleged CSRSS.EXE
2735 * process.
2736 */
2737static bool supdrvNtProtectIsAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pCsrss)
2738{
2739 if (pNtProtect->pCsrssProcess == pCsrss)
2740 {
2741 if (pNtProtect->hCsrssPid == PsGetProcessId(pCsrss))
2742 {
2743 return true;
2744 }
2745 }
2746 return false;
2747}
2748
2749
2750/**
2751 * Checks if the given process is the stupid themes service.
2752 *
2753 * The caller does some screening of access masks and what not. We do the rest.
2754 *
2755 * @returns true / false.
2756 * @param pNtProtect The NT protection structure.
2757 * @param pAnnoyingProcess The process structure of an process that might
2758 * happen to be the annoying themes process.
2759 */
2760static bool supdrvNtProtectIsFrigginThemesService(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pAnnoyingProcess)
2761{
2762 /*
2763 * Check the process name.
2764 */
2765 if (!supdrvNtProtectIsSystem32ProcessMatch(pAnnoyingProcess, "svchost.exe"))
2766 return false;
2767
2768 /** @todo Come up with more checks. */
2769
2770 return true;
2771}
2772
2773
2774#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
2775/**
2776 * Checks if the given process is one of the whitelisted debuggers.
2777 *
2778 * @returns true / false.
2779 * @param pProcess The process to check.
2780 */
2781static bool supdrvNtProtectIsWhitelistedDebugger(PEPROCESS pProcess)
2782{
2783 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
2784 if (!pszImageFile)
2785 return false;
2786
2787 if (pszImageFile[0] == 'w' || pszImageFile[0] == 'W')
2788 {
2789 if (RTStrICmp(pszImageFile, "windbg.exe") == 0)
2790 return true;
2791 if (RTStrICmp(pszImageFile, "werfault.exe") == 0)
2792 return true;
2793 if (RTStrICmp(pszImageFile, "werfaultsecure.exe") == 0)
2794 return true;
2795 }
2796 else if (pszImageFile[0] == 'd' || pszImageFile[0] == 'D')
2797 {
2798 if (RTStrICmp(pszImageFile, "drwtsn32.exe") == 0)
2799 return true;
2800 if (RTStrICmp(pszImageFile, "dwwin.exe") == 0)
2801 return true;
2802 }
2803
2804 return false;
2805}
2806#endif /* VBOX_WITHOUT_DEBUGGER_CHECKS */
2807
2808
2809/** @} */
2810
2811
2812/** @name Process Creation Callbacks.
2813 * @{ */
2814
2815
2816/**
2817 * Cleans up VBoxDrv or VBoxDrvStub error info not collected by the dead process.
2818 *
2819 * @param hProcessId The ID of the dead process.
2820 */
2821static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId)
2822{
2823 int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
2824 if (RT_SUCCESS(rc))
2825 {
2826 PSUPDRVNTERRORINFO pCur, pNext;
2827 RTListForEachSafe(&g_ErrorInfoHead, pCur, pNext, SUPDRVNTERRORINFO, ListEntry)
2828 {
2829 if (pCur->hProcessId == hProcessId)
2830 {
2831 RTListNodeRemove(&pCur->ListEntry);
2832 RTMemFree(pCur);
2833 }
2834 }
2835 RTSemMutexRelease(g_hErrorInfoLock);
2836 }
2837}
2838
2839
2840/**
2841 * Common worker used by the process creation hooks as well as the process
2842 * handle creation hooks to check if a VM process is being created.
2843 *
2844 * @returns true if likely to be a VM process, false if not.
2845 * @param pNtStub The NT protection structure for the possible
2846 * stub process.
2847 * @param hParentPid The parent pid.
2848 * @param hChildPid The child pid.
2849 */
2850static bool supdrvNtProtectIsSpawningStubProcess(PSUPDRVNTPROTECT pNtStub, HANDLE hParentPid, HANDLE hChildPid)
2851{
2852 bool fRc = false;
2853 if (pNtStub->AvlCore.Key == hParentPid) /* paranoia */
2854 {
2855 if (pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
2856 {
2857 /* Compare short names. */
2858 PEPROCESS pStubProcess;
2859 NTSTATUS rcNt = PsLookupProcessByProcessId(hParentPid, &pStubProcess);
2860 if (NT_SUCCESS(rcNt))
2861 {
2862 PEPROCESS pChildProcess;
2863 rcNt = PsLookupProcessByProcessId(hChildPid, &pChildProcess);
2864 if (NT_SUCCESS(rcNt))
2865 {
2866 const char *pszStub = (const char *)PsGetProcessImageFileName(pStubProcess);
2867 const char *pszChild = (const char *)PsGetProcessImageFileName(pChildProcess);
2868 fRc = pszStub != NULL
2869 && pszChild != NULL
2870 && strcmp(pszStub, pszChild) == 0;
2871
2872 /** @todo check that the full image names matches. */
2873
2874 ObDereferenceObject(pChildProcess);
2875 }
2876 ObDereferenceObject(pStubProcess);
2877 }
2878 }
2879 }
2880 return fRc;
2881}
2882
2883
2884/**
2885 * Common code used by the notifies to protect a child process.
2886 *
2887 * @returns VBox status code.
2888 * @param pNtStub The NT protect structure for the parent.
2889 * @param hChildPid The child pid.
2890 */
2891static int supdrvNtProtectProtectNewStubChild(PSUPDRVNTPROTECT pNtParent, HANDLE hChildPid)
2892{
2893 /*
2894 * Create a child protection struction.
2895 */
2896 PSUPDRVNTPROTECT pNtChild;
2897 int rc = supdrvNtProtectCreate(&pNtChild, hChildPid, kSupDrvNtProtectKind_VmProcessUnconfirmed, false /*fLink*/);
2898 if (RT_SUCCESS(rc))
2899 {
2900 pNtChild->fFirstProcessCreateHandle = true;
2901 pNtChild->fFirstThreadCreateHandle = true;
2902 pNtChild->fCsrssFirstProcessCreateHandle = true;
2903 pNtChild->cCsrssFirstProcessDuplicateHandle = ARCH_BITS == 32 ? 2 : 1;
2904 pNtChild->fThemesFirstProcessCreateHandle = true;
2905 pNtChild->hParentPid = pNtParent->AvlCore.Key;
2906 pNtChild->hCsrssPid = pNtParent->hCsrssPid;
2907 pNtChild->pCsrssProcess = pNtParent->pCsrssProcess;
2908 if (pNtChild->pCsrssProcess)
2909 ObReferenceObject(pNtChild->pCsrssProcess);
2910
2911 /*
2912 * Take the spinlock, recheck parent conditions and link things.
2913 */
2914 RTSpinlockAcquire(g_hNtProtectLock);
2915 if (pNtParent->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
2916 {
2917 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtChild->AvlCore);
2918 if (fSuccess)
2919 {
2920 pNtParent->u.pChild = pNtChild; /* Parent keeps the initial reference. */
2921 pNtParent->enmProcessKind = kSupDrvNtProtectKind_StubParent;
2922 pNtChild->u.pParent = pNtParent;
2923
2924 RTSpinlockRelease(g_hNtProtectLock);
2925 return VINF_SUCCESS;
2926 }
2927
2928 rc = VERR_INTERNAL_ERROR_2;
2929 }
2930 else
2931 rc = VERR_WRONG_ORDER;
2932 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
2933 RTSpinlockRelease(g_hNtProtectLock);
2934
2935 supdrvNtProtectRelease(pNtChild);
2936 }
2937 return rc;
2938}
2939
2940
2941/**
2942 * Common process termination code.
2943 *
2944 * Transitions protected process to the dead states, protecting against handle
2945 * PID reuse (esp. with unconfirmed VM processes) and handle cleanup issues.
2946 *
2947 * @param hDeadPid The PID of the dead process.
2948 */
2949static void supdrvNtProtectUnprotectDeadProcess(HANDLE hDeadPid)
2950{
2951 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hDeadPid);
2952 if (pNtProtect)
2953 {
2954 PSUPDRVNTPROTECT pNtChild = NULL;
2955
2956 RTSpinlockAcquire(g_hNtProtectLock);
2957
2958 /*
2959 * If this is an unconfirmed VM process, we must release the reference
2960 * the parent structure holds.
2961 */
2962 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
2963 {
2964 PSUPDRVNTPROTECT pNtParent = pNtProtect->u.pParent;
2965 AssertRelease(pNtParent); AssertRelease(pNtParent->u.pChild == pNtProtect);
2966 pNtParent->u.pChild = NULL;
2967 pNtProtect->u.pParent = NULL;
2968 pNtChild = pNtProtect;
2969 }
2970 /*
2971 * If this is a stub exitting before the VM process gets confirmed,
2972 * release the protection of the potential VM process as this is not
2973 * the prescribed behavior.
2974 */
2975 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
2976 && pNtProtect->u.pChild)
2977 {
2978 pNtChild = pNtProtect->u.pChild;
2979 pNtProtect->u.pChild = NULL;
2980 pNtChild->u.pParent = NULL;
2981 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
2982 }
2983
2984 /*
2985 * Transition it to the dead state to prevent it from opening the
2986 * support driver again or be posthumously abused as a vm process parent.
2987 */
2988 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
2989 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessConfirmed)
2990 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
2991 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
2992 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubSpawning
2993 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
2994 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_StubDead;
2995
2996 RTSpinlockRelease(g_hNtProtectLock);
2997
2998 supdrvNtProtectRelease(pNtProtect);
2999 supdrvNtProtectRelease(pNtChild);
3000
3001 /*
3002 * Do session cleanups.
3003 */
3004 AssertReturnVoid((HANDLE)(uintptr_t)RTProcSelf() == hDeadPid);
3005 if (g_pDevObjSys)
3006 {
3007 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
3008 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, (RTPROCESS)(uintptr_t)hDeadPid,
3009 RTR0ProcHandleSelf(), NULL);
3010 if (pSession)
3011 {
3012 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
3013 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
3014 }
3015 }
3016 }
3017}
3018
3019
3020/**
3021 * Common worker for the process creation callback that verifies a new child
3022 * being created by the handle creation callback code.
3023 *
3024 * @param pNtStub The parent.
3025 * @param pNtVm The child.
3026 * @param fCallerChecks The result of any additional tests the caller made.
3027 * This is in order to avoid duplicating the failure
3028 * path code.
3029 */
3030static void supdrvNtProtectVerifyNewChildProtection(PSUPDRVNTPROTECT pNtStub, PSUPDRVNTPROTECT pNtVm, bool fCallerChecks)
3031{
3032 if ( fCallerChecks
3033 && pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubParent
3034 && pNtVm->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3035 && pNtVm->u.pParent == pNtStub
3036 && pNtStub->u.pChild == pNtVm)
3037 {
3038 /* Fine, reset the CSRSS hack (fixes ViRobot APT Shield 2.0 issue). */
3039 pNtVm->fFirstProcessCreateHandle = true;
3040 return;
3041 }
3042
3043 LogRel(("vboxdrv: Misdetected vm stub; hParentPid=%p hChildPid=%p\n", pNtStub->AvlCore.Key, pNtVm->AvlCore.Key));
3044 if (pNtStub->enmProcessKind != kSupDrvNtProtectKind_VmProcessConfirmed)
3045 supdrvNtProtectUnprotectDeadProcess(pNtVm->AvlCore.Key);
3046}
3047
3048
3049/**
3050 * Old style callback (since forever).
3051 *
3052 * @param hParentPid The parent PID.
3053 * @param hNewPid The PID of the new child.
3054 * @param fCreated TRUE if it's a creation notification,
3055 * FALSE if termination.
3056 * @remarks ASSUMES this arrives before the handle creation callback.
3057 */
3058static VOID __stdcall
3059supdrvNtProtectCallback_ProcessCreateNotify(HANDLE hParentPid, HANDLE hNewPid, BOOLEAN fCreated)
3060{
3061 /*
3062 * Is it a new process that needs protection?
3063 */
3064 if (fCreated)
3065 {
3066 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
3067 if (pNtStub)
3068 {
3069 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
3070 if (!pNtVm)
3071 {
3072 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hNewPid))
3073 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
3074 }
3075 else
3076 {
3077 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm, true);
3078 supdrvNtProtectRelease(pNtVm);
3079 }
3080 supdrvNtProtectRelease(pNtStub);
3081 }
3082 }
3083 /*
3084 * Process termination, do clean ups.
3085 */
3086 else
3087 {
3088 supdrvNtProtectUnprotectDeadProcess(hNewPid);
3089 supdrvNtErrorInfoCleanupProcess(hNewPid);
3090 }
3091}
3092
3093
3094/**
3095 * New style callback (Vista SP1+ / w2k8).
3096 *
3097 * @param pNewProcess The new process.
3098 * @param hNewPid The PID of the new process.
3099 * @param pInfo Process creation details. NULL if process
3100 * termination notification.
3101 * @remarks ASSUMES this arrives before the handle creation callback.
3102 */
3103static VOID __stdcall
3104supdrvNtProtectCallback_ProcessCreateNotifyEx(PEPROCESS pNewProcess, HANDLE hNewPid, PPS_CREATE_NOTIFY_INFO pInfo)
3105{
3106 /*
3107 * Is it a new process that needs protection?
3108 */
3109 if (pInfo)
3110 {
3111 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(pInfo->CreatingThreadId.UniqueProcess);
3112
3113 Log(("vboxdrv/NewProcessEx: ctx=%04zx/%p pid=%04zx ppid=%04zx ctor=%04zx/%04zx rcNt=%#x %.*ls\n",
3114 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3115 hNewPid, pInfo->ParentProcessId,
3116 pInfo->CreatingThreadId.UniqueProcess, pInfo->CreatingThreadId.UniqueThread, pInfo->CreationStatus,
3117 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? (size_t)pInfo->ImageFileName->Length / 2 : 0,
3118 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? pInfo->ImageFileName->Buffer : NULL));
3119
3120 if (pNtStub)
3121 {
3122 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
3123 if (!pNtVm)
3124 {
3125 /* Parent must be creator. */
3126 if (pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId)
3127 {
3128 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, pInfo->ParentProcessId, hNewPid))
3129 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
3130 }
3131 }
3132 else
3133 {
3134 /* Parent must be creator (as above). */
3135 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm,
3136 pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId);
3137 supdrvNtProtectRelease(pNtVm);
3138 }
3139 supdrvNtProtectRelease(pNtStub);
3140 }
3141 }
3142 /*
3143 * Process termination, do clean ups.
3144 */
3145 else
3146 {
3147 supdrvNtProtectUnprotectDeadProcess(hNewPid);
3148 supdrvNtErrorInfoCleanupProcess(hNewPid);
3149 }
3150}
3151
3152/** @} */
3153
3154
3155/** @name Process Handle Callbacks.
3156 * @{ */
3157
3158/** Process rights that we allow for handles to stub and VM processes. */
3159# define SUPDRV_NT_ALLOW_PROCESS_RIGHTS \
3160 ( PROCESS_TERMINATE \
3161 | PROCESS_VM_READ \
3162 | PROCESS_QUERY_INFORMATION \
3163 | PROCESS_QUERY_LIMITED_INFORMATION \
3164 | PROCESS_SUSPEND_RESUME \
3165 | DELETE \
3166 | READ_CONTROL \
3167 | SYNCHRONIZE)
3168
3169/** Evil process rights. */
3170# define SUPDRV_NT_EVIL_PROCESS_RIGHTS \
3171 ( PROCESS_CREATE_THREAD \
3172 | PROCESS_SET_SESSIONID /*?*/ \
3173 | PROCESS_VM_OPERATION \
3174 | PROCESS_VM_WRITE \
3175 | PROCESS_DUP_HANDLE \
3176 | PROCESS_CREATE_PROCESS /*?*/ \
3177 | PROCESS_SET_QUOTA /*?*/ \
3178 | PROCESS_SET_INFORMATION \
3179 | PROCESS_SET_LIMITED_INFORMATION /*?*/ \
3180 | 0)
3181AssertCompile((SUPDRV_NT_ALLOW_PROCESS_RIGHTS & SUPDRV_NT_EVIL_PROCESS_RIGHTS) == 0);
3182
3183
3184static OB_PREOP_CALLBACK_STATUS __stdcall
3185supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
3186{
3187 Assert(pvUser == NULL);
3188 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3189 Assert(pOpInfo->ObjectType == *PsProcessType);
3190
3191 /*
3192 * Protected? Kludge required for NtOpenProcess calls comming in before
3193 * the create process hook triggers on Windows 8.1 (possibly others too).
3194 */
3195 HANDLE hObjPid = PsGetProcessId((PEPROCESS)pOpInfo->Object);
3196 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hObjPid);
3197 if (!pNtProtect)
3198 {
3199 HANDLE hParentPid = PsGetProcessInheritedFromUniqueProcessId((PEPROCESS)pOpInfo->Object);
3200 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
3201 if (pNtStub)
3202 {
3203 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hObjPid))
3204 {
3205 supdrvNtProtectProtectNewStubChild(pNtStub, hObjPid);
3206 pNtProtect = supdrvNtProtectLookup(hObjPid);
3207 }
3208 supdrvNtProtectRelease(pNtStub);
3209 }
3210 }
3211 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
3212 if (pNtProtect)
3213 {
3214 /*
3215 * Ok, it's a protected process. Strip rights as required or possible.
3216 */
3217 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
3218 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOW_PROCESS_RIGHTS;
3219
3220 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
3221 {
3222 /* Don't restrict the process accessing itself. */
3223 if ((PEPROCESS)pOpInfo->Object == PsGetCurrentProcess())
3224 {
3225 pOpInfo->CallContext = NULL; /* don't assert */
3226 pNtProtect->fFirstProcessCreateHandle = false;
3227
3228 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s\n",
3229 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3230 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3231 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3232 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3233 }
3234#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3235 /* Allow debuggers full access. */
3236 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
3237 {
3238 pOpInfo->CallContext = NULL; /* don't assert */
3239 pNtProtect->fFirstProcessCreateHandle = false;
3240
3241 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
3242 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3243 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3244 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3245 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3246 }
3247#endif
3248 else
3249 {
3250 /* Special case 1 on Vista, 7 & 8:
3251 The CreateProcess code passes the handle over to CSRSS.EXE
3252 and the code inBaseSrvCreateProcess will duplicate the
3253 handle with 0x1fffff as access mask. NtDuplicateObject will
3254 fail this call before it ever gets down here.
3255
3256 Special case 2 on 8.1:
3257 The CreateProcess code requires additional rights for
3258 something, we'll drop these in the stub code. */
3259 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3260 && pNtProtect->fFirstProcessCreateHandle
3261 && pOpInfo->KernelHandle == 0
3262 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess())
3263 && ExGetPreviousMode() != KernelMode)
3264 {
3265 if ( !pOpInfo->KernelHandle
3266 && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
3267 {
3268 if (g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3))
3269 fAllowedRights |= s_fCsrssStupidDesires;
3270 else
3271 fAllowedRights = fAllowedRights
3272 | PROCESS_VM_OPERATION
3273 | PROCESS_VM_WRITE
3274 | PROCESS_SET_INFORMATION
3275 | PROCESS_SET_LIMITED_INFORMATION
3276 | 0;
3277 pOpInfo->CallContext = NULL; /* don't assert this. */
3278 }
3279 pNtProtect->fFirstProcessCreateHandle = false;
3280 }
3281
3282 /* Special case 3 on 8.1:
3283 The interaction between the CreateProcess code and CSRSS.EXE
3284 has changed to the better with Windows 8.1. CSRSS.EXE no
3285 longer duplicates the process (thread too) handle, but opens
3286 it, thus allowing us to do our job. */
3287 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3)
3288 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3289 && pNtProtect->fCsrssFirstProcessCreateHandle
3290 && pOpInfo->KernelHandle == 0
3291 && ExGetPreviousMode() == UserMode
3292 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3293 {
3294 pNtProtect->fCsrssFirstProcessCreateHandle = false;
3295 if (pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
3296 {
3297 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
3298 PROCESS_CREATE_PROCESS */
3299 fAllowedRights = fAllowedRights
3300 | PROCESS_VM_OPERATION
3301 | PROCESS_VM_WRITE
3302 | PROCESS_DUP_HANDLE /* Needed for CreateProcess/VBoxTestOGL. */
3303 | 0;
3304 pOpInfo->CallContext = NULL; /* don't assert this. */
3305 }
3306 }
3307
3308 /* Special case 4, Windows 7, Vista, possibly 8, but not 8.1:
3309 The Themes service requires PROCESS_DUP_HANDLE access to our
3310 process or we won't get any menus and dialogs will be half
3311 unreadable. This is _very_ unfortunate and more work will
3312 go into making this more secure. */
3313 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)
3314 && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
3315 && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
3316 && pNtProtect->fThemesFirstProcessCreateHandle
3317 && pOpInfo->KernelHandle == 0
3318 && ExGetPreviousMode() == UserMode
3319 && supdrvNtProtectIsFrigginThemesService(pNtProtect, PsGetCurrentProcess()) )
3320 {
3321 pNtProtect->fThemesFirstProcessCreateHandle = true; /* Only once! */
3322 fAllowedRights |= PROCESS_DUP_HANDLE;
3323 pOpInfo->CallContext = NULL; /* don't assert this. */
3324 }
3325
3326 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p/pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
3327 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3328 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3329 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
3330 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess & fAllowedRights,
3331 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode() ));
3332
3333 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
3334 }
3335 }
3336 else
3337 {
3338 /* Don't restrict the process accessing itself. */
3339 if ( (PEPROCESS)pOpInfo->Object == PsGetCurrentProcess()
3340 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pOpInfo->Object)
3341 {
3342 Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
3343 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3344 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3345 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3346 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3347 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3348 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3349 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3350
3351 pOpInfo->CallContext = NULL; /* don't assert */
3352 }
3353 else
3354 {
3355 /* Special case 5 on Vista, 7 & 8:
3356 This is the CSRSS.EXE end of special case #1. */
3357 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
3358 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3359 && pNtProtect->cCsrssFirstProcessDuplicateHandle > 0
3360 && pOpInfo->KernelHandle == 0
3361 && pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess == s_fCsrssStupidDesires
3362 && pNtProtect->hParentPid
3363 == PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess)
3364 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
3365 && ExGetPreviousMode() == UserMode
3366 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()))
3367 {
3368 if (ASMAtomicDecS32(&pNtProtect->cCsrssFirstProcessDuplicateHandle) >= 0)
3369 {
3370 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
3371 PROCESS_CREATE_PROCESS, PROCESS_DUP_HANDLE */
3372 fAllowedRights = fAllowedRights
3373 | PROCESS_VM_OPERATION
3374 | PROCESS_VM_WRITE
3375 | PROCESS_DUP_HANDLE /* Needed for launching VBoxTestOGL. */
3376 | 0;
3377 pOpInfo->CallContext = NULL; /* don't assert this. */
3378 }
3379 }
3380
3381 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
3382 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3383 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3384 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3385 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3386 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3387 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3388 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3389
3390 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
3391 }
3392 }
3393 supdrvNtProtectRelease(pNtProtect);
3394 }
3395
3396 return OB_PREOP_SUCCESS;
3397}
3398
3399
3400static VOID __stdcall
3401supdrvNtProtectCallback_ProcessHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
3402{
3403 Assert(pvUser == NULL);
3404 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3405 Assert(pOpInfo->ObjectType == *PsProcessType);
3406
3407 if ( pOpInfo->CallContext
3408 && NT_SUCCESS(pOpInfo->ReturnStatus))
3409 {
3410 ACCESS_MASK const fGrantedAccess = pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE
3411 ? pOpInfo->Parameters->CreateHandleInformation.GrantedAccess
3412 : pOpInfo->Parameters->DuplicateHandleInformation.GrantedAccess;
3413 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOW_PROCESS_RIGHTS
3414 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
3415 | PROCESS_UNKNOWN_4000 /* Seen set on win 8.1 */
3416 /*| PROCESS_UNKNOWN_8000 */ ) )
3417 || pOpInfo->KernelHandle,
3418 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
3419 fGrantedAccess, SUPDRV_NT_ALLOW_PROCESS_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOW_PROCESS_RIGHTS));
3420 }
3421}
3422
3423# undef SUPDRV_NT_ALLOW_PROCESS_RIGHTS
3424
3425/** @} */
3426
3427
3428/** @name Thread Handle Callbacks
3429 * @{ */
3430
3431/* From ntifs.h */
3432extern "C" NTKERNELAPI PEPROCESS __stdcall IoThreadToProcess(PETHREAD);
3433
3434/** Thread rights that we allow for handles to stub and VM processes. */
3435# define SUPDRV_NT_ALLOWED_THREAD_RIGHTS \
3436 ( THREAD_TERMINATE \
3437 | THREAD_GET_CONTEXT \
3438 | THREAD_QUERY_INFORMATION \
3439 | THREAD_QUERY_LIMITED_INFORMATION \
3440 | DELETE \
3441 | READ_CONTROL \
3442 | SYNCHRONIZE)
3443/** @todo consider THREAD_SET_LIMITED_INFORMATION & THREAD_RESUME */
3444
3445/** Evil thread rights.
3446 * @remarks THREAD_RESUME is not included as it seems to be forced upon us by
3447 * Windows 8.1, at least for some processes. We dont' actively
3448 * allow it though, just tollerate it when forced to. */
3449# define SUPDRV_NT_EVIL_THREAD_RIGHTS \
3450 ( THREAD_SUSPEND_RESUME \
3451 | THREAD_SET_CONTEXT \
3452 | THREAD_SET_INFORMATION \
3453 | THREAD_SET_LIMITED_INFORMATION /*?*/ \
3454 | THREAD_SET_THREAD_TOKEN /*?*/ \
3455 | THREAD_IMPERSONATE /*?*/ \
3456 | THREAD_DIRECT_IMPERSONATION /*?*/ \
3457 /*| THREAD_RESUME - see remarks. */ \
3458 | 0)
3459AssertCompile((SUPDRV_NT_EVIL_THREAD_RIGHTS & SUPDRV_NT_ALLOWED_THREAD_RIGHTS) == 0);
3460
3461
3462static OB_PREOP_CALLBACK_STATUS __stdcall
3463supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
3464{
3465 Assert(pvUser == NULL);
3466 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3467 Assert(pOpInfo->ObjectType == *PsThreadType);
3468
3469 PEPROCESS pProcess = IoThreadToProcess((PETHREAD)pOpInfo->Object);
3470 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(PsGetProcessId(pProcess));
3471 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
3472 if (pNtProtect)
3473 {
3474 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
3475 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOWED_THREAD_RIGHTS;
3476
3477 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
3478 {
3479 /* Don't restrict the process accessing its own threads. */
3480 if (pProcess == PsGetCurrentProcess())
3481 {
3482 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] self\n",
3483 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3484 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3485 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind));
3486 pOpInfo->CallContext = NULL; /* don't assert */
3487 pNtProtect->fFirstThreadCreateHandle = false;
3488 }
3489#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3490 /* Allow debuggers full access. */
3491 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
3492 {
3493 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
3494 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3495 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3496 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3497 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3498 pOpInfo->CallContext = NULL; /* don't assert */
3499 }
3500#endif
3501 else
3502 {
3503 /* Special case 1 on Vista, 7, 8:
3504 The CreateProcess code passes the handle over to CSRSS.EXE
3505 and the code inBaseSrvCreateProcess will duplicate the
3506 handle with 0x1fffff as access mask. NtDuplicateObject will
3507 fail this call before it ever gets down here. */
3508 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
3509 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3510 && pNtProtect->fFirstThreadCreateHandle
3511 && pOpInfo->KernelHandle == 0
3512 && ExGetPreviousMode() == UserMode
3513 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess()) )
3514 {
3515 if ( !pOpInfo->KernelHandle
3516 && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
3517 {
3518 fAllowedRights |= s_fCsrssStupidDesires;
3519 pOpInfo->CallContext = NULL; /* don't assert this. */
3520 }
3521 pNtProtect->fFirstThreadCreateHandle = false;
3522 }
3523
3524 /* Special case 2 on 8.1, possibly also Vista, 7, 8:
3525 When creating a process like VBoxTestOGL from the VM process,
3526 CSRSS.EXE will try talk to the calling thread and, it
3527 appears, impersonate it. We unfortunately need to allow
3528 this or there will be no 3D support. Typical DbgPrint:
3529 "SXS: BasepCreateActCtx() Calling csrss server failed. Status = 0xc00000a5" */
3530 SUPDRVNTPROTECTKIND enmProcessKind;
3531 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
3532 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
3533 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3534 && pOpInfo->KernelHandle == 0
3535 && ExGetPreviousMode() == UserMode
3536 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3537 {
3538 fAllowedRights |= THREAD_IMPERSONATE;
3539 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
3540 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
3541 pOpInfo->CallContext = NULL; /* don't assert this. */
3542 }
3543
3544 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
3545 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3546 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3547 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
3548 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess & fAllowedRights,
3549 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode()));
3550
3551 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
3552 }
3553 }
3554 else
3555 {
3556 /* Don't restrict the process accessing its own threads. */
3557 if ( pProcess == PsGetCurrentProcess()
3558 && (PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pProcess)
3559 {
3560 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] self\n",
3561 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3562 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3563 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3564 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3565 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3566 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3567 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3568 pOpInfo->CallContext = NULL; /* don't assert */
3569 }
3570 else
3571 {
3572 /* Special case 3 on Vista, 7, 8:
3573 This is the follow up to special case 1. */
3574 SUPDRVNTPROTECTKIND enmProcessKind;
3575 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
3576 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
3577 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3578 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
3579 && pOpInfo->KernelHandle == 0
3580 && ExGetPreviousMode() == UserMode
3581 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3582 {
3583 fAllowedRights |= THREAD_IMPERSONATE;
3584 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
3585 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
3586 pOpInfo->CallContext = NULL; /* don't assert this. */
3587 }
3588
3589 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s\n",
3590 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3591 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3592 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3593 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3594 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3595 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
3596 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess & fAllowedRights,
3597 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3598
3599 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
3600 }
3601 }
3602
3603 supdrvNtProtectRelease(pNtProtect);
3604 }
3605
3606 return OB_PREOP_SUCCESS;
3607}
3608
3609
3610static VOID __stdcall
3611supdrvNtProtectCallback_ThreadHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
3612{
3613 Assert(pvUser == NULL);
3614 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3615 Assert(pOpInfo->ObjectType == *PsThreadType);
3616
3617 if ( pOpInfo->CallContext
3618 && NT_SUCCESS(pOpInfo->ReturnStatus))
3619 {
3620 ACCESS_MASK const fGrantedAccess = pOpInfo->Parameters->CreateHandleInformation.GrantedAccess;
3621 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOWED_THREAD_RIGHTS
3622 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
3623 | THREAD_RESUME /* This seems to be force upon us too with 8.1. */
3624 ) )
3625 || pOpInfo->KernelHandle,
3626 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
3627 fGrantedAccess, SUPDRV_NT_ALLOWED_THREAD_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOWED_THREAD_RIGHTS));
3628 }
3629}
3630
3631# undef SUPDRV_NT_ALLOWED_THREAD_RIGHTS
3632
3633/** @} */
3634
3635
3636/**
3637 * Creates a new process protection structure.
3638 *
3639 * @returns VBox status code.
3640 * @param ppNtProtect Where to return the pointer to the structure
3641 * on success.
3642 * @param hPid The process ID of the process to protect.
3643 * @param enmProcessKind The kind of process we're protecting.
3644 * @param fLink Whether to link the structure into the tree.
3645 */
3646static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid, SUPDRVNTPROTECTKIND enmProcessKind, bool fLink)
3647{
3648 AssertReturn(g_hNtProtectLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
3649
3650 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)RTMemAllocZ(sizeof(*pNtProtect));
3651 if (!pNtProtect)
3652 return VERR_NO_MEMORY;
3653
3654 pNtProtect->AvlCore.Key = hPid;
3655 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC;
3656 pNtProtect->cRefs = 1;
3657 pNtProtect->enmProcessKind = enmProcessKind;
3658 pNtProtect->hParentPid = NULL;
3659 pNtProtect->hOpenTid = NULL;
3660 pNtProtect->hCsrssPid = NULL;
3661 pNtProtect->pCsrssProcess = NULL;
3662
3663 if (fLink)
3664 {
3665 RTSpinlockAcquire(g_hNtProtectLock);
3666 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtProtect->AvlCore);
3667 RTSpinlockRelease(g_hNtProtectLock);
3668
3669 if (!fSuccess)
3670 {
3671 /* Duplicate entry, fail. */
3672 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC_DEAD;
3673 LogRel(("supdrvNtProtectCreate: Duplicate (%#x).\n", pNtProtect->AvlCore.Key));
3674 RTMemFree(pNtProtect);
3675 return VERR_DUPLICATE;
3676 }
3677 }
3678
3679 *ppNtProtect = pNtProtect;
3680 return VINF_SUCCESS;
3681}
3682
3683
3684/**
3685 * Releases a reference to a NT protection structure.
3686 *
3687 * @param pNtProtect The NT protection structure.
3688 */
3689static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
3690{
3691 if (!pNtProtect)
3692 return;
3693 AssertReturnVoid(pNtProtect->u32Magic == SUPDRVNTPROTECT_MAGIC);
3694
3695 RTSpinlockAcquire(g_hNtProtectLock);
3696 uint32_t cRefs = ASMAtomicDecU32(&pNtProtect->cRefs);
3697 if (cRefs != 0)
3698 RTSpinlockRelease(g_hNtProtectLock);
3699 else
3700 {
3701 /*
3702 * That was the last reference. Remove it from the tree, invalidate it
3703 * and free the resources associated with it. Also, release any
3704 * child/parent references related to this protection structure.
3705 */
3706 ASMAtomicWriteU32(&pNtProtect->u32Magic, SUPDRVNTPROTECT_MAGIC_DEAD);
3707 PSUPDRVNTPROTECT pRemoved = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pNtProtect->AvlCore.Key);
3708
3709 PSUPDRVNTPROTECT pRemovedChild = NULL;
3710 PSUPDRVNTPROTECT pChild = NULL;
3711 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent)
3712 {
3713 pChild = pNtProtect->u.pChild;
3714 if (pChild)
3715 {
3716 pNtProtect->u.pChild = NULL;
3717 pChild->u.pParent = NULL;
3718 pChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3719 uint32_t cChildRefs = ASMAtomicDecU32(&pChild->cRefs);
3720 if (!cChildRefs)
3721 pRemovedChild = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pChild->AvlCore.Key);
3722 else
3723 pChild = NULL;
3724 }
3725 }
3726 else
3727 AssertRelease(pNtProtect->enmProcessKind != kSupDrvNtProtectKind_VmProcessUnconfirmed);
3728
3729 RTSpinlockRelease(g_hNtProtectLock);
3730 Assert(pRemoved == pNtProtect);
3731 Assert(pRemovedChild == pChild);
3732
3733 if (pNtProtect->pCsrssProcess)
3734 {
3735 ObDereferenceObject(pNtProtect->pCsrssProcess);
3736 pNtProtect->pCsrssProcess = NULL;
3737 }
3738
3739 RTMemFree(pNtProtect);
3740 if (pChild)
3741 RTMemFree(pChild);
3742 }
3743}
3744
3745
3746/**
3747 * Looks up a PID in the NT protect tree.
3748 *
3749 * @returns Pointer to a NT protection structure (with a referenced) on success,
3750 * NULL if not found.
3751 * @param hPid The process ID.
3752 */
3753static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid)
3754{
3755 RTSpinlockAcquire(g_hNtProtectLock);
3756 PSUPDRVNTPROTECT pFound = (PSUPDRVNTPROTECT)RTAvlPVGet(&g_NtProtectTree, hPid);
3757 if (pFound)
3758 ASMAtomicIncU32(&pFound->cRefs);
3759 RTSpinlockRelease(g_hNtProtectLock);
3760 return pFound;
3761}
3762
3763
3764/**
3765 * Validates a few facts about the stub process when the VM process opens
3766 * vboxdrv.
3767 *
3768 * This makes sure the stub process is still around and that it has neither
3769 * debugger nor extra threads in it.
3770 *
3771 * @returns VBox status code.
3772 * @param pNtProtect The unconfirmed VM process currently trying to
3773 * open vboxdrv.
3774 * @param pErrInfo Additional error information.
3775 */
3776static int supdrvNtProtectVerifyStubForVmProcess(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
3777{
3778 /*
3779 * Grab a reference to the parent stub process.
3780 */
3781 SUPDRVNTPROTECTKIND enmStub = kSupDrvNtProtectKind_Invalid;
3782 PSUPDRVNTPROTECT pNtStub = NULL;
3783 RTSpinlockAcquire(g_hNtProtectLock);
3784 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3785 {
3786 pNtStub = pNtProtect->u.pParent; /* weak reference. */
3787 if (pNtStub)
3788 {
3789 enmStub = pNtStub->enmProcessKind;
3790 if (enmStub == kSupDrvNtProtectKind_StubParent)
3791 {
3792 uint32_t cRefs = ASMAtomicIncU32(&pNtStub->cRefs);
3793 Assert(cRefs > 0 && cRefs < 1024);
3794 }
3795 else
3796 pNtStub = NULL;
3797 }
3798 }
3799 RTSpinlockRelease(g_hNtProtectLock);
3800
3801 /*
3802 * We require the stub process to be present.
3803 */
3804 if (!pNtStub)
3805 return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND, "Missing stub process (enmStub=%d).", enmStub);
3806
3807 /*
3808 * Open the parent process and thread so we can check for debuggers and unwanted threads.
3809 */
3810 int rc;
3811 PEPROCESS pStubProcess;
3812 NTSTATUS rcNt = PsLookupProcessByProcessId(pNtStub->AvlCore.Key, &pStubProcess);
3813 if (NT_SUCCESS(rcNt))
3814 {
3815 HANDLE hStubProcess;
3816 rcNt = ObOpenObjectByPointer(pStubProcess, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
3817 0 /*DesiredAccess*/, *PsProcessType, KernelMode, &hStubProcess);
3818 if (NT_SUCCESS(rcNt))
3819 {
3820 PETHREAD pStubThread;
3821 rcNt = PsLookupThreadByThreadId(pNtStub->hOpenTid, &pStubThread);
3822 if (NT_SUCCESS(rcNt))
3823 {
3824 HANDLE hStubThread;
3825 rcNt = ObOpenObjectByPointer(pStubThread, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
3826 0 /*DesiredAccess*/, *PsThreadType, KernelMode, &hStubThread);
3827 if (NT_SUCCESS(rcNt))
3828 {
3829 /*
3830 * Do some simple sanity checking.
3831 */
3832 rc = supHardNtVpDebugger(hStubProcess, pErrInfo);
3833 if (RT_SUCCESS(rc))
3834 rc = supHardNtVpThread(hStubProcess, hStubThread, pErrInfo);
3835
3836 /* Clean up. */
3837 rcNt = NtClose(hStubThread); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
3838 }
3839 else
3840 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_OPEN_ERROR,
3841 "Error opening stub thread %p (tid %p, pid %p): %#x",
3842 pStubThread, pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
3843 }
3844 else
3845 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_NOT_FOUND,
3846 "Failed to locate thread %p in %p: %#x", pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
3847 rcNt = NtClose(hStubProcess); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
3848 }
3849 else
3850 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_OPEN_ERROR,
3851 "Error opening stub process %p (pid %p): %#x", pStubProcess, pNtStub->AvlCore.Key, rcNt);
3852 ObDereferenceObject(pStubProcess);
3853 }
3854 else
3855 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND,
3856 "Failed to locate stub process %p: %#x", pNtStub->AvlCore.Key, rcNt);
3857
3858 supdrvNtProtectRelease(pNtStub);
3859 return rc;
3860}
3861
3862
3863/**
3864 * Worker for supdrvNtProtectVerifyProcess that verifies the handles to a VM
3865 * process and its thread.
3866 *
3867 * @returns VBox status code.
3868 * @param pNtProtect The NT protect structure for getting information
3869 * about special processes.
3870 * @param pErrInfo Where to return additional error details.
3871 */
3872static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
3873{
3874 /*
3875 * What to protect.
3876 */
3877 PEPROCESS pProtectedProcess = PsGetCurrentProcess();
3878 HANDLE hProtectedPid = PsGetProcessId(pProtectedProcess);
3879 PETHREAD pProtectedThread = PsGetCurrentThread();
3880 AssertReturn(pNtProtect->AvlCore.Key == hProtectedPid, VERR_INTERNAL_ERROR_5);
3881
3882 /*
3883 * Take a snapshot of all the handles in the system.
3884 * Note! The 32 bytes on the size of to counteract the allocation header
3885 * that rtR0MemAllocEx slaps on everything.
3886 */
3887 uint32_t cbBuf = _256K - 32;
3888 uint8_t *pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
3889 ULONG cbNeeded = cbBuf;
3890 NTSTATUS rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
3891 if (!NT_SUCCESS(rcNt))
3892 {
3893 while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
3894 && cbNeeded > cbBuf
3895 && cbBuf <= 32U*_1M)
3896 {
3897 cbBuf = RT_ALIGN_32(cbNeeded + _4K, _64K) - 32;
3898 RTMemFree(pbBuf);
3899 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
3900 if (!pbBuf)
3901 return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Error allocating %zu bytes for querying handles.", cbBuf);
3902 rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
3903 }
3904 if (!NT_SUCCESS(rcNt))
3905 {
3906 RTMemFree(pbBuf);
3907 return RTErrInfoSetF(pErrInfo, RTErrConvertFromNtStatus(rcNt),
3908 "NtQuerySystemInformation/SystemExtendedHandleInformation failed: %#x\n", rcNt);
3909 }
3910 }
3911
3912 /*
3913 * Walk the information and look for handles to the two objects we're protecting.
3914 */
3915 int rc = VINF_SUCCESS;
3916# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3917 HANDLE idLastDebugger = (HANDLE)~(uintptr_t)0;
3918# endif
3919
3920 uint32_t cCsrssProcessHandles = 0;
3921 uint32_t cSystemProcessHandles = 0;
3922 uint32_t cEvilProcessHandles = 0;
3923 uint32_t cBenignProcessHandles = 0;
3924
3925 uint32_t cCsrssThreadHandles = 0;
3926 uint32_t cEvilThreadHandles = 0;
3927 uint32_t cBenignThreadHandles = 0;
3928
3929 SYSTEM_HANDLE_INFORMATION_EX const *pInfo = (SYSTEM_HANDLE_INFORMATION_EX const *)pbBuf;
3930 ULONG_PTR i = pInfo->NumberOfHandles;
3931 AssertRelease(RT_OFFSETOF(SYSTEM_HANDLE_INFORMATION_EX, Handles[i]) == cbNeeded);
3932 while (i-- > 0)
3933 {
3934 const char *pszType;
3935 SYSTEM_HANDLE_ENTRY_INFO_EX const *pHandleInfo = &pInfo->Handles[i];
3936 if (pHandleInfo->Object == pProtectedProcess)
3937 {
3938 /* Handles within the protected process are fine. */
3939 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_PROCESS_RIGHTS)
3940 || pHandleInfo->UniqueProcessId == hProtectedPid)
3941 {
3942 cBenignProcessHandles++;
3943 continue;
3944 }
3945
3946 /* CSRSS is allowed to have one evil process handle.
3947 See the special cases in the hook code. */
3948 if ( cCsrssProcessHandles < 1
3949 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
3950 {
3951 cCsrssProcessHandles++;
3952 continue;
3953 }
3954
3955 /* The system process is allowed having two open process handle in
3956 Windows 8.1 and later, and one in earlier. This is probably a
3957 little overly paranoid as I think we can safely trust the
3958 system process... */
3959 if ( cSystemProcessHandles < (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3) ? 2 : 1)
3960 && pHandleInfo->UniqueProcessId == PsGetProcessId(PsInitialSystemProcess))
3961 {
3962 cSystemProcessHandles++;
3963 continue;
3964 }
3965
3966 cEvilProcessHandles++;
3967 pszType = "process";
3968 }
3969 else if (pHandleInfo->Object == pProtectedThread)
3970 {
3971 /* Handles within the protected process is fine. */
3972 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_THREAD_RIGHTS)
3973 || pHandleInfo->UniqueProcessId == hProtectedPid)
3974 {
3975 cBenignThreadHandles++;
3976 continue;
3977 }
3978
3979 /* CSRSS is allowed to have one evil handle to the primary thread
3980 for LPC purposes. See the hook for special case. */
3981 if ( cCsrssThreadHandles < 1
3982 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
3983 {
3984 cCsrssThreadHandles++;
3985 continue;
3986 }
3987
3988 cEvilThreadHandles++;
3989 pszType = "thread";
3990 }
3991 else
3992 continue;
3993
3994# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3995 /* Ignore whitelisted debuggers. */
3996 if (pHandleInfo->UniqueProcessId == idLastDebugger)
3997 continue;
3998 PEPROCESS pDbgProc;
3999 NTSTATUS rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pDbgProc);
4000 if (NT_SUCCESS(rcNt))
4001 {
4002 bool fIsDebugger = supdrvNtProtectIsWhitelistedDebugger(pDbgProc);
4003 ObDereferenceObject(pDbgProc);
4004 if (fIsDebugger)
4005 {
4006 idLastDebugger = pHandleInfo->UniqueProcessId;
4007 continue;
4008 }
4009 }
4010# endif
4011
4012 /* Found evil handle. Currently ignoring on pre-Vista. */
4013# ifndef VBOX_WITH_VISTA_NO_SP
4014 if ( g_uNtVerCombined >= SUP_NT_VER_VISTA
4015# else
4016 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0)
4017# endif
4018 || g_pfnObRegisterCallbacks)
4019 {
4020 LogRel(("vboxdrv: Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s\n",
4021 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
4022 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType));
4023 rc = RTErrInfoAddF(pErrInfo, VERR_SUPDRV_HARDENING_EVIL_HANDLE,
4024 *pErrInfo->pszMsg
4025 ? "\nFound evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s"
4026 : "Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s",
4027 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
4028 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType);
4029
4030 /* Try add the process name. */
4031 PEPROCESS pOffendingProcess;
4032 rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pOffendingProcess);
4033 if (NT_SUCCESS(rcNt))
4034 {
4035 const char *pszName = (const char *)PsGetProcessImageFileName(pOffendingProcess);
4036 if (pszName && *pszName)
4037 rc = RTErrInfoAddF(pErrInfo, rc, " [%s]", pszName);
4038
4039 ObDereferenceObject(pOffendingProcess);
4040 }
4041 }
4042 }
4043
4044 RTMemFree(pbBuf);
4045 return rc;
4046}
4047
4048
4049/**
4050 * Checks if the current process checks out as a VM process stub.
4051 *
4052 * @returns VBox status code.
4053 * @param pNtProtect The NT protect structure. This is upgraded to a
4054 * final protection kind (state) on success.
4055 */
4056static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
4057{
4058 AssertReturn(PsGetProcessId(PsGetCurrentProcess()) == pNtProtect->AvlCore.Key, VERR_INTERNAL_ERROR_3);
4059
4060 /*
4061 * Do the verification. The handle restriction checks are only preformed
4062 * on VM processes.
4063 */
4064 int rc = VINF_SUCCESS;
4065 PSUPDRVNTERRORINFO pErrorInfo = (PSUPDRVNTERRORINFO)RTMemAllocZ(sizeof(*pErrorInfo));
4066 if (RT_SUCCESS(rc))
4067 {
4068 pErrorInfo->hProcessId = PsGetCurrentProcessId();
4069 pErrorInfo->hThreadId = PsGetCurrentThreadId();
4070 RTERRINFO ErrInfo;
4071 RTErrInfoInit(&ErrInfo, pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo));
4072
4073 if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
4074 rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect, &ErrInfo);
4075 if (RT_SUCCESS(rc))
4076 {
4077 rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY, 0 /*fFlags*/,
4078 NULL /*pcFixes*/, &ErrInfo);
4079 if (RT_SUCCESS(rc) && pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
4080 rc = supdrvNtProtectVerifyStubForVmProcess(pNtProtect, &ErrInfo);
4081 }
4082 }
4083 else
4084 rc = VERR_NO_MEMORY;
4085
4086 /*
4087 * Upgrade and return.
4088 */
4089 HANDLE hOpenTid = PsGetCurrentThreadId();
4090 RTSpinlockAcquire(g_hNtProtectLock);
4091
4092 /* Stub process verficiation is pretty much straight forward. */
4093 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
4094 {
4095 pNtProtect->enmProcessKind = RT_SUCCESS(rc) ? kSupDrvNtProtectKind_StubSpawning : kSupDrvNtProtectKind_StubDead;
4096 pNtProtect->hOpenTid = hOpenTid;
4097 }
4098 /* The VM process verification is a little bit more complicated
4099 because we need to drop the parent process reference as well. */
4100 else if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4101 {
4102 AssertRelease(pNtProtect->cRefs >= 2); /* Parent + Caller */
4103 PSUPDRVNTPROTECT pParent = pNtProtect->u.pParent;
4104 AssertRelease(pParent);
4105 AssertRelease(pParent->u.pParent == pNtProtect);
4106 AssertRelease(pParent->enmProcessKind == kSupDrvNtProtectKind_StubParent);
4107 pParent->u.pParent = NULL;
4108
4109 pNtProtect->u.pParent = NULL;
4110 ASMAtomicDecU32(&pNtProtect->cRefs);
4111
4112 if (RT_SUCCESS(rc))
4113 {
4114 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessConfirmed;
4115 pNtProtect->hOpenTid = hOpenTid;
4116 }
4117 else
4118 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4119 }
4120
4121 /* Since the stub and VM processes are only supposed to have one thread,
4122 we're not supposed to be subject to any races from within the processes.
4123
4124 There is a race between VM process verification and the stub process
4125 exiting, though. We require the stub process to be alive until the new
4126 VM process has made it thru the validation. So, when the stub
4127 terminates the notification handler will change the state of both stub
4128 and VM process to dead.
4129
4130 Also, I'm not entirely certain where the process
4131 termination notification is triggered from, so that can theorically
4132 create a race in both cases. */
4133 else
4134 {
4135 AssertReleaseMsg( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubDead
4136 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessDead,
4137 ("enmProcessKind=%d rc=%Rrc\n", pNtProtect->enmProcessKind, rc));
4138 if (RT_SUCCESS(rc))
4139 rc = VERR_INVALID_STATE; /* There should be no races here. */
4140 }
4141
4142 RTSpinlockRelease(g_hNtProtectLock);
4143
4144 /*
4145 * Free error info on success, keep it on failure.
4146 */
4147 if (RT_SUCCESS(rc))
4148 RTMemFree(pErrorInfo);
4149 else if (pErrorInfo)
4150 {
4151 pErrorInfo->cchErrorInfo = (uint32_t)strlen(pErrorInfo->szErrorInfo);
4152 if (!pErrorInfo->cchErrorInfo)
4153 pErrorInfo->cchErrorInfo = (uint32_t)RTStrPrintf(pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo),
4154 "supdrvNtProtectVerifyProcess: rc=%d", rc);
4155 if (RT_FAILURE(rc))
4156 RTLogWriteDebugger(pErrorInfo->szErrorInfo, pErrorInfo->cchErrorInfo);
4157
4158 int rc2 = RTSemMutexRequest(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
4159 if (RT_SUCCESS(rc2))
4160 {
4161 pErrorInfo->uCreatedMsTs = RTTimeMilliTS();
4162
4163 /* Free old entries. */
4164 PSUPDRVNTERRORINFO pCur;
4165 while ( (pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL
4166 && (int64_t)(pErrorInfo->uCreatedMsTs - pCur->uCreatedMsTs) > 60000 /*60sec*/)
4167 {
4168 RTListNodeRemove(&pCur->ListEntry);
4169 RTMemFree(pCur);
4170 }
4171
4172 /* Insert our new entry. */
4173 RTListAppend(&g_ErrorInfoHead, &pErrorInfo->ListEntry);
4174
4175 RTSemMutexRelease(g_hErrorInfoLock);
4176 }
4177 else
4178 RTMemFree(pErrorInfo);
4179 }
4180
4181 return rc;
4182}
4183
4184
4185# ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
4186
4187/**
4188 * Checks if the current process is being debugged.
4189 * @return @c true if debugged, @c false if not.
4190 */
4191static bool supdrvNtIsDebuggerAttached(void)
4192{
4193 return PsIsProcessBeingDebugged(PsGetCurrentProcess()) != FALSE;
4194}
4195
4196# endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
4197
4198
4199/**
4200 * Terminates the hardening bits.
4201 */
4202static void supdrvNtProtectTerm(void)
4203{
4204 /*
4205 * Stop intercepting process and thread handle creation calls.
4206 */
4207 if (g_pvObCallbacksCookie)
4208 {
4209 g_pfnObUnRegisterCallbacks(g_pvObCallbacksCookie);
4210 g_pvObCallbacksCookie = NULL;
4211 }
4212
4213 /*
4214 * Stop intercepting process creation and termination notifications.
4215 */
4216 NTSTATUS rcNt;
4217 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
4218 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
4219 else
4220 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
4221 AssertMsg(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt));
4222
4223 Assert(g_NtProtectTree == NULL);
4224
4225 /*
4226 * Clean up globals.
4227 */
4228 RTSpinlockDestroy(g_hNtProtectLock);
4229 g_NtProtectTree = NIL_RTSPINLOCK;
4230
4231 RTSemMutexDestroy(g_hErrorInfoLock);
4232 g_hErrorInfoLock = NIL_RTSEMMUTEX;
4233
4234 PSUPDRVNTERRORINFO pCur;
4235 while ((pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL)
4236 {
4237 RTListNodeRemove(&pCur->ListEntry);
4238 RTMemFree(pCur);
4239 }
4240
4241 supHardenedWinTermImageVerifier();
4242}
4243
4244# ifdef RT_ARCH_X86
4245DECLASM(void) supdrvNtQueryVirtualMemory_0xAF(void);
4246DECLASM(void) supdrvNtQueryVirtualMemory_0xB0(void);
4247DECLASM(void) supdrvNtQueryVirtualMemory_0xB1(void);
4248DECLASM(void) supdrvNtQueryVirtualMemory_0xB2(void);
4249DECLASM(void) supdrvNtQueryVirtualMemory_0xB3(void);
4250DECLASM(void) supdrvNtQueryVirtualMemory_0xB4(void);
4251DECLASM(void) supdrvNtQueryVirtualMemory_0xB5(void);
4252DECLASM(void) supdrvNtQueryVirtualMemory_0xB6(void);
4253DECLASM(void) supdrvNtQueryVirtualMemory_0xB7(void);
4254DECLASM(void) supdrvNtQueryVirtualMemory_0xB8(void);
4255DECLASM(void) supdrvNtQueryVirtualMemory_0xB9(void);
4256DECLASM(void) supdrvNtQueryVirtualMemory_0xBA(void);
4257DECLASM(void) supdrvNtQueryVirtualMemory_0xBB(void);
4258DECLASM(void) supdrvNtQueryVirtualMemory_0xBC(void);
4259DECLASM(void) supdrvNtQueryVirtualMemory_0xBD(void);
4260DECLASM(void) supdrvNtQueryVirtualMemory_0xBE(void);
4261# elif defined(RT_ARCH_AMD64)
4262DECLASM(void) supdrvNtQueryVirtualMemory_0x1F(void);
4263DECLASM(void) supdrvNtQueryVirtualMemory_0x20(void);
4264DECLASM(void) supdrvNtQueryVirtualMemory_0x21(void);
4265DECLASM(void) supdrvNtQueryVirtualMemory_0x22(void);
4266DECLASM(void) supdrvNtQueryVirtualMemory_0x23(void);
4267extern "C" NTSYSAPI NTSTATUS NTAPI ZwRequestWaitReplyPort(HANDLE, PVOID, PVOID);
4268# endif
4269
4270/**
4271 * Initalizes the hardening bits.
4272 *
4273 * @returns NT status code.
4274 */
4275static NTSTATUS supdrvNtProtectInit(void)
4276{
4277 /*
4278 * Initialize the globals.
4279 */
4280
4281 /* The NT version. */
4282 ULONG uMajor, uMinor, uBuild;
4283 PsGetVersion(&uMajor, &uMinor, &uBuild, NULL);
4284 g_uNtVerCombined = SUP_MAKE_NT_VER_COMBINED(uMajor, uMinor, uBuild, 0, 0);
4285
4286 /* Resolve methods we want but isn't available everywhere. */
4287 UNICODE_STRING RoutineName;
4288
4289 RtlInitUnicodeString(&RoutineName, L"ObGetObjectType");
4290 g_pfnObGetObjectType = (PFNOBGETOBJECTTYPE)MmGetSystemRoutineAddress(&RoutineName);
4291
4292 RtlInitUnicodeString(&RoutineName, L"ObRegisterCallbacks");
4293 g_pfnObRegisterCallbacks = (PFNOBREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
4294
4295 RtlInitUnicodeString(&RoutineName, L"ObUnRegisterCallbacks");
4296 g_pfnObUnRegisterCallbacks = (PFNOBUNREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
4297
4298 RtlInitUnicodeString(&RoutineName, L"PsSetCreateProcessNotifyRoutineEx");
4299 g_pfnPsSetCreateProcessNotifyRoutineEx = (PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)MmGetSystemRoutineAddress(&RoutineName);
4300
4301 RtlInitUnicodeString(&RoutineName, L"PsReferenceProcessFilePointer");
4302 g_pfnPsReferenceProcessFilePointer = (PFNPSREFERENCEPROCESSFILEPOINTER)MmGetSystemRoutineAddress(&RoutineName);
4303
4304 RtlInitUnicodeString(&RoutineName, L"PsIsProtectedProcessLight");
4305 g_pfnPsIsProtectedProcessLight = (PFNPSISPROTECTEDPROCESSLIGHT)MmGetSystemRoutineAddress(&RoutineName);
4306
4307 RtlInitUnicodeString(&RoutineName, L"ZwAlpcCreatePort");
4308 g_pfnZwAlpcCreatePort = (PFNZWALPCCREATEPORT)MmGetSystemRoutineAddress(&RoutineName);
4309
4310 RtlInitUnicodeString(&RoutineName, L"ZwQueryVirtualMemory"); /* Yes, using Zw version here. */
4311 g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)MmGetSystemRoutineAddress(&RoutineName);
4312 if (!g_pfnNtQueryVirtualMemory && g_uNtVerCombined < SUP_NT_VER_VISTA)
4313 {
4314 /* XP & W2K3 doesn't have this function exported, so we've cooked up a
4315 few alternative in the assembly helper file that uses the code in
4316 ZwReadFile with a different eax value. We figure the syscall number
4317 by inspecting ZwQueryVolumeInformationFile as it's the next number. */
4318# ifdef RT_ARCH_X86
4319 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwQueryVolumeInformationFile;
4320 if (*pbCode == 0xb8) /* mov eax, dword */
4321 switch (*(uint32_t const *)&pbCode[1])
4322 {
4323 case 0xb0: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xAF; break; /* just in case */
4324 case 0xb1: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB0; break; /* just in case */
4325 case 0xb2: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB1; break; /* just in case */
4326 case 0xb3: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* XP SP3 */
4327 case 0xb4: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* just in case */
4328 case 0xb5: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB3; break; /* just in case */
4329 case 0xb6: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB4; break; /* just in case */
4330 case 0xb7: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB5; break; /* just in case */
4331 case 0xb8: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB6; break; /* just in case */
4332 case 0xb9: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB7; break; /* just in case */
4333 case 0xba: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB8; break; /* just in case */
4334 case 0xbb: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBA; break; /* W2K3 R2 SP2 */
4335 case 0xbc: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBB; break; /* just in case */
4336 case 0xbd: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBC; break; /* just in case */
4337 case 0xbe: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBD; break; /* just in case */
4338 case 0xbf: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBE; break; /* just in case */
4339 }
4340# elif defined(RT_ARCH_AMD64)
4341 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwRequestWaitReplyPort;
4342 if ( pbCode[ 0] == 0x48 /* mov rax, rsp */
4343 && pbCode[ 1] == 0x8b
4344 && pbCode[ 2] == 0xc4
4345 && pbCode[ 3] == 0xfa /* cli */
4346 && pbCode[ 4] == 0x48 /* sub rsp, 10h */
4347 && pbCode[ 5] == 0x83
4348 && pbCode[ 6] == 0xec
4349 && pbCode[ 7] == 0x10
4350 && pbCode[ 8] == 0x50 /* push rax */
4351 && pbCode[ 9] == 0x9c /* pushfq */
4352 && pbCode[10] == 0x6a /* push 10 */
4353 && pbCode[11] == 0x10
4354 && pbCode[12] == 0x48 /* lea rax, [nt!KiServiceLinkage] */
4355 && pbCode[13] == 0x8d
4356 && pbCode[14] == 0x05
4357 && pbCode[19] == 0x50 /* push rax */
4358 && pbCode[20] == 0xb8 /* mov eax,1fh <- the syscall no. */
4359 /*&& pbCode[21] == 0x1f*/
4360 && pbCode[22] == 0x00
4361 && pbCode[23] == 0x00
4362 && pbCode[24] == 0x00
4363 && pbCode[25] == 0xe9 /* jmp KiServiceInternal */
4364 )
4365 {
4366 uint8_t const *pbKiServiceInternal = &pbCode[30] + *(int32_t const *)&pbCode[26];
4367 uint8_t const *pbKiServiceLinkage = &pbCode[19] + *(int32_t const *)&pbCode[15];
4368 if (*pbKiServiceLinkage == 0xc3)
4369 {
4370 g_pfnKiServiceInternal = (PFNRT)pbKiServiceInternal;
4371 g_pfnKiServiceLinkage = (PFNRT)pbKiServiceLinkage;
4372 switch (pbCode[21])
4373 {
4374 case 0x1e: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x1F; break;
4375 case 0x1f: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x20; break;
4376 case 0x20: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x21; break;
4377 case 0x21: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x22; break;
4378 case 0x22: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x23; break;
4379 }
4380 }
4381 }
4382# endif
4383 }
4384 if (!g_pfnNtQueryVirtualMemory)
4385 {
4386 LogRel(("vboxdrv: Cannot locate ZwQueryVirtualMemory in ntoskrnl, nor were we able to cook up a replacement.\n"));
4387 return STATUS_PROCEDURE_NOT_FOUND;
4388 }
4389
4390# ifdef VBOX_STRICT
4391 if ( g_uNtVerCombined >= SUP_NT_VER_W70
4392 && ( g_pfnObGetObjectType == NULL
4393 || g_pfnZwAlpcCreatePort == NULL) )
4394 {
4395 LogRel(("vboxdrv: g_pfnObGetObjectType=%p g_pfnZwAlpcCreatePort=%p.\n", g_pfnObGetObjectType, g_pfnZwAlpcCreatePort));
4396 return STATUS_PROCEDURE_NOT_FOUND;
4397 }
4398# endif
4399
4400 /* LPC object type. */
4401 g_pAlpcPortObjectType1 = *LpcPortObjectType;
4402
4403 /* The spinlock protecting our structures. */
4404 int rc = RTSpinlockCreate(&g_hNtProtectLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "NtProtectLock");
4405 if (RT_FAILURE(rc))
4406 return VBoxDrvNtErr2NtStatus(rc);
4407 g_NtProtectTree = NULL;
4408
4409 NTSTATUS rcNt;
4410
4411 /* The mutex protecting the error information. */
4412 RTListInit(&g_ErrorInfoHead);
4413 rc = RTSemMutexCreate(&g_hErrorInfoLock);
4414 if (RT_SUCCESS(rc))
4415 {
4416 /* Image stuff + certificates. */
4417 rc = supHardenedWinInitImageVerifier(NULL);
4418 if (RT_SUCCESS(rc))
4419 {
4420 /*
4421 * Intercept process creation and termination.
4422 */
4423 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
4424 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
4425 else
4426 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
4427 if (NT_SUCCESS(rcNt))
4428 {
4429 /*
4430 * Intercept process and thread handle creation calls.
4431 * The preferred method is only available on Vista SP1+.
4432 */
4433 if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
4434 {
4435 static OB_OPERATION_REGISTRATION s_aObOperations[] =
4436 {
4437 {
4438 PsProcessType,
4439 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
4440 supdrvNtProtectCallback_ProcessHandlePre,
4441 supdrvNtProtectCallback_ProcessHandlePost,
4442 },
4443 {
4444 PsThreadType,
4445 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
4446 supdrvNtProtectCallback_ThreadHandlePre,
4447 supdrvNtProtectCallback_ThreadHandlePost,
4448 },
4449 };
4450 static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
4451 {
4452 /* .Version = */ OB_FLT_REGISTRATION_VERSION,
4453 /* .OperationRegistrationCount = */ RT_ELEMENTS(s_aObOperations),
4454 /* .Altitude.Length = */ 0,
4455 /* .Altitude.MaximumLength = */ 0,
4456 /* .Altitude.Buffer = */ NULL,
4457 /* .RegistrationContext = */ NULL,
4458 /* .OperationRegistration = */ &s_aObOperations[0]
4459 };
4460 static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
4461 {
4462 L"48596.98940", L"46935.19485", L"49739.39704", L"40334.74976",
4463 L"66667.98940", L"69888.19485", L"69889.39704", L"60364.74976",
4464 L"85780.98940", L"88978.19485", L"89939.39704", L"80320.74976",
4465 L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
4466 };
4467
4468 rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
4469 for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
4470 {
4471 s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
4472 s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
4473 s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
4474
4475 rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
4476 if (NT_SUCCESS(rcNt))
4477 {
4478 /*
4479 * Happy ending.
4480 */
4481 return STATUS_SUCCESS;
4482 }
4483 }
4484 LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
4485 g_pvObCallbacksCookie = NULL;
4486 }
4487 else
4488 {
4489 /*
4490 * For the time being, we do not implement extra process
4491 * protection on pre-Vista-SP1 systems as they are lacking
4492 * necessary KPIs. XP is end of life, we do not wish to
4493 * spend more time on it, so we don't put up a fuss there.
4494 * Vista users without SP1 can install SP1 (or later), darn it,
4495 * so refuse to load.
4496 */
4497 /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
4498 * stuff to a couple of object types. */
4499# ifndef VBOX_WITH_VISTA_NO_SP
4500 if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
4501# else
4502 if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
4503# endif
4504 {
4505 DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
4506 rcNt = STATUS_SXS_VERSION_CONFLICT;
4507 }
4508 else
4509 {
4510 Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
4511 return rcNt = STATUS_SUCCESS;
4512 }
4513 g_pvObCallbacksCookie = NULL;
4514 }
4515
4516 /*
4517 * Drop process create/term notifications.
4518 */
4519 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
4520 g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
4521 else
4522 PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
4523 }
4524 else
4525 LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
4526 g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
4527 supHardenedWinTermImageVerifier();
4528 }
4529 else
4530 rcNt = VBoxDrvNtErr2NtStatus(rc);
4531
4532 RTSemMutexDestroy(g_hErrorInfoLock);
4533 g_hErrorInfoLock = NIL_RTSEMMUTEX;
4534 }
4535 else
4536 rcNt = VBoxDrvNtErr2NtStatus(rc);
4537
4538 RTSpinlockDestroy(g_hNtProtectLock);
4539 g_NtProtectTree = NIL_RTSPINLOCK;
4540 return rcNt;
4541}
4542
4543#endif /* VBOX_WITH_HARDENING */
4544
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