VirtualBox

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

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

SUPDrv-win.cpp: Make sure we don't call ExFreePoolWithTag with a NULL pointer and make sure the request header didn't changed.

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