VirtualBox

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

Last change on this file since 1 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.8 KB
Line 
1/** @file
2 *
3 * PATMGuest - Guest OS Patching Manager (non-generic)
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung 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 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_PATM
26#include <VBox/patm.h>
27#include <VBox/stam.h>
28#include <VBox/pgm.h>
29#include <VBox/cpum.h>
30#include <VBox/iom.h>
31#include <VBox/sup.h>
32#include <VBox/mm.h>
33#include <VBox/ssm.h>
34#include <VBox/pdm.h>
35#include <VBox/trpm.h>
36#include <VBox/param.h>
37#include <iprt/avl.h>
38#include "PATMInternal.h"
39#include <VBox/vm.h>
40#include <VBox/csam.h>
41
42#include <VBox/dbg.h>
43#include <VBox/err.h>
44#include <VBox/log.h>
45#include <iprt/assert.h>
46#include <VBox/dis.h>
47#include <VBox/disopcode.h>
48#include <string.h>
49
50/*
51 * ntdll!KiFastSystemCall:
52 * 7c90eb8b 8bd4 mov edx,esp
53 * 7c90eb8d 0f34 sysenter
54 * 7c90eb8f 90 nop
55 * 7c90eb90 90 nop
56 * 7c90eb91 90 nop
57 * 7c90eb92 90 nop
58 * 7c90eb93 90 nop
59 * ntdll!KiFastSystemCallRet:
60 * 7c90eb94 c3 ret
61 *
62 * ntdll!KiIntSystemCall:
63 * 7c90eba5 8d542408 lea edx,[esp+0x8]
64 * 7c90eba9 cd2e int 2e
65 * 7c90ebab c3 ret
66 *
67 */
68static uint8_t uFnKiFastSystemCall[7] = {0x8b, 0xd4, 0x0f, 0x34, 0x90, 0x90, 0x90};
69static uint8_t uFnKiIntSystemCall[7] = {0x8d, 0x54, 0x24, 0x08, 0xcd, 0x2e, 0xc3};
70
71/*
72 * D0101B6C: pushf [9C]
73 * D0101B6D: push CS [0E]
74 * D0101B6E: push ESI [56]
75 * D0101B6F: cli [FA]
76 */
77static uint8_t uFnOpenBSDHandlerPrefix[4] = { 0x9C, 0x0E, 0x56, 0xFA };
78
79
80/**
81 * Check Windows XP sysenter heuristics and install patch
82 *
83 * @returns VBox status code.
84 * @param pVM The VM to operate on.
85 * @param pInstrGC GC Instruction pointer for sysenter
86 * @param pPatchRec Patch structure
87 *
88 */
89int PATMPatchSysenterXP(PVM pVM, RTGCPTR pInstrGC, PPATMPATCHREC pPatchRec)
90{
91 PPATCHINFO pPatch = &pPatchRec->patch;
92 uint8_t uTemp[16];
93 RTGCPTR lpfnKiFastSystemCall, lpfnKiIntSystemCall = 0; /* (initializing it to shut up warning.) */
94 int rc, i;
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 = PGMPhysReadGCPtr(pVM, uTemp, lpfnKiFastSystemCall, sizeof(uFnKiFastSystemCall));
104 if ( VBOX_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 = PGMPhysReadGCPtr(pVM, uTemp, pInstrGC + i, sizeof(uFnKiIntSystemCall));
114 if(VBOX_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 = PGMPhysReadGCPtr(pVM, 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 *(RTGCPTR *)&uTemp[1] = lpfnKiIntSystemCall - (pInstrGC + SIZEOF_NEARJUMP32);
144 rc = PGMPhysWriteGCPtrDirty(pVM, pInstrGC, uTemp, SIZEOF_NEARJUMP32);
145 if (VBOX_FAILURE(rc))
146 {
147 Log(("MMR3PhysWriteGCVirt failed with rc=%d!!\n", rc));
148 return VERR_PATCHING_REFUSED;
149 }
150
151#ifdef DEBUG
152 Log(("Sysenter Patch code ----------------------------------------------------------\n"));
153 patmr3DisasmCodeStream(pVM, pInstrGC, pInstrGC, patmr3DisasmCallback, pPatch);
154 Log(("Sysenter Patch code ends -----------------------------------------------------\n"));
155#endif
156
157 pPatch->uState = PATCH_ENABLED;
158 return VINF_SUCCESS;
159}
160
161/**
162 * Patch OpenBSD interrupt handler prefix
163 *
164 * @returns VBox status code.
165 * @param pVM The VM to operate on
166 * @param pCpu Disassembly state of instruction.
167 * @param pInstrGC GC Instruction pointer for instruction
168 * @param pInstrHC GC Instruction pointer for instruction
169 * @param pPatchRec Patch structure
170 *
171 */
172int PATMPatchOpenBSDHandlerPrefix(PVM pVM, PDISCPUSTATE pCpu, RTGCPTR pInstrGC, uint8_t *pInstrHC, PPATMPATCHREC pPatchRec)
173{
174 uint8_t uTemp[16];
175 int rc;
176
177 Assert(sizeof(uTemp) > sizeof(uFnOpenBSDHandlerPrefix));
178
179 /* Guest OS specific patch; check heuristics first */
180
181 rc = PGMPhysReadGCPtr(pVM, uTemp, pInstrGC, sizeof(uFnOpenBSDHandlerPrefix));
182 if (VBOX_FAILURE(rc) || memcmp(uFnOpenBSDHandlerPrefix, uTemp, sizeof(uFnOpenBSDHandlerPrefix)))
183 {
184 return VERR_PATCHING_REFUSED;
185 }
186 /* Found it; patch the pushf block (including push cs) */
187 pPatchRec->patch.flags &= ~(PATMFL_GUEST_SPECIFIC); /* prevent a breakpoint from being triggered */
188 return PATMR3PatchBlock(pVM, pInstrGC, pInstrHC, pCpu->pCurInstr->opcode, pCpu->opsize, pPatchRec);
189}
190
191/**
192 * Install guest OS specific patch
193 *
194 * @returns VBox status code.
195 * @param pVM The VM to operate on
196 * @param pCpu Disassembly state of instruction.
197 * @param pInstrGC GC Instruction pointer for instruction
198 * @param pInstrHC GC Instruction pointer for instruction
199 * @param pCallerGC GC address of caller; CODE32_UNKNOWN_CALLER if unknown
200 * @param pPatchRec Patch structure
201 *
202 */
203int PATMInstallGuestSpecificPatch(PVM pVM, PDISCPUSTATE pCpu, RTGCPTR pInstrGC, uint8_t *pInstrHC, PPATMPATCHREC pPatchRec)
204{
205 int rc;
206
207 /** @todo might have to check if the patch crosses a page boundary. Currently not necessary, but that might change in the future!! */
208 switch (pCpu->pCurInstr->opcode)
209 {
210 case OP_SYSENTER:
211 pPatchRec->patch.flags |= PATMFL_SYSENTER_XP | PATMFL_USER_MODE | PATMFL_GUEST_SPECIFIC;
212
213 rc = PATMPatchSysenterXP(pVM, pInstrGC, pPatchRec);
214 if (VBOX_FAILURE(rc))
215 {
216 return VERR_PATCHING_REFUSED;
217 }
218 return VINF_SUCCESS;
219
220 case OP_PUSHF:
221 /* OpenBSD guest specific patch for the following code block:
222 *
223 * pushf
224 * push cs <- dangerous because of DPL 0 tests
225 * push esi
226 * cli
227 */
228 return PATMPatchOpenBSDHandlerPrefix(pVM, pCpu, pInstrGC, pInstrHC, pPatchRec);
229
230 default:
231 AssertMsgFailed(("PATMInstallGuestSpecificPatch: unknown opcode %d\n", pCpu->pCurInstr->opcode));
232 return VERR_PATCHING_REFUSED;
233 }
234 return VERR_PATCHING_REFUSED;
235}
236
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