summaryrefslogtreecommitdiffstats
path: root/sandbox
diff options
context:
space:
mode:
authorrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-29 00:24:26 +0000
committerrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-29 00:24:26 +0000
commitddcd5e3b2cd813bc21befe70f8faf6eb65dd3829 (patch)
treeab310abd6ace427cf08c315ec549d4e64f429059 /sandbox
parentaac2c87d5100f23b869435387d55938e70ae8d34 (diff)
downloadchromium_src-ddcd5e3b2cd813bc21befe70f8faf6eb65dd3829.zip
chromium_src-ddcd5e3b2cd813bc21befe70f8faf6eb65dd3829.tar.gz
chromium_src-ddcd5e3b2cd813bc21befe70f8faf6eb65dd3829.tar.bz2
Sandbox: Add the base code for the 46-bit service resolver.
BUG=27218 TEST=none Review URL: http://codereview.chromium.org/552223 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37468 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox')
-rw-r--r--sandbox/sandbox.gyp6
-rw-r--r--sandbox/src/service_resolver_64.cc299
2 files changed, 304 insertions, 1 deletions
diff --git a/sandbox/sandbox.gyp b/sandbox/sandbox.gyp
index 58f0059..85bd6b3 100644
--- a/sandbox/sandbox.gyp
+++ b/sandbox/sandbox.gyp
@@ -76,6 +76,7 @@
'src/sandbox.cc',
'src/sandbox.h',
'src/security_level.h',
+ 'src/service_resolver.h',
'src/shared_handles.cc',
'src/shared_handles.h',
'src/sid.cc',
@@ -207,7 +208,6 @@
'src/registry_interception.cc',
'src/registry_interception.h',
'src/service_resolver.cc',
- 'src/service_resolver.h',
'src/sharedmem_ipc_client.cc',
'src/sharedmem_ipc_client.h',
'src/sharedmem_ipc_server.cc',
@@ -263,6 +263,10 @@
},
},
'msvs_guid': 'BE3468E6-B314-4310-B449-6FC0C52EE155',
+ 'sources': [
+ # Files that are used by the 64-bit version of Windows sandbox only.
+ 'src/service_resolver_64.cc',
+ ],
'include_dirs': [
'..',
],
diff --git a/sandbox/src/service_resolver_64.cc b/sandbox/src/service_resolver_64.cc
new file mode 100644
index 0000000..3a46d73
--- /dev/null
+++ b/sandbox/src/service_resolver_64.cc
@@ -0,0 +1,299 @@
+// Copyright (c) 2006-2010 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 "sandbox/wow_helper/service64_resolver.h"
+
+#include "base/scoped_ptr.h"
+#include "sandbox/wow_helper/target_code.h"
+
+namespace {
+#pragma pack(push, 1)
+
+const BYTE kMovEax = 0xB8;
+const BYTE kMovEdx = 0xBA;
+const USHORT kCallPtrEdx = 0x12FF;
+const BYTE kRet = 0xC2;
+const BYTE kNop = 0x90;
+const USHORT kJmpEdx = 0xE2FF;
+const USHORT kXorEcx = 0xC933;
+const ULONG kLeaEdx = 0x0424548D;
+const ULONG kCallFs1 = 0xC015FF64;
+const ULONG kCallFs2Ret = 0xC2000000;
+const BYTE kPopEdx = 0x5A;
+const BYTE kPushEdx = 0x52;
+const BYTE kPush32 = 0x68;
+
+const ULONG kMmovR10EcxMovEax = 0xB8D18B4C;
+const USHORT kSyscall = 0x050F;
+const BYTE kRetNp = 0xC3;
+const BYTE kPad = 0x66;
+const USHORT kNop16 = 0x9066;
+const BYTE kRelJmp = 0xE9;
+
+const ULONG kXorRaxMovEax = 0xB8C03148;
+const ULONG kSaveRcx = 0x10488948;
+const ULONG kMovRcxRaxJmp = 0xE9C88B48;
+
+// Service code for 64 bit systems.
+struct ServiceEntry {
+ // this struct contains roughly the following code:
+ // mov r10,rcx
+ // mov eax,52h
+ // syscall
+ // ret
+ // xchg ax,ax
+ // xchg ax,ax
+
+ ULONG mov_r10_ecx_mov_eax; // = 4C 8B D1 B8
+ ULONG service_id;
+ USHORT syscall; // = 0F 05
+ BYTE ret; // = C3
+ BYTE pad; // = 66
+ USHORT xchg_ax_ax1; // = 66 90
+ USHORT xchg_ax_ax2; // = 66 90
+};
+
+struct Redirected {
+ // this struct contains roughly the following code:
+ // jmp relative_32
+ // xchg ax,ax // 3 byte nop
+
+ Redirected() {
+ jmp = kRelJmp;
+ relative = 0;
+ pad = kPad;
+ xchg_ax_ax = kNop16;
+ };
+ BYTE jmp; // = E9
+ ULONG relative;
+ BYTE pad; // = 66
+ USHORT xchg_ax_ax; // = 66 90
+};
+
+struct InternalThunk {
+ // this struct contains roughly the following code:
+ // xor rax,rax
+ // mov eax, 0x00080000 // Thunk storage.
+ // mov [rax]PatchInfo.service, rcx // Save first argument.
+ // mov rcx, rax
+ // jmp relative_to_interceptor
+
+ InternalThunk() {
+ xor_rax_mov_eax = kXorRaxMovEax;
+ patch_info = 0;
+ save_rcx = kSaveRcx;
+ mov_rcx_rax_jmp = kMovRcxRaxJmp;
+ relative = 0;
+ };
+ ULONG xor_rax_mov_eax; // = 48 31 C0 B8
+ ULONG patch_info;
+ ULONG save_rcx; // = 48 89 48 10
+ ULONG mov_rcx_rax_jmp; // = 48 8b c8 e9
+ ULONG relative;
+};
+
+struct ServiceFullThunk {
+ sandbox::PatchInfo patch_info;
+ ServiceEntry original;
+ InternalThunk internal_thunk;
+};
+
+#pragma pack(pop)
+
+// Simple utility function to write to a buffer on the child, if the memery has
+// write protection attributes.
+// Arguments:
+// child_process (in): process to write to.
+// address (out): memory position on the child to write to.
+// buffer (in): local buffer with the data to write .
+// length (in): number of bytes to write.
+// Returns true on success.
+bool WriteProtectedChildMemory(HANDLE child_process,
+ void* address,
+ const void* buffer,
+ size_t length) {
+ // first, remove the protections
+ DWORD old_protection;
+ if (!::VirtualProtectEx(child_process, address, length,
+ PAGE_WRITECOPY, &old_protection))
+ return false;
+
+ SIZE_T written;
+ bool ok = ::WriteProcessMemory(child_process, address, buffer, length,
+ &written) && (length == written);
+
+ // always attempt to restore the original protection
+ if (!::VirtualProtectEx(child_process, address, length,
+ old_protection, &old_protection))
+ return false;
+
+ return ok;
+}
+
+// Get pointers to the functions that we need from ntdll.dll.
+NTSTATUS ResolveNtdll(sandbox::PatchInfo* patch_info) {
+ wchar_t* ntdll_name = L"ntdll.dll";
+ HMODULE ntdll = ::GetModuleHandle(ntdll_name);
+ if (!ntdll)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ void* signal = ::GetProcAddress(ntdll, "NtSignalAndWaitForSingleObject");
+ if (!signal)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ patch_info->signal_and_wait =
+ reinterpret_cast<NtSignalAndWaitForSingleObjectFunction>(signal);
+
+ return STATUS_SUCCESS;
+}
+
+}; // namespace
+
+namespace sandbox {
+
+NTSTATUS Service64ResolverThunk::Setup(const void* target_module,
+ const void* interceptor_module,
+ const char* target_name,
+ const char* interceptor_name,
+ const void* interceptor_entry_point,
+ void* thunk_storage,
+ size_t storage_bytes,
+ size_t* storage_used) {
+ NTSTATUS ret = Init(target_module, interceptor_module, target_name,
+ interceptor_name, interceptor_entry_point,
+ thunk_storage, storage_bytes);
+ if (!NT_SUCCESS(ret))
+ return ret;
+
+ size_t thunk_bytes = GetThunkSize();
+ scoped_array<char> thunk_buffer(new char[thunk_bytes]);
+ ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>(
+ thunk_buffer.get());
+
+ if (!IsFunctionAService(&thunk->original))
+ return STATUS_UNSUCCESSFUL;
+
+ ret = PerformPatch(thunk, thunk_storage);
+
+ if (NULL != storage_used)
+ *storage_used = thunk_bytes;
+
+ return ret;
+}
+
+NTSTATUS Service64ResolverThunk::ResolveInterceptor(
+ const void* interceptor_module,
+ const char* interceptor_name,
+ const void** address) {
+ // After all, we are using a locally mapped version of the exe, so the
+ // action is the same as for a target function.
+ return ResolveTarget(interceptor_module, interceptor_name,
+ const_cast<void**>(address));
+}
+
+// In this case all the work is done from the parent, so resolve is
+// just a simple GetProcAddress.
+NTSTATUS Service64ResolverThunk::ResolveTarget(const void* module,
+ const char* function_name,
+ void** address) {
+ if (NULL == module)
+ return STATUS_UNSUCCESSFUL;
+
+ *address = ::GetProcAddress(bit_cast<HMODULE>(module), function_name);
+
+ if (NULL == *address)
+ return STATUS_UNSUCCESSFUL;
+
+ return STATUS_SUCCESS;
+}
+
+size_t Service64ResolverThunk::GetThunkSize() const {
+ return sizeof(ServiceFullThunk);
+}
+
+bool Service64ResolverThunk::IsFunctionAService(void* local_thunk) const {
+ ServiceEntry function_code;
+ SIZE_T read;
+ if (!::ReadProcessMemory(process_, target_, &function_code,
+ sizeof(function_code), &read))
+ return false;
+
+ if (sizeof(function_code) != read)
+ return false;
+
+ if (kMmovR10EcxMovEax != function_code.mov_r10_ecx_mov_eax ||
+ kSyscall != function_code.syscall || kRetNp != function_code.ret)
+ return false;
+
+ // Save the verified code
+ memcpy(local_thunk, &function_code, sizeof(function_code));
+
+ return true;
+}
+
+NTSTATUS Service64ResolverThunk::PerformPatch(void* local_thunk,
+ void* remote_thunk) {
+ ServiceFullThunk* full_local_thunk = reinterpret_cast<ServiceFullThunk*>(
+ local_thunk);
+ ServiceFullThunk* full_remote_thunk = reinterpret_cast<ServiceFullThunk*>(
+ remote_thunk);
+
+ // If the source or target are above 4GB we cannot do this relative jump.
+ if (reinterpret_cast<ULONG_PTR>(full_remote_thunk) >
+ static_cast<ULONG_PTR>(ULONG_MAX))
+ return STATUS_CONFLICTING_ADDRESSES;
+
+ if (reinterpret_cast<ULONG_PTR>(target_) > static_cast<ULONG_PTR>(ULONG_MAX))
+ return STATUS_CONFLICTING_ADDRESSES;
+
+ // Patch the original code.
+ Redirected local_service;
+ Redirected* remote_service = reinterpret_cast<Redirected*>(target_);
+ ULONG_PTR diff = reinterpret_cast<BYTE*>(&full_remote_thunk->internal_thunk) -
+ &remote_service->pad;
+ local_service.relative = static_cast<ULONG>(diff);
+
+ // Setup the PatchInfo structure.
+ SIZE_T actual;
+ if (!::ReadProcessMemory(process_, remote_thunk, local_thunk,
+ sizeof(PatchInfo), &actual))
+ return STATUS_UNSUCCESSFUL;
+ if (sizeof(PatchInfo) != actual)
+ return STATUS_UNSUCCESSFUL;
+
+ full_local_thunk->patch_info.orig_MapViewOfSection = reinterpret_cast<
+ NtMapViewOfSectionFunction>(&full_remote_thunk->original);
+ full_local_thunk->patch_info.patch_location = target_;
+ NTSTATUS ret = ResolveNtdll(&full_local_thunk->patch_info);
+ if (!NT_SUCCESS(ret))
+ return ret;
+
+ // Setup the thunk. The jump out is performed from right after the end of the
+ // thunk (full_remote_thunk + 1).
+ InternalThunk my_thunk;
+ ULONG_PTR patch_info = reinterpret_cast<ULONG_PTR>(remote_thunk);
+ my_thunk.patch_info = static_cast<ULONG>(patch_info);
+ diff = reinterpret_cast<const BYTE*>(interceptor_) -
+ reinterpret_cast<BYTE*>(full_remote_thunk + 1);
+ my_thunk.relative = static_cast<ULONG>(diff);
+
+ memcpy(&full_local_thunk->internal_thunk, &my_thunk, sizeof(my_thunk));
+
+ // copy the local thunk buffer to the child
+ if (!::WriteProcessMemory(process_, remote_thunk, local_thunk,
+ sizeof(ServiceFullThunk), &actual))
+ return STATUS_UNSUCCESSFUL;
+
+ if (sizeof(ServiceFullThunk) != actual)
+ return STATUS_UNSUCCESSFUL;
+
+ // and now change the function to intercept, on the child
+ if (!::WriteProtectedChildMemory(process_, target_, &local_service,
+ sizeof(local_service)))
+ return STATUS_UNSUCCESSFUL;
+
+ return STATUS_SUCCESS;
+}
+
+} // namespace sandbox