VirtualBox

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

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

SUPDrv: Modified SUP_IOCTL_LDR_LOAD to return an error string, major support driver version bump, and removed the long obsolete VMMR0EntryInt.

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