OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // Implementation of PreamblePatcher | |
6 | |
7 #include "sandbox/win/src/sidestep/preamble_patcher.h" | |
8 | |
9 #include <stddef.h> | |
10 | |
11 #include "sandbox/win/src/sandbox_nt_util.h" | |
12 #include "sandbox/win/src/sidestep/mini_disassembler.h" | |
13 | |
14 // Definitions of assembly statements we need | |
15 #define ASM_JMP32REL 0xE9 | |
16 #define ASM_INT3 0xCC | |
17 | |
18 namespace { | |
19 | |
20 // Very basic memcpy. We are copying 4 to 12 bytes most of the time, so there | |
21 // is no attempt to optimize this code or have a general purpose function. | |
22 // We don't want to call the crt from this code. | |
23 inline void* RawMemcpy(void* destination, const void* source, size_t bytes) { | |
24 const char* from = reinterpret_cast<const char*>(source); | |
25 char* to = reinterpret_cast<char*>(destination); | |
26 | |
27 for (size_t i = 0; i < bytes ; i++) | |
28 to[i] = from[i]; | |
29 | |
30 return destination; | |
31 } | |
32 | |
33 // Very basic memset. We are filling 1 to 7 bytes most of the time, so there | |
34 // is no attempt to optimize this code or have a general purpose function. | |
35 // We don't want to call the crt from this code. | |
36 inline void* RawMemset(void* destination, int value, size_t bytes) { | |
37 char* to = reinterpret_cast<char*>(destination); | |
38 | |
39 for (size_t i = 0; i < bytes ; i++) | |
40 to[i] = static_cast<char>(value); | |
41 | |
42 return destination; | |
43 } | |
44 | |
45 } // namespace | |
46 | |
47 #define ASSERT(a, b) DCHECK_NT(a) | |
48 | |
49 namespace sidestep { | |
50 | |
51 SideStepError PreamblePatcher::RawPatchWithStub( | |
52 void* target_function, | |
53 void* replacement_function, | |
54 unsigned char* preamble_stub, | |
55 size_t stub_size, | |
56 size_t* bytes_needed) { | |
57 if ((NULL == target_function) || | |
58 (NULL == replacement_function) || | |
59 (NULL == preamble_stub)) { | |
60 ASSERT(false, (L"Invalid parameters - either pTargetFunction or " | |
61 L"pReplacementFunction or pPreambleStub were NULL.")); | |
62 return SIDESTEP_INVALID_PARAMETER; | |
63 } | |
64 | |
65 // TODO(V7:joi) Siggi and I just had a discussion and decided that both | |
66 // patching and unpatching are actually unsafe. We also discussed a | |
67 // method of making it safe, which is to freeze all other threads in the | |
68 // process, check their thread context to see if their eip is currently | |
69 // inside the block of instructions we need to copy to the stub, and if so | |
70 // wait a bit and try again, then unfreeze all threads once we've patched. | |
71 // Not implementing this for now since we're only using SideStep for unit | |
72 // testing, but if we ever use it for production code this is what we | |
73 // should do. | |
74 // | |
75 // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using | |
76 // FPU instructions, and on newer processors we could use cmpxchg8b or | |
77 // cmpxchg16b. So it might be possible to do the patching/unpatching | |
78 // atomically and avoid having to freeze other threads. Note though, that | |
79 // doing it atomically does not help if one of the other threads happens | |
80 // to have its eip in the middle of the bytes you change while you change | |
81 // them. | |
82 unsigned char* target = reinterpret_cast<unsigned char*>(target_function); | |
83 | |
84 // Let's disassemble the preamble of the target function to see if we can | |
85 // patch, and to see how much of the preamble we need to take. We need 5 | |
86 // bytes for our jmp instruction, so let's find the minimum number of | |
87 // instructions to get 5 bytes. | |
88 MiniDisassembler disassembler; | |
89 unsigned int preamble_bytes = 0; | |
90 while (preamble_bytes < 5) { | |
91 InstructionType instruction_type = | |
92 disassembler.Disassemble(target + preamble_bytes, &preamble_bytes); | |
93 if (IT_JUMP == instruction_type) { | |
94 ASSERT(false, (L"Unable to patch because there is a jump instruction " | |
95 L"in the first 5 bytes.")); | |
96 return SIDESTEP_JUMP_INSTRUCTION; | |
97 } else if (IT_RETURN == instruction_type) { | |
98 ASSERT(false, (L"Unable to patch because function is too short")); | |
99 return SIDESTEP_FUNCTION_TOO_SMALL; | |
100 } else if (IT_GENERIC != instruction_type) { | |
101 ASSERT(false, (L"Disassembler encountered unsupported instruction " | |
102 L"(either unused or unknown")); | |
103 return SIDESTEP_UNSUPPORTED_INSTRUCTION; | |
104 } | |
105 } | |
106 | |
107 if (NULL != bytes_needed) | |
108 *bytes_needed = preamble_bytes + 5; | |
109 | |
110 // Inv: preamble_bytes is the number of bytes (at least 5) that we need to | |
111 // take from the preamble to have whole instructions that are 5 bytes or more | |
112 // in size total. The size of the stub required is cbPreamble + size of | |
113 // jmp (5) | |
114 if (preamble_bytes + 5 > stub_size) { | |
115 NOTREACHED_NT(); | |
116 return SIDESTEP_INSUFFICIENT_BUFFER; | |
117 } | |
118 | |
119 // First, copy the preamble that we will overwrite. | |
120 RawMemcpy(reinterpret_cast<void*>(preamble_stub), | |
121 reinterpret_cast<void*>(target), preamble_bytes); | |
122 | |
123 // Now, make a jmp instruction to the rest of the target function (minus the | |
124 // preamble bytes we moved into the stub) and copy it into our preamble-stub. | |
125 // find address to jump to, relative to next address after jmp instruction | |
126 #pragma warning(push) | |
127 #pragma warning(disable:4244) | |
128 // This assignment generates a warning because it is 32 bit specific. | |
129 int relative_offset_to_target_rest | |
130 = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) - | |
131 (preamble_stub + preamble_bytes + 5)); | |
132 #pragma warning(pop) | |
133 // jmp (Jump near, relative, displacement relative to next instruction) | |
134 preamble_stub[preamble_bytes] = ASM_JMP32REL; | |
135 // copy the address | |
136 RawMemcpy(reinterpret_cast<void*>(preamble_stub + preamble_bytes + 1), | |
137 reinterpret_cast<void*>(&relative_offset_to_target_rest), 4); | |
138 | |
139 // Inv: preamble_stub points to assembly code that will execute the | |
140 // original function by first executing the first cbPreamble bytes of the | |
141 // preamble, then jumping to the rest of the function. | |
142 | |
143 // Overwrite the first 5 bytes of the target function with a jump to our | |
144 // replacement function. | |
145 // (Jump near, relative, displacement relative to next instruction) | |
146 target[0] = ASM_JMP32REL; | |
147 | |
148 // Find offset from instruction after jmp, to the replacement function. | |
149 #pragma warning(push) | |
150 #pragma warning(disable:4244) | |
151 int offset_to_replacement_function = | |
152 reinterpret_cast<unsigned char*>(replacement_function) - | |
153 reinterpret_cast<unsigned char*>(target) - 5; | |
154 #pragma warning(pop) | |
155 // complete the jmp instruction | |
156 RawMemcpy(reinterpret_cast<void*>(target + 1), | |
157 reinterpret_cast<void*>(&offset_to_replacement_function), 4); | |
158 // Set any remaining bytes that were moved to the preamble-stub to INT3 so | |
159 // as not to cause confusion (otherwise you might see some strange | |
160 // instructions if you look at the disassembly, or even invalid | |
161 // instructions). Also, by doing this, we will break into the debugger if | |
162 // some code calls into this portion of the code. If this happens, it | |
163 // means that this function cannot be patched using this patcher without | |
164 // further thought. | |
165 if (preamble_bytes > 5) { | |
166 RawMemset(reinterpret_cast<void*>(target + 5), ASM_INT3, | |
167 preamble_bytes - 5); | |
168 } | |
169 | |
170 // Inv: The memory pointed to by target_function now points to a relative | |
171 // jump instruction that jumps over to the preamble_stub. The preamble | |
172 // stub contains the first stub_size bytes of the original target | |
173 // function's preamble code, followed by a relative jump back to the next | |
174 // instruction after the first cbPreamble bytes. | |
175 | |
176 return SIDESTEP_SUCCESS; | |
177 } | |
178 | |
179 }; // namespace sidestep | |
180 | |
181 #undef ASSERT | |
OLD | NEW |