VirtualBox

source: vbox/trunk/src/VBox/VMM/PATM/PATMGuest.cpp@ 5458

Last change on this file since 5458 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.1 KB
Line 
1/* $Id: PATMGuest.cpp 4071 2007-08-07 17:07:59Z vboxsync $ */
2/** @file
3 * PATMGuest - Guest OS Patching Manager (non-generic)
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_PATM
22#include <VBox/patm.h>
23#include <VBox/stam.h>
24#include <VBox/pgm.h>
25#include <VBox/cpum.h>
26#include <VBox/iom.h>
27#include <VBox/sup.h>
28#include <VBox/mm.h>
29#include <VBox/ssm.h>
30#include <VBox/pdm.h>
31#include <VBox/trpm.h>
32#include <VBox/param.h>
33#include <iprt/avl.h>
34#include "PATMInternal.h"
35#include <VBox/vm.h>
36#include <VBox/csam.h>
37
38#include <VBox/dbg.h>
39#include <VBox/err.h>
40#include <VBox/log.h>
41#include <iprt/assert.h>
42#include <iprt/string.h>
43#include <VBox/dis.h>
44#include <VBox/disopcode.h>
45
46/*
47 * ntdll!KiFastSystemCall:
48 * 7c90eb8b 8bd4 mov edx,esp
49 * 7c90eb8d 0f34 sysenter
50 * 7c90eb8f 90 nop
51 * 7c90eb90 90 nop
52 * 7c90eb91 90 nop
53 * 7c90eb92 90 nop
54 * 7c90eb93 90 nop
55 * ntdll!KiFastSystemCallRet:
56 * 7c90eb94 c3 ret
57 *
58 * ntdll!KiIntSystemCall:
59 * 7c90eba5 8d542408 lea edx,[esp+0x8]
60 * 7c90eba9 cd2e int 2e
61 * 7c90ebab c3 ret
62 *
63 */
64static uint8_t uFnKiFastSystemCall[7] = {0x8b, 0xd4, 0x0f, 0x34, 0x90, 0x90, 0x90};
65static uint8_t uFnKiIntSystemCall[7] = {0x8d, 0x54, 0x24, 0x08, 0xcd, 0x2e, 0xc3};
66
67/*
68 * OpenBSD 3.7 & 3.8:
69 *
70 * D0101B6D: push CS [0E]
71 * D0101B6E: push ESI [56]
72 * D0101B6F: cli [FA]
73 */
74static uint8_t uFnOpenBSDHandlerPrefix1[3] = { 0x0E, 0x56, 0xFA };
75/*
76 * OpenBSD 3.9 & 4.0
77 *
78 * D0101BD1: push CS [0E]
79 * D0101BD2: push ESI [56]
80 * D0101BD3: push 0x00 [6A 00]
81 * D0101BD4: push 0x03 [6A 03]
82 */
83static uint8_t uFnOpenBSDHandlerPrefix2[6] = { 0x0E, 0x56, 0x6A, 0x00, 0x6A, 0x03 };
84
85
86/**
87 * Check Windows XP sysenter heuristics and install patch
88 *
89 * @returns VBox status code.
90 * @param pVM The VM to operate on.
91 * @param pInstrGC GC Instruction pointer for sysenter
92 * @param pPatchRec Patch structure
93 *
94 */
95int PATMPatchSysenterXP(PVM pVM, RTGCPTR pInstrGC, PPATMPATCHREC pPatchRec)
96{
97 PPATCHINFO pPatch = &pPatchRec->patch;
98 uint8_t uTemp[16];
99 RTGCPTR lpfnKiFastSystemCall, lpfnKiIntSystemCall = 0; /* (initializing it to shut up warning.) */
100 int rc, i;
101
102 Assert(sizeof(uTemp) > sizeof(uFnKiIntSystemCall));
103 Assert(sizeof(uTemp) > sizeof(uFnKiFastSystemCall));
104
105 /* Guest OS specific patch; check heuristics first */
106
107 /* check the epilog of KiFastSystemCall */
108 lpfnKiFastSystemCall = pInstrGC - 2;
109 rc = PGMPhysReadGCPtr(pVM, uTemp, lpfnKiFastSystemCall, sizeof(uFnKiFastSystemCall));
110 if ( VBOX_FAILURE(rc)
111 || memcmp(uFnKiFastSystemCall, uTemp, sizeof(uFnKiFastSystemCall)))
112 {
113 return VERR_PATCHING_REFUSED;
114 }
115
116 /* Now search for KiIntSystemCall */
117 for (i=0;i<64;i++)
118 {
119 rc = PGMPhysReadGCPtr(pVM, uTemp, pInstrGC + i, sizeof(uFnKiIntSystemCall));
120 if(VBOX_FAILURE(rc))
121 {
122 break;
123 }
124 if(!memcmp(uFnKiIntSystemCall, uTemp, sizeof(uFnKiIntSystemCall)))
125 {
126 lpfnKiIntSystemCall = pInstrGC + i;
127 /* Found it! */
128 break;
129 }
130 }
131 if (i == 64)
132 {
133 Log(("KiIntSystemCall not found!!\n"));
134 return VERR_PATCHING_REFUSED;
135 }
136
137 if (PAGE_ADDRESS(lpfnKiFastSystemCall) != PAGE_ADDRESS(lpfnKiIntSystemCall))
138 {
139 Log(("KiFastSystemCall and KiIntSystemCall not in the same page!!\n"));
140 return VERR_PATCHING_REFUSED;
141 }
142
143 // make a copy of the guest code bytes that will be overwritten
144 rc = PGMPhysReadGCPtr(pVM, pPatch->aPrivInstr, pPatch->pPrivInstrGC, SIZEOF_NEARJUMP32);
145 AssertRC(rc);
146
147 /* Now we simply jump from the fast version to the 'old and slow' system call */
148 uTemp[0] = 0xE9;
149 *(RTGCPTR *)&uTemp[1] = lpfnKiIntSystemCall - (pInstrGC + SIZEOF_NEARJUMP32);
150 rc = PGMPhysWriteGCPtrDirty(pVM, pInstrGC, uTemp, SIZEOF_NEARJUMP32);
151 if (VBOX_FAILURE(rc))
152 {
153 Log(("MMR3PhysWriteGCVirt failed with rc=%d!!\n", rc));
154 return VERR_PATCHING_REFUSED;
155 }
156
157#ifdef DEBUG
158 Log(("Sysenter Patch code ----------------------------------------------------------\n"));
159 patmr3DisasmCodeStream(pVM, pInstrGC, pInstrGC, patmr3DisasmCallback, pPatch);
160 Log(("Sysenter Patch code ends -----------------------------------------------------\n"));
161#endif
162
163 pPatch->uState = PATCH_ENABLED;
164 return VINF_SUCCESS;
165}
166
167/**
168 * Patch OpenBSD interrupt handler prefix
169 *
170 * @returns VBox status code.
171 * @param pVM The VM to operate on
172 * @param pCpu Disassembly state of instruction.
173 * @param pInstrGC GC Instruction pointer for instruction
174 * @param pInstrHC GC Instruction pointer for instruction
175 * @param pPatchRec Patch structure
176 *
177 */
178int PATMPatchOpenBSDHandlerPrefix(PVM pVM, PDISCPUSTATE pCpu, RTGCPTR pInstrGC, uint8_t *pInstrHC, PPATMPATCHREC pPatchRec)
179{
180 uint8_t uTemp[16];
181 int rc;
182
183 Assert(sizeof(uTemp) > RT_MAX(sizeof(uFnOpenBSDHandlerPrefix1), sizeof(uFnOpenBSDHandlerPrefix2)));
184
185 /* Guest OS specific patch; check heuristics first */
186
187 rc = PGMPhysReadGCPtr(pVM, uTemp, pInstrGC, RT_MAX(sizeof(uFnOpenBSDHandlerPrefix1), sizeof(uFnOpenBSDHandlerPrefix2)));
188 if ( VBOX_FAILURE(rc)
189 || ( memcmp(uFnOpenBSDHandlerPrefix1, uTemp, sizeof(uFnOpenBSDHandlerPrefix1))
190 && memcmp(uFnOpenBSDHandlerPrefix2, uTemp, sizeof(uFnOpenBSDHandlerPrefix2))))
191 {
192 return VERR_PATCHING_REFUSED;
193 }
194 /* Found it; patch the push cs */
195 pPatchRec->patch.flags &= ~(PATMFL_GUEST_SPECIFIC); /* prevent a breakpoint from being triggered */
196 return PATMR3PatchInstrInt3(pVM, pInstrGC, pInstrHC, pCpu, &pPatchRec->patch);
197}
198
199/**
200 * Install guest OS specific patch
201 *
202 * @returns VBox status code.
203 * @param pVM The VM to operate on
204 * @param pCpu Disassembly state of instruction.
205 * @param pInstrGC GC Instruction pointer for instruction
206 * @param pInstrHC GC Instruction pointer for instruction
207 * @param pCallerGC GC address of caller; CODE32_UNKNOWN_CALLER if unknown
208 * @param pPatchRec Patch structure
209 *
210 */
211int PATMInstallGuestSpecificPatch(PVM pVM, PDISCPUSTATE pCpu, RTGCPTR pInstrGC, uint8_t *pInstrHC, PPATMPATCHREC pPatchRec)
212{
213 int rc;
214
215 /** @todo might have to check if the patch crosses a page boundary. Currently not necessary, but that might change in the future!! */
216 switch (pCpu->pCurInstr->opcode)
217 {
218 case OP_SYSENTER:
219 pPatchRec->patch.flags |= PATMFL_SYSENTER_XP | PATMFL_USER_MODE | PATMFL_GUEST_SPECIFIC;
220
221 rc = PATMPatchSysenterXP(pVM, pInstrGC, pPatchRec);
222 if (VBOX_FAILURE(rc))
223 {
224 return VERR_PATCHING_REFUSED;
225 }
226 return VINF_SUCCESS;
227
228 case OP_PUSH:
229 /* OpenBSD guest specific patch for the following code block:
230 *
231 * pushf
232 * push cs <- dangerous because of DPL 0 tests
233 * push esi
234 * cli
235 */
236 if (pCpu->pCurInstr->param1 == OP_PARM_REG_CS)
237 return PATMPatchOpenBSDHandlerPrefix(pVM, pCpu, pInstrGC, pInstrHC, pPatchRec);
238
239 return VERR_PATCHING_REFUSED;
240
241 default:
242 AssertMsgFailed(("PATMInstallGuestSpecificPatch: unknown opcode %d\n", pCpu->pCurInstr->opcode));
243 return VERR_PATCHING_REFUSED;
244 }
245 return VERR_PATCHING_REFUSED;
246}
247
Note: See TracBrowser for help on using the repository browser.

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