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