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

Unified Diff: chrome_frame/function_stub.cc

Issue 992008: Reimplementation of FunctionStub, to avoid rewriting potentially executing co... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 9 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome_frame/function_stub.h ('k') | chrome_frame/function_stub_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome_frame/function_stub.cc
===================================================================
--- chrome_frame/function_stub.cc (revision 0)
+++ chrome_frame/function_stub.cc (revision 0)
@@ -0,0 +1,141 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "chrome_frame/function_stub.h"
+
+#include <new>
+#include "base/lock.h"
+#include "base/logging.h"
+
+#ifndef _M_IX86
+#error Only x86 supported right now.
+#endif
+
+namespace {
+typedef enum AsmConstants {
+ POP_EAX = 0x58,
+ PUSH_IND = 0x35ff,
+ PUSH_EAX = 0x50,
+ JUMP_IND = 0x25ff,
+};
+
+// A quick and dirty wrapper class that allows us to defer allocating
+// the executable heap until first use, and to release it teardown.
+class ExecutableHeap {
+ public:
+ ExecutableHeap() : heap_(NULL) {
+ }
+
+ ~ExecutableHeap() {
+ if (heap_ != NULL) {
+ BOOL ret = ::HeapDestroy(heap_);
+ heap_ = NULL;
+ }
+ }
+
+ void* Allocate(size_t size) {
+ if (!heap_)
+ CreateHeap();
+
+ DCHECK(heap_);
+
+ return ::HeapAlloc(heap_, 0, size);
+ }
+
+ void Free(void* ptr) {
+ DCHECK(heap_ != NULL);
+ ::HeapFree(heap_, 0, ptr);
+ }
+
+ void CreateHeap() {
+ AutoLock lock(init_lock_);
+
+ if (heap_ == NULL)
+ heap_ = ::HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
+ }
+
+ private:
+ Lock init_lock_;
+ HANDLE heap_;
+};
+
+// Our executable heap instance, all stubs are allocated from here.
+ExecutableHeap heap_;
+
+} // namespace
+
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+
+bool FunctionStub::is_valid() const {
+ return signature_ == reinterpret_cast<HMODULE>(&__ImageBase) &&
+ !is_bypassed();
+}
+
+FunctionStub::FunctionStub(uintptr_t extra_argument, void* dest)
+ : signature_(reinterpret_cast<HMODULE>(&__ImageBase)),
+ argument_(extra_argument),
+ destination_function_(reinterpret_cast<uintptr_t>(dest)) {
+ bypass_address_ = reinterpret_cast<uintptr_t>(&stub_.pop_return_addr_);
+ Init(&stub_);
+}
+
+FunctionStub::~FunctionStub() {
+}
+
+void FunctionStub::Init(FunctionStubAsm* stub) {
+ DCHECK(stub != NULL);
+
+ stub->jump_to_bypass_ = JUMP_IND;
+ stub->bypass_target_addr_ = reinterpret_cast<uintptr_t>(&bypass_address_);
+ stub->pop_return_addr_ = POP_EAX;
+ stub->push_ = PUSH_IND;
+ stub->arg_addr_ = reinterpret_cast<uintptr_t>(&argument_);
+ stub->push_return_addr_ = PUSH_EAX;
+ stub->jump_to_target = JUMP_IND;
+ stub->target_addr_ = reinterpret_cast<uintptr_t>(&destination_function_);
+
+ // Flush the instruction cache for the newly written code.
+ BOOL ret = ::FlushInstructionCache(::GetCurrentProcess(),
+ stub,
+ sizeof(*stub));
+}
+
+void FunctionStub::BypassStub(void* new_target) {
+ set_bypass_address(reinterpret_cast<uintptr_t>(new_target));
+}
+
+FunctionStub* FunctionStub::Create(uintptr_t extra_argument, void* dest) {
+ DCHECK(dest);
+ FunctionStub* stub =
+ reinterpret_cast<FunctionStub*>(heap_.Allocate(sizeof(FunctionStub)));
+
+ if (stub != NULL)
+ new (stub) FunctionStub(extra_argument, dest);
+
+ return stub;
+}
+
+FunctionStub* FunctionStub::FromCode(void* address) {
+ // Address points to arbitrary code here, which may e.g.
+ // lie at the end of an executable segment, which in turn
+ // may terminate earlier than the last address we probe.
+ // We therefore execute under an SEH, so as not to crash
+ // on failed probes.
+ __try {
+ // Retrieve the candidata function stub.
+ FunctionStub* candidate = CONTAINING_RECORD(address, FunctionStub, stub_);
+ if (candidate->stub_.jump_to_bypass_ == JUMP_IND &&
+ candidate->signature_ == reinterpret_cast<HMODULE>(&__ImageBase)) {
+ return candidate;
+ }
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+ }
+
+ return NULL;
+}
+
+bool FunctionStub::Destroy(FunctionStub* stub) {
+ heap_.Free(stub);
+
+ return true;
+}
Property changes on: chrome_frame\function_stub.cc
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « chrome_frame/function_stub.h ('k') | chrome_frame/function_stub_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698