preamble_patcher_with_stub.cpp revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implementation of PreamblePatcher
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/sidestep/preamble_patcher.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/sandbox_nt_util.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/sidestep/mini_disassembler.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Definitions of assembly statements we need
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JMP32REL 0xE9
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_INT3 0xCC
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Very basic memcpy. We are copying 4 to 12 bytes most of the time, so there
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is no attempt to optimize this code or have a general purpose function.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We don't want to call the crt from this code.
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void* RawMemcpy(void* destination, const void* source, size_t bytes) {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* from = reinterpret_cast<const char*>(source);
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* to = reinterpret_cast<char*>(destination);
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < bytes ; i++)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    to[i] = from[i];
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return destination;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Very basic memset. We are filling 1 to 7 bytes most of the time, so there
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is no attempt to optimize this code or have a general purpose function.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We don't want to call the crt from this code.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void* RawMemset(void* destination, int value, size_t bytes) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* to = reinterpret_cast<char*>(destination);
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < bytes ; i++)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    to[i] = static_cast<char>(value);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return destination;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASSERT(a, b) DCHECK_NT(a)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace sidestep {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SideStepError PreamblePatcher::RawPatchWithStub(
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void* target_function,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void* replacement_function,
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* preamble_stub,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t stub_size,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t* bytes_needed) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((NULL == target_function) ||
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (NULL == replacement_function) ||
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (NULL == preamble_stub)) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT(false, (L"Invalid parameters - either pTargetFunction or "
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   L"pReplacementFunction or pPreambleStub were NULL."));
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SIDESTEP_INVALID_PARAMETER;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(V7:joi) Siggi and I just had a discussion and decided that both
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // patching and unpatching are actually unsafe.  We also discussed a
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // method of making it safe, which is to freeze all other threads in the
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // process, check their thread context to see if their eip is currently
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // inside the block of instructions we need to copy to the stub, and if so
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // wait a bit and try again, then unfreeze all threads once we've patched.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Not implementing this for now since we're only using SideStep for unit
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // testing, but if we ever use it for production code this is what we
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // should do.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // FPU instructions, and on newer processors we could use cmpxchg8b or
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cmpxchg16b. So it might be possible to do the patching/unpatching
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // atomically and avoid having to freeze other threads.  Note though, that
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // doing it atomically does not help if one of the other threads happens
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to have its eip in the middle of the bytes you change while you change
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // them.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* target = reinterpret_cast<unsigned char*>(target_function);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Let's disassemble the preamble of the target function to see if we can
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // patch, and to see how much of the preamble we need to take.  We need 5
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // bytes for our jmp instruction, so let's find the minimum number of
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // instructions to get 5 bytes.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MiniDisassembler disassembler;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int preamble_bytes = 0;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (preamble_bytes < 5) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InstructionType instruction_type =
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      disassembler.Disassemble(target + preamble_bytes, &preamble_bytes);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IT_JUMP == instruction_type) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ASSERT(false, (L"Unable to patch because there is a jump instruction "
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     L"in the first 5 bytes."));
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return SIDESTEP_JUMP_INSTRUCTION;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (IT_RETURN == instruction_type) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ASSERT(false, (L"Unable to patch because function is too short"));
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return SIDESTEP_FUNCTION_TOO_SMALL;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (IT_GENERIC != instruction_type) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ASSERT(false, (L"Disassembler encountered unsupported instruction "
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     L"(either unused or unknown"));
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return SIDESTEP_UNSUPPORTED_INSTRUCTION;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL != bytes_needed)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *bytes_needed = preamble_bytes + 5;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Inv: preamble_bytes is the number of bytes (at least 5) that we need to
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // take from the preamble to have whole instructions that are 5 bytes or more
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in size total. The size of the stub required is cbPreamble + size of
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // jmp (5)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (preamble_bytes + 5 > stub_size) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED_NT();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SIDESTEP_INSUFFICIENT_BUFFER;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First, copy the preamble that we will overwrite.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RawMemcpy(reinterpret_cast<void*>(preamble_stub),
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            reinterpret_cast<void*>(target), preamble_bytes);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now, make a jmp instruction to the rest of the target function (minus the
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // preamble bytes we moved into the stub) and copy it into our preamble-stub.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // find address to jump to, relative to next address after jmp instruction
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(push)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(disable:4244)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This assignment generates a warning because it is 32 bit specific.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int relative_offset_to_target_rest
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) -
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (preamble_stub + preamble_bytes + 5));
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(pop)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // jmp (Jump near, relative, displacement relative to next instruction)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preamble_stub[preamble_bytes] = ASM_JMP32REL;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // copy the address
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RawMemcpy(reinterpret_cast<void*>(preamble_stub + preamble_bytes + 1),
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            reinterpret_cast<void*>(&relative_offset_to_target_rest), 4);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Inv: preamble_stub points to assembly code that will execute the
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // original function by first executing the first cbPreamble bytes of the
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // preamble, then jumping to the rest of the function.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Overwrite the first 5 bytes of the target function with a jump to our
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // replacement function.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (Jump near, relative, displacement relative to next instruction)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  target[0] = ASM_JMP32REL;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find offset from instruction after jmp, to the replacement function.
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(push)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(disable:4244)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int offset_to_replacement_function =
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reinterpret_cast<unsigned char*>(replacement_function) -
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reinterpret_cast<unsigned char*>(target) - 5;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(pop)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // complete the jmp instruction
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RawMemcpy(reinterpret_cast<void*>(target + 1),
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            reinterpret_cast<void*>(&offset_to_replacement_function), 4);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set any remaining bytes that were moved to the preamble-stub to INT3 so
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // as not to cause confusion (otherwise you might see some strange
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // instructions if you look at the disassembly, or even invalid
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // instructions). Also, by doing this, we will break into the debugger if
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // some code calls into this portion of the code.  If this happens, it
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // means that this function cannot be patched using this patcher without
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // further thought.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (preamble_bytes > 5) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RawMemset(reinterpret_cast<void*>(target + 5), ASM_INT3,
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              preamble_bytes - 5);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Inv: The memory pointed to by target_function now points to a relative
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // jump instruction that jumps over to the preamble_stub.  The preamble
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // stub contains the first stub_size bytes of the original target
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // function's preamble code, followed by a relative jump back to the next
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // instruction after the first cbPreamble bytes.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SIDESTEP_SUCCESS;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};  // namespace sidestep
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef ASSERT
180