VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PATMGuest.cpp@ 39034

Last change on this file since 39034 was 35348, checked in by vboxsync, 14 years ago

VMM reorg: Moving PATM to where the other VMM sources are.

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