VirtualBox

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

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

Temporarily disabled delta calculations on windows.

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