crosscall_client.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  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. #ifndef SANDBOX_WIN_SRC_CROSSCALL_CLIENT_H_
  5. #define SANDBOX_WIN_SRC_CROSSCALL_CLIENT_H_
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include "base/compiler_specific.h"
  9. #include "sandbox/win/src/crosscall_params.h"
  10. #include "sandbox/win/src/sandbox.h"
  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_t 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. enum class IpcTag;
  41. // this is the assumed channel size. This can be overridden in a given
  42. // IPC implementation.
  43. const uint32_t kIPCChannelSize = 1024;
  44. // The copy helper uses templates to deduce the appropriate copy function to
  45. // copy the input parameters in the buffer that is going to be send across the
  46. // IPC. These template facility can be made more sophisticated as need arises.
  47. // The default copy helper. It catches the general case where no other
  48. // specialized template matches better. We set the type to UINT32_TYPE, so this
  49. // only works with objects whose size is 32 bits.
  50. template <typename T>
  51. class CopyHelper {
  52. public:
  53. explicit CopyHelper(const T& t) : t_(t) {}
  54. // Returns the pointer to the start of the input.
  55. const void* GetStart() const { return &t_; }
  56. // Update the stored value with the value in the buffer. This is not
  57. // supported for this type.
  58. bool Update(void* buffer) {
  59. // Not supported;
  60. return true;
  61. }
  62. // Returns the size of the input in bytes.
  63. uint32_t GetSize() const { return sizeof(T); }
  64. // Returns true if the current type is used as an In or InOut parameter.
  65. bool IsInOut() { return false; }
  66. // Returns this object's type.
  67. ArgType GetType() {
  68. static_assert(sizeof(T) == sizeof(uint32_t), "specialization needed");
  69. return UINT32_TYPE;
  70. }
  71. private:
  72. const T& t_;
  73. };
  74. // This copy helper template specialization if for the void pointer
  75. // case both 32 and 64 bit.
  76. template <>
  77. class CopyHelper<void*> {
  78. public:
  79. explicit CopyHelper(void* t) : t_(t) {}
  80. // Returns the pointer to the start of the input.
  81. const void* GetStart() const { return &t_; }
  82. // Update the stored value with the value in the buffer. This is not
  83. // supported for this type.
  84. bool Update(void* buffer) {
  85. // Not supported;
  86. return true;
  87. }
  88. // Returns the size of the input in bytes.
  89. uint32_t GetSize() const { return sizeof(t_); }
  90. // Returns true if the current type is used as an In or InOut parameter.
  91. bool IsInOut() { return false; }
  92. // Returns this object's type.
  93. ArgType GetType() { return VOIDPTR_TYPE; }
  94. private:
  95. const void* t_;
  96. };
  97. // This copy helper template specialization catches the cases where the
  98. // parameter is a pointer to a string.
  99. template <>
  100. class CopyHelper<const wchar_t*> {
  101. public:
  102. explicit CopyHelper(const wchar_t* t) : t_(t) {}
  103. // Returns the pointer to the start of the string.
  104. const void* GetStart() const { return t_; }
  105. // Update the stored value with the value in the buffer. This is not
  106. // supported for this type.
  107. bool Update(void* buffer) {
  108. // Not supported;
  109. return true;
  110. }
  111. // Returns the size of the string in bytes. We define a nullptr string to
  112. // be of zero length.
  113. uint32_t GetSize() const {
  114. __try {
  115. return (!t_) ? 0
  116. : static_cast<uint32_t>(StringLength(t_) * sizeof(t_[0]));
  117. } __except (EXCEPTION_EXECUTE_HANDLER) {
  118. return UINT32_MAX;
  119. }
  120. }
  121. // Returns true if the current type is used as an In or InOut parameter.
  122. bool IsInOut() { return false; }
  123. ArgType GetType() { return WCHAR_TYPE; }
  124. private:
  125. // We provide our not very optimized version of wcslen(), since we don't
  126. // want to risk having the linker use the version in the CRT since the CRT
  127. // might not be present when we do an early IPC call.
  128. static size_t CDECL StringLength(const wchar_t* wcs) {
  129. const wchar_t* eos = wcs;
  130. while (*eos++)
  131. ;
  132. return static_cast<size_t>(eos - wcs - 1);
  133. }
  134. const wchar_t* t_;
  135. };
  136. // Specialization for non-const strings. We just reuse the implementation of the
  137. // const string specialization.
  138. template <>
  139. class CopyHelper<wchar_t*> : public CopyHelper<const wchar_t*> {
  140. public:
  141. typedef CopyHelper<const wchar_t*> Base;
  142. explicit CopyHelper(wchar_t* t) : Base(t) {}
  143. const void* GetStart() const { return Base::GetStart(); }
  144. bool Update(void* buffer) { return Base::Update(buffer); }
  145. uint32_t GetSize() const { return Base::GetSize(); }
  146. bool IsInOut() { return Base::IsInOut(); }
  147. ArgType GetType() { return Base::GetType(); }
  148. };
  149. // Specialization for wchar_t arrays strings. We just reuse the implementation
  150. // of the const string specialization.
  151. template <size_t n>
  152. class CopyHelper<const wchar_t[n]> : public CopyHelper<const wchar_t*> {
  153. public:
  154. typedef const wchar_t array[n];
  155. typedef CopyHelper<const wchar_t*> Base;
  156. explicit CopyHelper(array t) : Base(t) {}
  157. const void* GetStart() const { return Base::GetStart(); }
  158. bool Update(void* buffer) { return Base::Update(buffer); }
  159. uint32_t GetSize() const { return Base::GetSize(); }
  160. bool IsInOut() { return Base::IsInOut(); }
  161. ArgType GetType() { return Base::GetType(); }
  162. };
  163. // Generic encapsulation class containing a pointer to a buffer and the
  164. // size of the buffer. It is used by the IPC to be able to pass in/out
  165. // parameters.
  166. class InOutCountedBuffer : public CountedBuffer {
  167. public:
  168. InOutCountedBuffer(void* buffer, uint32_t size)
  169. : CountedBuffer(buffer, size) {}
  170. };
  171. // This copy helper template specialization catches the cases where the
  172. // parameter is a an input/output buffer.
  173. template <>
  174. class CopyHelper<InOutCountedBuffer> {
  175. public:
  176. explicit CopyHelper(const InOutCountedBuffer t) : t_(t) {}
  177. // Returns the pointer to the start of the string.
  178. const void* GetStart() const { return t_.Buffer(); }
  179. // Updates the buffer with the value from the new buffer in parameter.
  180. bool Update(void* buffer) {
  181. // We are touching user memory, this has to be done from inside a try
  182. // except.
  183. __try {
  184. memcpy_wrapper(t_.Buffer(), buffer, t_.Size());
  185. } __except (EXCEPTION_EXECUTE_HANDLER) {
  186. return false;
  187. }
  188. return true;
  189. }
  190. // Returns the size of the string in bytes. We define a nullptr string to
  191. // be of zero length.
  192. uint32_t GetSize() const { return t_.Size(); }
  193. // Returns true if the current type is used as an In or InOut parameter.
  194. bool IsInOut() { return true; }
  195. ArgType GetType() { return INOUTPTR_TYPE; }
  196. private:
  197. const InOutCountedBuffer t_;
  198. };
  199. // The following two macros make it less error prone the generation
  200. // of CrossCall functions with ever more input parameters.
  201. #define XCALL_GEN_PARAMS_OBJ(num, params) \
  202. typedef ActualCallParams<num, kIPCChannelSize> ActualParams; \
  203. void* raw_mem = ipc_provider.GetBuffer(); \
  204. if (!raw_mem) \
  205. return SBOX_ERROR_NO_SPACE; \
  206. ActualParams* params = new (raw_mem) ActualParams(tag);
  207. #define XCALL_GEN_COPY_PARAM(num, params) \
  208. static_assert(kMaxIpcParams >= num, "too many parameters"); \
  209. CopyHelper<Par##num> ch##num(p##num); \
  210. if (!params->CopyParamIn(num - 1, ch##num.GetStart(), ch##num.GetSize(), \
  211. ch##num.IsInOut(), ch##num.GetType())) \
  212. return SBOX_ERROR_NO_SPACE;
  213. #define XCALL_GEN_UPDATE_PARAM(num, params) \
  214. if (!ch##num.Update(params->GetParamPtr(num - 1))) { \
  215. ipc_provider.FreeBuffer(raw_mem); \
  216. return SBOX_ERROR_BAD_PARAMS; \
  217. }
  218. #define XCALL_GEN_FREE_CHANNEL() ipc_provider.FreeBuffer(raw_mem);
  219. // CrossCall template with one input parameter
  220. template <typename IPCProvider, typename Par1>
  221. ResultCode CrossCall(IPCProvider& ipc_provider,
  222. IpcTag tag,
  223. const Par1& p1,
  224. CrossCallReturn* answer) {
  225. XCALL_GEN_PARAMS_OBJ(1, call_params);
  226. XCALL_GEN_COPY_PARAM(1, call_params);
  227. ResultCode result = ipc_provider.DoCall(call_params, answer);
  228. if (SBOX_ERROR_CHANNEL_ERROR != result) {
  229. XCALL_GEN_UPDATE_PARAM(1, call_params);
  230. XCALL_GEN_FREE_CHANNEL();
  231. }
  232. return result;
  233. }
  234. // CrossCall template with two input parameters.
  235. template <typename IPCProvider, typename Par1, typename Par2>
  236. ResultCode CrossCall(IPCProvider& ipc_provider,
  237. IpcTag tag,
  238. const Par1& p1,
  239. const Par2& p2,
  240. CrossCallReturn* answer) {
  241. XCALL_GEN_PARAMS_OBJ(2, call_params);
  242. XCALL_GEN_COPY_PARAM(1, call_params);
  243. XCALL_GEN_COPY_PARAM(2, call_params);
  244. ResultCode result = ipc_provider.DoCall(call_params, answer);
  245. if (SBOX_ERROR_CHANNEL_ERROR != result) {
  246. XCALL_GEN_UPDATE_PARAM(1, call_params);
  247. XCALL_GEN_UPDATE_PARAM(2, call_params);
  248. XCALL_GEN_FREE_CHANNEL();
  249. }
  250. return result;
  251. }
  252. // CrossCall template with three input parameters.
  253. template <typename IPCProvider, typename Par1, typename Par2, typename Par3>
  254. ResultCode CrossCall(IPCProvider& ipc_provider,
  255. IpcTag tag,
  256. const Par1& p1,
  257. const Par2& p2,
  258. const Par3& p3,
  259. CrossCallReturn* answer) {
  260. XCALL_GEN_PARAMS_OBJ(3, call_params);
  261. XCALL_GEN_COPY_PARAM(1, call_params);
  262. XCALL_GEN_COPY_PARAM(2, call_params);
  263. XCALL_GEN_COPY_PARAM(3, call_params);
  264. ResultCode result = ipc_provider.DoCall(call_params, answer);
  265. if (SBOX_ERROR_CHANNEL_ERROR != result) {
  266. XCALL_GEN_UPDATE_PARAM(1, call_params);
  267. XCALL_GEN_UPDATE_PARAM(2, call_params);
  268. XCALL_GEN_UPDATE_PARAM(3, call_params);
  269. XCALL_GEN_FREE_CHANNEL();
  270. }
  271. return result;
  272. }
  273. // CrossCall template with four input parameters.
  274. template <typename IPCProvider,
  275. typename Par1,
  276. typename Par2,
  277. typename Par3,
  278. typename Par4>
  279. ResultCode CrossCall(IPCProvider& ipc_provider,
  280. IpcTag tag,
  281. const Par1& p1,
  282. const Par2& p2,
  283. const Par3& p3,
  284. const Par4& p4,
  285. CrossCallReturn* answer) {
  286. XCALL_GEN_PARAMS_OBJ(4, call_params);
  287. XCALL_GEN_COPY_PARAM(1, call_params);
  288. XCALL_GEN_COPY_PARAM(2, call_params);
  289. XCALL_GEN_COPY_PARAM(3, call_params);
  290. XCALL_GEN_COPY_PARAM(4, call_params);
  291. ResultCode result = ipc_provider.DoCall(call_params, answer);
  292. if (SBOX_ERROR_CHANNEL_ERROR != result) {
  293. XCALL_GEN_UPDATE_PARAM(1, call_params);
  294. XCALL_GEN_UPDATE_PARAM(2, call_params);
  295. XCALL_GEN_UPDATE_PARAM(3, call_params);
  296. XCALL_GEN_UPDATE_PARAM(4, call_params);
  297. XCALL_GEN_FREE_CHANNEL();
  298. }
  299. return result;
  300. }
  301. // CrossCall template with five input parameters.
  302. template <typename IPCProvider,
  303. typename Par1,
  304. typename Par2,
  305. typename Par3,
  306. typename Par4,
  307. typename Par5>
  308. ResultCode CrossCall(IPCProvider& ipc_provider,
  309. IpcTag tag,
  310. const Par1& p1,
  311. const Par2& p2,
  312. const Par3& p3,
  313. const Par4& p4,
  314. const Par5& p5,
  315. CrossCallReturn* answer) {
  316. XCALL_GEN_PARAMS_OBJ(5, call_params);
  317. XCALL_GEN_COPY_PARAM(1, call_params);
  318. XCALL_GEN_COPY_PARAM(2, call_params);
  319. XCALL_GEN_COPY_PARAM(3, call_params);
  320. XCALL_GEN_COPY_PARAM(4, call_params);
  321. XCALL_GEN_COPY_PARAM(5, call_params);
  322. ResultCode result = ipc_provider.DoCall(call_params, answer);
  323. if (SBOX_ERROR_CHANNEL_ERROR != result) {
  324. XCALL_GEN_UPDATE_PARAM(1, call_params);
  325. XCALL_GEN_UPDATE_PARAM(2, call_params);
  326. XCALL_GEN_UPDATE_PARAM(3, call_params);
  327. XCALL_GEN_UPDATE_PARAM(4, call_params);
  328. XCALL_GEN_UPDATE_PARAM(5, call_params);
  329. XCALL_GEN_FREE_CHANNEL();
  330. }
  331. return result;
  332. }
  333. // CrossCall template with six input parameters.
  334. template <typename IPCProvider,
  335. typename Par1,
  336. typename Par2,
  337. typename Par3,
  338. typename Par4,
  339. typename Par5,
  340. typename Par6>
  341. ResultCode CrossCall(IPCProvider& ipc_provider,
  342. IpcTag tag,
  343. const Par1& p1,
  344. const Par2& p2,
  345. const Par3& p3,
  346. const Par4& p4,
  347. const Par5& p5,
  348. const Par6& p6,
  349. CrossCallReturn* answer) {
  350. XCALL_GEN_PARAMS_OBJ(6, call_params);
  351. XCALL_GEN_COPY_PARAM(1, call_params);
  352. XCALL_GEN_COPY_PARAM(2, call_params);
  353. XCALL_GEN_COPY_PARAM(3, call_params);
  354. XCALL_GEN_COPY_PARAM(4, call_params);
  355. XCALL_GEN_COPY_PARAM(5, call_params);
  356. XCALL_GEN_COPY_PARAM(6, call_params);
  357. ResultCode result = ipc_provider.DoCall(call_params, answer);
  358. if (SBOX_ERROR_CHANNEL_ERROR != result) {
  359. XCALL_GEN_UPDATE_PARAM(1, call_params);
  360. XCALL_GEN_UPDATE_PARAM(2, call_params);
  361. XCALL_GEN_UPDATE_PARAM(3, call_params);
  362. XCALL_GEN_UPDATE_PARAM(4, call_params);
  363. XCALL_GEN_UPDATE_PARAM(5, call_params);
  364. XCALL_GEN_UPDATE_PARAM(6, call_params);
  365. XCALL_GEN_FREE_CHANNEL();
  366. }
  367. return result;
  368. }
  369. // CrossCall template with seven input parameters.
  370. template <typename IPCProvider,
  371. typename Par1,
  372. typename Par2,
  373. typename Par3,
  374. typename Par4,
  375. typename Par5,
  376. typename Par6,
  377. typename Par7>
  378. ResultCode CrossCall(IPCProvider& ipc_provider,
  379. IpcTag tag,
  380. const Par1& p1,
  381. const Par2& p2,
  382. const Par3& p3,
  383. const Par4& p4,
  384. const Par5& p5,
  385. const Par6& p6,
  386. const Par7& p7,
  387. CrossCallReturn* answer) {
  388. XCALL_GEN_PARAMS_OBJ(7, call_params);
  389. XCALL_GEN_COPY_PARAM(1, call_params);
  390. XCALL_GEN_COPY_PARAM(2, call_params);
  391. XCALL_GEN_COPY_PARAM(3, call_params);
  392. XCALL_GEN_COPY_PARAM(4, call_params);
  393. XCALL_GEN_COPY_PARAM(5, call_params);
  394. XCALL_GEN_COPY_PARAM(6, call_params);
  395. XCALL_GEN_COPY_PARAM(7, call_params);
  396. ResultCode result = ipc_provider.DoCall(call_params, answer);
  397. if (SBOX_ERROR_CHANNEL_ERROR != result) {
  398. XCALL_GEN_UPDATE_PARAM(1, call_params);
  399. XCALL_GEN_UPDATE_PARAM(2, call_params);
  400. XCALL_GEN_UPDATE_PARAM(3, call_params);
  401. XCALL_GEN_UPDATE_PARAM(4, call_params);
  402. XCALL_GEN_UPDATE_PARAM(5, call_params);
  403. XCALL_GEN_UPDATE_PARAM(6, call_params);
  404. XCALL_GEN_UPDATE_PARAM(7, call_params);
  405. XCALL_GEN_FREE_CHANNEL();
  406. }
  407. return result;
  408. }
  409. } // namespace sandbox
  410. #endif // SANDBOX_WIN_SRC_CROSSCALL_CLIENT_H_