OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 #ifndef SANDBOX_SRC_CROSSCALL_CLIENT_H_ | |
6 #define SANDBOX_SRC_CROSSCALL_CLIENT_H_ | |
7 | |
8 #include "sandbox/src/crosscall_params.h" | |
9 #include "sandbox/src/sandbox.h" | |
10 | |
11 // This header defines the CrossCall(..) family of templated functions | |
12 // Their purpose is to simulate the syntax of regular call but to generate | |
13 // and IPC from the client-side. | |
14 // | |
15 // The basic pattern is to | |
16 // 1) use template argument deduction to compute the size of each | |
17 // parameter and the appropriate copy method | |
18 // 2) pack the parameters in the appropriate ActualCallParams< > object | |
19 // 3) call the IPC interface IPCProvider::DoCall( ) | |
20 // | |
21 // The general interface of CrossCall is: | |
22 // ResultCode CrossCall(IPCProvider& ipc_provider, | |
23 // uint32 tag, | |
24 // const Par1& p1, const Par2& p2,...pn | |
25 // CrossCallReturn* answer) | |
26 // | |
27 // where: | |
28 // ipc_provider: is a specific implementation of the ipc transport see | |
29 // sharedmem_ipc_server.h for an example. | |
30 // tag : is the unique id for this IPC call. Is used to route the call to | |
31 // the appropriate service. | |
32 // p1, p2,.. pn : The input parameters of the IPC. Use only simple types | |
33 // and wide strings (can add support for others). | |
34 // answer : If the IPC was successful. The server-side answer is here. The | |
35 // interpretation of the answer is private to client and server. | |
36 // | |
37 // The return value is ALL_OK if the IPC was delivered to the server, other | |
38 // return codes indicate that the IPC transport failed to deliver it. | |
39 namespace sandbox { | |
40 | |
41 // this is the assumed channel size. This can be overridden in a given | |
42 // IPC implementation. | |
43 const uint32 kIPCChannelSize = 1024; | |
44 | |
45 // The copy helper uses templates to deduce the appropriate copy function to | |
46 // copy the input parameters in the buffer that is going to be send across the | |
47 // IPC. These template facility can be made more sophisticated as need arises. | |
48 | |
49 // The default copy helper. It catches the general case where no other | |
50 // specialized template matches better. We set the type to ULONG_TYPE, so this | |
51 // only works with objects whose size is 32 bits. | |
52 template<typename T> | |
53 class CopyHelper { | |
54 public: | |
55 CopyHelper(const T& t) : t_(t) {} | |
56 | |
57 // Returns the pointer to the start of the input. | |
58 const void* GetStart() const { | |
59 return &t_; | |
60 } | |
61 | |
62 // Update the stored value with the value in the buffer. This is not | |
63 // supported for this type. | |
64 bool Update(void* buffer) { | |
65 // Not supported; | |
66 return true; | |
67 } | |
68 | |
69 // Returns the size of the input in bytes. | |
70 uint32 GetSize() const { | |
71 return sizeof(T); | |
72 } | |
73 | |
74 // Returns true if the current type is used as an In or InOut parameter. | |
75 bool IsInOut() { | |
76 return false; | |
77 } | |
78 | |
79 // Returns this object's type. | |
80 ArgType GetType() { | |
81 COMPILE_ASSERT(sizeof(T) == sizeof(uint32), need_specialization); | |
82 return ULONG_TYPE; | |
83 } | |
84 | |
85 private: | |
86 const T& t_; | |
87 }; | |
88 | |
89 // This copy helper template specialization if for the void pointer | |
90 // case both 32 and 64 bit. | |
91 template<> | |
92 class CopyHelper<void*> { | |
93 public: | |
94 CopyHelper(void* t) : t_(t) {} | |
95 | |
96 // Returns the pointer to the start of the input. | |
97 const void* GetStart() const { | |
98 return &t_; | |
99 } | |
100 | |
101 // Update the stored value with the value in the buffer. This is not | |
102 // supported for this type. | |
103 bool Update(void* buffer) { | |
104 // Not supported; | |
105 return true; | |
106 } | |
107 | |
108 // Returns the size of the input in bytes. | |
109 uint32 GetSize() const { | |
110 return sizeof(t_); | |
111 } | |
112 | |
113 // Returns true if the current type is used as an In or InOut parameter. | |
114 bool IsInOut() { | |
115 return false; | |
116 } | |
117 | |
118 // Returns this object's type. | |
119 ArgType GetType() { | |
120 return VOIDPTR_TYPE; | |
121 } | |
122 | |
123 private: | |
124 const void* t_; | |
125 }; | |
126 | |
127 // This copy helper template specialization catches the cases where the | |
128 // parameter is a pointer to a string. | |
129 template<> | |
130 class CopyHelper<const wchar_t*> { | |
131 public: | |
132 CopyHelper(const wchar_t* t) | |
133 : t_(t) { | |
134 } | |
135 | |
136 // Returns the pointer to the start of the string. | |
137 const void* GetStart() const { | |
138 return t_; | |
139 } | |
140 | |
141 // Update the stored value with the value in the buffer. This is not | |
142 // supported for this type. | |
143 bool Update(void* buffer) { | |
144 // Not supported; | |
145 return true; | |
146 } | |
147 | |
148 // Returns the size of the string in bytes. We define a NULL string to | |
149 // be of zero length. | |
150 uint32 GetSize() const { | |
151 __try { | |
152 return (!t_) ? 0 : static_cast<uint32>(StringLength(t_) * sizeof(t_[0])); | |
153 } | |
154 __except(EXCEPTION_EXECUTE_HANDLER) { | |
155 return kuint32max; | |
156 } | |
157 } | |
158 | |
159 // Returns true if the current type is used as an In or InOut parameter. | |
160 bool IsInOut() { | |
161 return false; | |
162 } | |
163 | |
164 ArgType GetType() { | |
165 return WCHAR_TYPE; | |
166 } | |
167 | |
168 private: | |
169 // We provide our not very optimized version of wcslen(), since we don't | |
170 // want to risk having the linker use the version in the CRT since the CRT | |
171 // might not be present when we do an early IPC call. | |
172 static size_t __cdecl StringLength(const wchar_t* wcs) { | |
173 const wchar_t *eos = wcs; | |
174 while (*eos++); | |
175 return static_cast<size_t>(eos - wcs - 1); | |
176 } | |
177 | |
178 const wchar_t* t_; | |
179 }; | |
180 | |
181 // Specialization for non-const strings. We just reuse the implementation of the | |
182 // const string specialization. | |
183 template<> | |
184 class CopyHelper<wchar_t*> : public CopyHelper<const wchar_t*> { | |
185 public: | |
186 typedef CopyHelper<const wchar_t*> Base; | |
187 CopyHelper(wchar_t* t) : Base(t) {} | |
188 | |
189 const void* GetStart() const { | |
190 return Base::GetStart(); | |
191 } | |
192 | |
193 bool Update(void* buffer) { | |
194 return Base::Update(buffer); | |
195 } | |
196 | |
197 uint32 GetSize() const { | |
198 return Base::GetSize(); | |
199 } | |
200 | |
201 bool IsInOut() { | |
202 return Base::IsInOut(); | |
203 } | |
204 | |
205 ArgType GetType() { | |
206 return Base::GetType(); | |
207 } | |
208 }; | |
209 | |
210 // Specialization for wchar_t arrays strings. We just reuse the implementation | |
211 // of the const string specialization. | |
212 template<size_t n> | |
213 class CopyHelper<const wchar_t[n]> : public CopyHelper<const wchar_t*> { | |
214 public: | |
215 typedef const wchar_t array[n]; | |
216 typedef CopyHelper<const wchar_t*> Base; | |
217 CopyHelper(array t) : Base(t) {} | |
218 | |
219 const void* GetStart() const { | |
220 return Base::GetStart(); | |
221 } | |
222 | |
223 bool Update(void* buffer) { | |
224 return Base::Update(buffer); | |
225 } | |
226 | |
227 uint32 GetSize() const { | |
228 return Base::GetSize(); | |
229 } | |
230 | |
231 bool IsInOut() { | |
232 return Base::IsInOut(); | |
233 } | |
234 | |
235 ArgType GetType() { | |
236 return Base::GetType(); | |
237 } | |
238 }; | |
239 | |
240 // Generic encapsulation class containing a pointer to a buffer and the | |
241 // size of the buffer. It is used by the IPC to be able to pass in/out | |
242 // parameters. | |
243 class InOutCountedBuffer : public CountedBuffer { | |
244 public: | |
245 InOutCountedBuffer(void* buffer, uint32 size) : CountedBuffer(buffer, size) {} | |
246 }; | |
247 | |
248 // This copy helper template specialization catches the cases where the | |
249 // parameter is a an input/output buffer. | |
250 template<> | |
251 class CopyHelper<InOutCountedBuffer> { | |
252 public: | |
253 CopyHelper(const InOutCountedBuffer t) : t_(t) {} | |
254 | |
255 // Returns the pointer to the start of the string. | |
256 const void* GetStart() const { | |
257 return t_.Buffer(); | |
258 } | |
259 | |
260 // Updates the buffer with the value from the new buffer in parameter. | |
261 bool Update(void* buffer) { | |
262 // We are touching user memory, this has to be done from inside a try | |
263 // except. | |
264 __try { | |
265 memcpy(t_.Buffer(), buffer, t_.Size()); | |
266 } | |
267 __except(EXCEPTION_EXECUTE_HANDLER) { | |
268 return false; | |
269 } | |
270 return true; | |
271 } | |
272 | |
273 // Returns the size of the string in bytes. We define a NULL string to | |
274 // be of zero length. | |
275 uint32 GetSize() const { | |
276 return t_.Size(); | |
277 } | |
278 | |
279 // Returns true if the current type is used as an In or InOut parameter. | |
280 bool IsInOut() { | |
281 return true; | |
282 } | |
283 | |
284 ArgType GetType() { | |
285 return INOUTPTR_TYPE; | |
286 } | |
287 | |
288 private: | |
289 const InOutCountedBuffer t_; | |
290 }; | |
291 | |
292 // The following two macros make it less error prone the generation | |
293 // of CrossCall functions with ever more input parameters. | |
294 | |
295 #define XCALL_GEN_PARAMS_OBJ(num, params) \ | |
296 typedef ActualCallParams<num, kIPCChannelSize> ActualParams; \ | |
297 void* raw_mem = ipc_provider.GetBuffer(); \ | |
298 if (NULL == raw_mem) \ | |
299 return SBOX_ERROR_NO_SPACE; \ | |
300 ActualParams* params = new(raw_mem) ActualParams(tag); | |
301 | |
302 #define XCALL_GEN_COPY_PARAM(num, params) \ | |
303 COMPILE_ASSERT(kMaxIpcParams >= num, too_many_parameters); \ | |
304 CopyHelper<Par##num> ch##num(p##num); \ | |
305 if (!params->CopyParamIn(num - 1, ch##num.GetStart(), ch##num.GetSize(), \ | |
306 ch##num.IsInOut(), ch##num.GetType())) \ | |
307 return SBOX_ERROR_NO_SPACE; | |
308 | |
309 #define XCALL_GEN_UPDATE_PARAM(num, params) \ | |
310 if (!ch##num.Update(params->GetParamPtr(num-1))) {\ | |
311 ipc_provider.FreeBuffer(raw_mem); \ | |
312 return SBOX_ERROR_BAD_PARAMS; \ | |
313 } | |
314 | |
315 #define XCALL_GEN_FREE_CHANNEL() \ | |
316 ipc_provider.FreeBuffer(raw_mem); | |
317 | |
318 // CrossCall template with one input parameter | |
319 template <typename IPCProvider, typename Par1> | |
320 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, | |
321 CrossCallReturn* answer) { | |
322 XCALL_GEN_PARAMS_OBJ(1, call_params); | |
323 XCALL_GEN_COPY_PARAM(1, call_params); | |
324 | |
325 ResultCode result = ipc_provider.DoCall(call_params, answer); | |
326 | |
327 if (SBOX_ERROR_CHANNEL_ERROR != result) { | |
328 XCALL_GEN_UPDATE_PARAM(1, call_params); | |
329 XCALL_GEN_FREE_CHANNEL(); | |
330 } | |
331 | |
332 return result; | |
333 } | |
334 | |
335 // CrossCall template with two input parameters. | |
336 template <typename IPCProvider, typename Par1, typename Par2> | |
337 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, | |
338 const Par2& p2, CrossCallReturn* answer) { | |
339 XCALL_GEN_PARAMS_OBJ(2, call_params); | |
340 XCALL_GEN_COPY_PARAM(1, call_params); | |
341 XCALL_GEN_COPY_PARAM(2, call_params); | |
342 | |
343 ResultCode result = ipc_provider.DoCall(call_params, answer); | |
344 | |
345 if (SBOX_ERROR_CHANNEL_ERROR != result) { | |
346 XCALL_GEN_UPDATE_PARAM(1, call_params); | |
347 XCALL_GEN_UPDATE_PARAM(2, call_params); | |
348 XCALL_GEN_FREE_CHANNEL(); | |
349 } | |
350 return result; | |
351 } | |
352 | |
353 // CrossCall template with three input parameters. | |
354 template <typename IPCProvider, typename Par1, typename Par2, typename Par3> | |
355 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, | |
356 const Par2& p2, const Par3& p3, CrossCallReturn* answer) { | |
357 XCALL_GEN_PARAMS_OBJ(3, call_params); | |
358 XCALL_GEN_COPY_PARAM(1, call_params); | |
359 XCALL_GEN_COPY_PARAM(2, call_params); | |
360 XCALL_GEN_COPY_PARAM(3, call_params); | |
361 | |
362 ResultCode result = ipc_provider.DoCall(call_params, answer); | |
363 | |
364 if (SBOX_ERROR_CHANNEL_ERROR != result) { | |
365 XCALL_GEN_UPDATE_PARAM(1, call_params); | |
366 XCALL_GEN_UPDATE_PARAM(2, call_params); | |
367 XCALL_GEN_UPDATE_PARAM(3, call_params); | |
368 XCALL_GEN_FREE_CHANNEL(); | |
369 } | |
370 return result; | |
371 } | |
372 | |
373 // CrossCall template with four input parameters. | |
374 template <typename IPCProvider, typename Par1, typename Par2, typename Par3, | |
375 typename Par4> | |
376 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, | |
377 const Par2& p2, const Par3& p3, const Par4& p4, | |
378 CrossCallReturn* answer) { | |
379 XCALL_GEN_PARAMS_OBJ(4, call_params); | |
380 XCALL_GEN_COPY_PARAM(1, call_params); | |
381 XCALL_GEN_COPY_PARAM(2, call_params); | |
382 XCALL_GEN_COPY_PARAM(3, call_params); | |
383 XCALL_GEN_COPY_PARAM(4, call_params); | |
384 | |
385 ResultCode result = ipc_provider.DoCall(call_params, answer); | |
386 | |
387 if (SBOX_ERROR_CHANNEL_ERROR != result) { | |
388 XCALL_GEN_UPDATE_PARAM(1, call_params); | |
389 XCALL_GEN_UPDATE_PARAM(2, call_params); | |
390 XCALL_GEN_UPDATE_PARAM(3, call_params); | |
391 XCALL_GEN_UPDATE_PARAM(4, call_params); | |
392 XCALL_GEN_FREE_CHANNEL(); | |
393 } | |
394 return result; | |
395 } | |
396 | |
397 // CrossCall template with five input parameters. | |
398 template <typename IPCProvider, typename Par1, typename Par2, typename Par3, | |
399 typename Par4, typename Par5> | |
400 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, | |
401 const Par2& p2, const Par3& p3, const Par4& p4, | |
402 const Par5& p5, CrossCallReturn* answer) { | |
403 XCALL_GEN_PARAMS_OBJ(5, call_params); | |
404 XCALL_GEN_COPY_PARAM(1, call_params); | |
405 XCALL_GEN_COPY_PARAM(2, call_params); | |
406 XCALL_GEN_COPY_PARAM(3, call_params); | |
407 XCALL_GEN_COPY_PARAM(4, call_params); | |
408 XCALL_GEN_COPY_PARAM(5, call_params); | |
409 | |
410 ResultCode result = ipc_provider.DoCall(call_params, answer); | |
411 | |
412 if (SBOX_ERROR_CHANNEL_ERROR != result) { | |
413 XCALL_GEN_UPDATE_PARAM(1, call_params); | |
414 XCALL_GEN_UPDATE_PARAM(2, call_params); | |
415 XCALL_GEN_UPDATE_PARAM(3, call_params); | |
416 XCALL_GEN_UPDATE_PARAM(4, call_params); | |
417 XCALL_GEN_UPDATE_PARAM(5, call_params); | |
418 XCALL_GEN_FREE_CHANNEL(); | |
419 } | |
420 return result; | |
421 } | |
422 | |
423 // CrossCall template with six input parameters. | |
424 template <typename IPCProvider, typename Par1, typename Par2, typename Par3, | |
425 typename Par4, typename Par5, typename Par6> | |
426 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, | |
427 const Par2& p2, const Par3& p3, const Par4& p4, | |
428 const Par5& p5, const Par6& p6, CrossCallReturn* answer) { | |
429 XCALL_GEN_PARAMS_OBJ(6, call_params); | |
430 XCALL_GEN_COPY_PARAM(1, call_params); | |
431 XCALL_GEN_COPY_PARAM(2, call_params); | |
432 XCALL_GEN_COPY_PARAM(3, call_params); | |
433 XCALL_GEN_COPY_PARAM(4, call_params); | |
434 XCALL_GEN_COPY_PARAM(5, call_params); | |
435 XCALL_GEN_COPY_PARAM(6, call_params); | |
436 | |
437 ResultCode result = ipc_provider.DoCall(call_params, answer); | |
438 | |
439 if (SBOX_ERROR_CHANNEL_ERROR != result) { | |
440 XCALL_GEN_UPDATE_PARAM(1, call_params); | |
441 XCALL_GEN_UPDATE_PARAM(2, call_params); | |
442 XCALL_GEN_UPDATE_PARAM(3, call_params); | |
443 XCALL_GEN_UPDATE_PARAM(4, call_params); | |
444 XCALL_GEN_UPDATE_PARAM(5, call_params); | |
445 XCALL_GEN_UPDATE_PARAM(6, call_params); | |
446 XCALL_GEN_FREE_CHANNEL(); | |
447 } | |
448 return result; | |
449 } | |
450 | |
451 // CrossCall template with seven input parameters. | |
452 template <typename IPCProvider, typename Par1, typename Par2, typename Par3, | |
453 typename Par4, typename Par5, typename Par6, typename Par7> | |
454 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, | |
455 const Par2& p2, const Par3& p3, const Par4& p4, | |
456 const Par5& p5, const Par6& p6, const Par7& p7, | |
457 CrossCallReturn* answer) { | |
458 XCALL_GEN_PARAMS_OBJ(7, call_params); | |
459 XCALL_GEN_COPY_PARAM(1, call_params); | |
460 XCALL_GEN_COPY_PARAM(2, call_params); | |
461 XCALL_GEN_COPY_PARAM(3, call_params); | |
462 XCALL_GEN_COPY_PARAM(4, call_params); | |
463 XCALL_GEN_COPY_PARAM(5, call_params); | |
464 XCALL_GEN_COPY_PARAM(6, call_params); | |
465 XCALL_GEN_COPY_PARAM(7, call_params); | |
466 | |
467 ResultCode result = ipc_provider.DoCall(call_params, answer); | |
468 | |
469 if (SBOX_ERROR_CHANNEL_ERROR != result) { | |
470 XCALL_GEN_UPDATE_PARAM(1, call_params); | |
471 XCALL_GEN_UPDATE_PARAM(2, call_params); | |
472 XCALL_GEN_UPDATE_PARAM(3, call_params); | |
473 XCALL_GEN_UPDATE_PARAM(4, call_params); | |
474 XCALL_GEN_UPDATE_PARAM(5, call_params); | |
475 XCALL_GEN_UPDATE_PARAM(6, call_params); | |
476 XCALL_GEN_UPDATE_PARAM(7, call_params); | |
477 XCALL_GEN_FREE_CHANNEL(); | |
478 } | |
479 return result; | |
480 } | |
481 } // namespace sandbox | |
482 | |
483 #endif // SANDBOX_SRC_CROSSCALL_CLIENT_H__ | |
OLD | NEW |