Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(426)

Side by Side Diff: sandbox/src/sidestep/preamble_patcher_with_stub.cpp

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

Powered by Google App Engine
This is Rietveld 408576698