security/sandbox/win/src/sidestep/preamble_patcher_with_stub.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial