VirtualBox

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

Last change on this file since 62596 was 62478, checked in by vboxsync, 8 years ago

(C) 2016

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