security/sandbox/win/src/interception.h

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) 2011 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 // Defines InterceptionManager, the class in charge of setting up interceptions
michael@0 6 // for the sandboxed process. For more details see
michael@0 7 // http://dev.chromium.org/developers/design-documents/sandbox .
michael@0 8
michael@0 9 #ifndef SANDBOX_SRC_INTERCEPTION_H_
michael@0 10 #define SANDBOX_SRC_INTERCEPTION_H_
michael@0 11
michael@0 12 #include <list>
michael@0 13 #include <string>
michael@0 14
michael@0 15 #include "base/basictypes.h"
michael@0 16 #include "base/gtest_prod_util.h"
michael@0 17 #include "sandbox/win/src/sandbox_types.h"
michael@0 18
michael@0 19 namespace sandbox {
michael@0 20
michael@0 21 class TargetProcess;
michael@0 22 enum InterceptorId;
michael@0 23
michael@0 24 // Internal structures used for communication between the broker and the target.
michael@0 25 struct DllPatchInfo;
michael@0 26 struct DllInterceptionData;
michael@0 27
michael@0 28 // The InterceptionManager executes on the parent application, and it is in
michael@0 29 // charge of setting up the desired interceptions, and placing the Interception
michael@0 30 // Agent into the child application.
michael@0 31 //
michael@0 32 // The exposed API consists of two methods: AddToPatchedFunctions to set up a
michael@0 33 // particular interception, and InitializeInterceptions to actually go ahead and
michael@0 34 // perform all interceptions and transfer data to the child application.
michael@0 35 //
michael@0 36 // The typical usage is something like this:
michael@0 37 //
michael@0 38 // InterceptionManager interception_manager(child);
michael@0 39 // if (!interception_manager.AddToPatchedFunctions(
michael@0 40 // L"ntdll.dll", "NtCreateFile",
michael@0 41 // sandbox::INTERCEPTION_SERVICE_CALL, &MyNtCreateFile, MY_ID_1))
michael@0 42 // return false;
michael@0 43 //
michael@0 44 // if (!interception_manager.AddToPatchedFunctions(
michael@0 45 // L"kernel32.dll", "CreateDirectoryW",
michael@0 46 // sandbox::INTERCEPTION_EAT, L"MyCreateDirectoryW@12", MY_ID_2))
michael@0 47 // return false;
michael@0 48 //
michael@0 49 // if (!interception_manager.InitializeInterceptions()) {
michael@0 50 // DWORD error = ::GetLastError();
michael@0 51 // return false;
michael@0 52 // }
michael@0 53 //
michael@0 54 // Any required syncronization must be performed outside this class. Also, it is
michael@0 55 // not possible to perform further interceptions after InitializeInterceptions
michael@0 56 // is called.
michael@0 57 //
michael@0 58 class InterceptionManager {
michael@0 59 // The unit test will access private members.
michael@0 60 // Allow tests to be marked DISABLED_. Note that FLAKY_ and FAILS_ prefixes
michael@0 61 // do not work with sandbox tests.
michael@0 62 FRIEND_TEST_ALL_PREFIXES(InterceptionManagerTest, BufferLayout1);
michael@0 63 FRIEND_TEST_ALL_PREFIXES(InterceptionManagerTest, BufferLayout2);
michael@0 64
michael@0 65 public:
michael@0 66 // An interception manager performs interceptions on a given child process.
michael@0 67 // If we are allowed to intercept functions that have been patched by somebody
michael@0 68 // else, relaxed should be set to true.
michael@0 69 // Note: We increase the child's reference count internally.
michael@0 70 InterceptionManager(TargetProcess* child_process, bool relaxed);
michael@0 71 ~InterceptionManager();
michael@0 72
michael@0 73 // Patches function_name inside dll_name to point to replacement_code_address.
michael@0 74 // function_name has to be an exported symbol of dll_name.
michael@0 75 // Returns true on success.
michael@0 76 //
michael@0 77 // The new function should match the prototype and calling convention of the
michael@0 78 // function to intercept except for one extra argument (the first one) that
michael@0 79 // contains a pointer to the original function, to simplify the development
michael@0 80 // of interceptors (for IA32). In x64, there is no extra argument to the
michael@0 81 // interceptor, so the provided InterceptorId is used to keep a table of
michael@0 82 // intercepted functions so that the interceptor can index that table to get
michael@0 83 // the pointer that would have been the first argument (g_originals[id]).
michael@0 84 //
michael@0 85 // For example, to intercept NtClose, the following code could be used:
michael@0 86 //
michael@0 87 // typedef NTSTATUS (WINAPI *NtCloseFunction) (IN HANDLE Handle);
michael@0 88 // NTSTATUS WINAPI MyNtCose(IN NtCloseFunction OriginalClose,
michael@0 89 // IN HANDLE Handle) {
michael@0 90 // // do something
michael@0 91 // // call the original function
michael@0 92 // return OriginalClose(Handle);
michael@0 93 // }
michael@0 94 //
michael@0 95 // And in x64:
michael@0 96 //
michael@0 97 // typedef NTSTATUS (WINAPI *NtCloseFunction) (IN HANDLE Handle);
michael@0 98 // NTSTATUS WINAPI MyNtCose64(IN HANDLE Handle) {
michael@0 99 // // do something
michael@0 100 // // call the original function
michael@0 101 // NtCloseFunction OriginalClose = g_originals[NT_CLOSE_ID];
michael@0 102 // return OriginalClose(Handle);
michael@0 103 // }
michael@0 104 bool AddToPatchedFunctions(const wchar_t* dll_name,
michael@0 105 const char* function_name,
michael@0 106 InterceptionType interception_type,
michael@0 107 const void* replacement_code_address,
michael@0 108 InterceptorId id);
michael@0 109
michael@0 110 // Patches function_name inside dll_name to point to
michael@0 111 // replacement_function_name.
michael@0 112 bool AddToPatchedFunctions(const wchar_t* dll_name,
michael@0 113 const char* function_name,
michael@0 114 InterceptionType interception_type,
michael@0 115 const char* replacement_function_name,
michael@0 116 InterceptorId id);
michael@0 117
michael@0 118 // The interception agent will unload the dll with dll_name.
michael@0 119 bool AddToUnloadModules(const wchar_t* dll_name);
michael@0 120
michael@0 121 // Initializes all interceptions on the client.
michael@0 122 // Returns true on success.
michael@0 123 //
michael@0 124 // The child process must be created suspended, and cannot be resumed until
michael@0 125 // after this method returns. In addition, no action should be performed on
michael@0 126 // the child that may cause it to resume momentarily, such as injecting
michael@0 127 // threads or APCs.
michael@0 128 //
michael@0 129 // This function must be called only once, after all interceptions have been
michael@0 130 // set up using AddToPatchedFunctions.
michael@0 131 bool InitializeInterceptions();
michael@0 132
michael@0 133 private:
michael@0 134 // Used to store the interception information until the actual set-up.
michael@0 135 struct InterceptionData {
michael@0 136 InterceptionType type; // Interception type.
michael@0 137 InterceptorId id; // Interceptor id.
michael@0 138 std::wstring dll; // Name of dll to intercept.
michael@0 139 std::string function; // Name of function to intercept.
michael@0 140 std::string interceptor; // Name of interceptor function.
michael@0 141 const void* interceptor_address; // Interceptor's entry point.
michael@0 142 };
michael@0 143
michael@0 144 // Calculates the size of the required configuration buffer.
michael@0 145 size_t GetBufferSize() const;
michael@0 146
michael@0 147 // Rounds up the size of a given buffer, considering alignment (padding).
michael@0 148 // value is the current size of the buffer, and alignment is specified in
michael@0 149 // bytes.
michael@0 150 static inline size_t RoundUpToMultiple(size_t value, size_t alignment) {
michael@0 151 return ((value + alignment -1) / alignment) * alignment;
michael@0 152 }
michael@0 153
michael@0 154 // Sets up a given buffer with all the information that has to be transfered
michael@0 155 // to the child.
michael@0 156 // Returns true on success.
michael@0 157 //
michael@0 158 // The buffer size should be at least the value returned by GetBufferSize
michael@0 159 bool SetupConfigBuffer(void* buffer, size_t buffer_bytes);
michael@0 160
michael@0 161 // Fills up the part of the transfer buffer that corresponds to information
michael@0 162 // about one dll to patch.
michael@0 163 // data is the first recorded interception for this dll.
michael@0 164 // Returns true on success.
michael@0 165 //
michael@0 166 // On successful return, buffer will be advanced from it's current position
michael@0 167 // to the point where the next block of configuration data should be written
michael@0 168 // (the actual interception info), and the current size of the buffer will
michael@0 169 // decrease to account the space used by this method.
michael@0 170 bool SetupDllInfo(const InterceptionData& data,
michael@0 171 void** buffer, size_t* buffer_bytes) const;
michael@0 172
michael@0 173 // Fills up the part of the transfer buffer that corresponds to a single
michael@0 174 // function to patch.
michael@0 175 // dll_info points to the dll being updated with the interception stored on
michael@0 176 // data. The buffer pointer and remaining size are updated by this call.
michael@0 177 // Returns true on success.
michael@0 178 bool SetupInterceptionInfo(const InterceptionData& data, void** buffer,
michael@0 179 size_t* buffer_bytes,
michael@0 180 DllPatchInfo* dll_info) const;
michael@0 181
michael@0 182 // Returns true if this interception is to be performed by the child
michael@0 183 // as opposed to from the parent.
michael@0 184 bool IsInterceptionPerformedByChild(const InterceptionData& data) const;
michael@0 185
michael@0 186 // Allocates a buffer on the child's address space (returned on
michael@0 187 // remote_buffer), and fills it with the contents of a local buffer.
michael@0 188 // Returns true on success.
michael@0 189 bool CopyDataToChild(const void* local_buffer, size_t buffer_bytes,
michael@0 190 void** remote_buffer) const;
michael@0 191
michael@0 192 // Performs the cold patch (from the parent) of ntdll.
michael@0 193 // Returns true on success.
michael@0 194 //
michael@0 195 // This method will insert additional interceptions to launch the interceptor
michael@0 196 // agent on the child process, if there are additional interceptions to do.
michael@0 197 bool PatchNtdll(bool hot_patch_needed);
michael@0 198
michael@0 199 // Peforms the actual interceptions on ntdll.
michael@0 200 // thunks is the memory to store all the thunks for this dll (on the child),
michael@0 201 // and dll_data is a local buffer to hold global dll interception info.
michael@0 202 // Returns true on success.
michael@0 203 bool PatchClientFunctions(DllInterceptionData* thunks,
michael@0 204 size_t thunk_bytes,
michael@0 205 DllInterceptionData* dll_data);
michael@0 206
michael@0 207 // The process to intercept.
michael@0 208 TargetProcess* child_;
michael@0 209 // Holds all interception info until the call to initialize (perform the
michael@0 210 // actual patch).
michael@0 211 std::list<InterceptionData> interceptions_;
michael@0 212
michael@0 213 // Keep track of patches added by name.
michael@0 214 bool names_used_;
michael@0 215
michael@0 216 // true if we are allowed to patch already-patched functions.
michael@0 217 bool relaxed_;
michael@0 218
michael@0 219 DISALLOW_COPY_AND_ASSIGN(InterceptionManager);
michael@0 220 };
michael@0 221
michael@0 222 // This macro simply calls interception_manager.AddToPatchedFunctions with
michael@0 223 // the given service to intercept (INTERCEPTION_SERVICE_CALL), and assumes that
michael@0 224 // the interceptor is called "TargetXXX", where XXX is the name of the service.
michael@0 225 // Note that num_params is the number of bytes to pop out of the stack for
michael@0 226 // the exported interceptor, following the calling convention of a service call
michael@0 227 // (WINAPI = with the "C" underscore).
michael@0 228 #if SANDBOX_EXPORTS
michael@0 229 #if defined(_WIN64)
michael@0 230 #define MAKE_SERVICE_NAME(service, params) "Target" # service "64"
michael@0 231 #else
michael@0 232 #define MAKE_SERVICE_NAME(service, params) "_Target" # service "@" # params
michael@0 233 #endif
michael@0 234
michael@0 235 #define ADD_NT_INTERCEPTION(service, id, num_params) \
michael@0 236 AddToPatchedFunctions(kNtdllName, #service, \
michael@0 237 sandbox::INTERCEPTION_SERVICE_CALL, \
michael@0 238 MAKE_SERVICE_NAME(service, num_params), id)
michael@0 239
michael@0 240 #define INTERCEPT_NT(manager, service, id, num_params) \
michael@0 241 ((&Target##service) ? \
michael@0 242 manager->ADD_NT_INTERCEPTION(service, id, num_params) : false)
michael@0 243
michael@0 244 #define INTERCEPT_EAT(manager, dll, function, id, num_params) \
michael@0 245 ((&Target##function) ? \
michael@0 246 manager->AddToPatchedFunctions(dll, #function, sandbox::INTERCEPTION_EAT, \
michael@0 247 MAKE_SERVICE_NAME(function, num_params), \
michael@0 248 id) : \
michael@0 249 false)
michael@0 250 #else // SANDBOX_EXPORTS
michael@0 251 #if defined(_WIN64)
michael@0 252 #define MAKE_SERVICE_NAME(service) &Target##service##64
michael@0 253 #else
michael@0 254 #define MAKE_SERVICE_NAME(service) &Target##service
michael@0 255 #endif
michael@0 256
michael@0 257 #define ADD_NT_INTERCEPTION(service, id, num_params) \
michael@0 258 AddToPatchedFunctions(kNtdllName, #service, \
michael@0 259 sandbox::INTERCEPTION_SERVICE_CALL, \
michael@0 260 MAKE_SERVICE_NAME(service), id)
michael@0 261
michael@0 262 #define INTERCEPT_NT(manager, service, id, num_params) \
michael@0 263 manager->ADD_NT_INTERCEPTION(service, id, num_params)
michael@0 264
michael@0 265 #define INTERCEPT_EAT(manager, dll, function, id, num_params) \
michael@0 266 manager->AddToPatchedFunctions(dll, #function, sandbox::INTERCEPTION_EAT, \
michael@0 267 MAKE_SERVICE_NAME(function), id)
michael@0 268 #endif // SANDBOX_EXPORTS
michael@0 269
michael@0 270 } // namespace sandbox
michael@0 271
michael@0 272 #endif // SANDBOX_SRC_INTERCEPTION_H_

mercurial