VirtualBox

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

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

*: scm cleanup run.

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

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