VirtualBox

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

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

windows hardning error reporting improvements.

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