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