VirtualBox

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

Last change on this file since 27184 was 26152, checked in by vboxsync, 15 years ago

VMM: pdm.h and @copydoc cleanups.

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