crosscall_server.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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. #include "sandbox/win/src/crosscall_server.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <atomic>
  8. #include <string>
  9. #include <vector>
  10. #include "base/check.h"
  11. #include "base/strings/utf_string_conversions.h"
  12. #include "sandbox/win/src/crosscall_client.h"
  13. #include "sandbox/win/src/crosscall_params.h"
  14. // See comment in atomicops.h. This is needed any time windows.h is included
  15. // after atomicops.h.
  16. #undef MemoryBarrier
  17. // This code performs the ipc message validation. Potential security flaws
  18. // on the ipc are likelier to be found in this code than in the rest of
  19. // the ipc code.
  20. namespace {
  21. // The buffer for a message must match the max channel size.
  22. const size_t kMaxBufferSize = sandbox::kIPCChannelSize;
  23. } // namespace
  24. namespace sandbox {
  25. // Returns the actual size for the parameters in an IPC buffer. Returns
  26. // zero if the |param_count| is zero or too big.
  27. uint32_t GetActualBufferSize(uint32_t param_count, void* buffer_base) {
  28. // The template types are used to calculate the maximum expected size.
  29. typedef ActualCallParams<1, kMaxBufferSize> ActualCP1;
  30. typedef ActualCallParams<2, kMaxBufferSize> ActualCP2;
  31. typedef ActualCallParams<3, kMaxBufferSize> ActualCP3;
  32. typedef ActualCallParams<4, kMaxBufferSize> ActualCP4;
  33. typedef ActualCallParams<5, kMaxBufferSize> ActualCP5;
  34. typedef ActualCallParams<6, kMaxBufferSize> ActualCP6;
  35. typedef ActualCallParams<7, kMaxBufferSize> ActualCP7;
  36. typedef ActualCallParams<8, kMaxBufferSize> ActualCP8;
  37. typedef ActualCallParams<9, kMaxBufferSize> ActualCP9;
  38. // Retrieve the actual size and the maximum size of the params buffer.
  39. switch (param_count) {
  40. case 0:
  41. return 0;
  42. case 1:
  43. return reinterpret_cast<ActualCP1*>(buffer_base)->GetSize();
  44. case 2:
  45. return reinterpret_cast<ActualCP2*>(buffer_base)->GetSize();
  46. case 3:
  47. return reinterpret_cast<ActualCP3*>(buffer_base)->GetSize();
  48. case 4:
  49. return reinterpret_cast<ActualCP4*>(buffer_base)->GetSize();
  50. case 5:
  51. return reinterpret_cast<ActualCP5*>(buffer_base)->GetSize();
  52. case 6:
  53. return reinterpret_cast<ActualCP6*>(buffer_base)->GetSize();
  54. case 7:
  55. return reinterpret_cast<ActualCP7*>(buffer_base)->GetSize();
  56. case 8:
  57. return reinterpret_cast<ActualCP8*>(buffer_base)->GetSize();
  58. case 9:
  59. return reinterpret_cast<ActualCP9*>(buffer_base)->GetSize();
  60. default:
  61. return 0;
  62. }
  63. }
  64. // Verifies that the declared sizes of an IPC buffer are within range.
  65. bool IsSizeWithinRange(uint32_t buffer_size,
  66. uint32_t min_declared_size,
  67. uint32_t declared_size) {
  68. if ((buffer_size < min_declared_size) ||
  69. (sizeof(CrossCallParamsEx) > min_declared_size)) {
  70. // Minimal computed size bigger than existing buffer or param_count
  71. // integer overflow.
  72. return false;
  73. }
  74. if ((declared_size > buffer_size) || (declared_size < min_declared_size)) {
  75. // Declared size is bigger than buffer or smaller than computed size
  76. // or param_count is equal to 0 or bigger than 9.
  77. return false;
  78. }
  79. return true;
  80. }
  81. CrossCallParamsEx::CrossCallParamsEx() : CrossCallParams(IpcTag::UNUSED, 0) {}
  82. // We override the delete operator because the object's backing memory
  83. // is hand allocated in CreateFromBuffer. We don't override the new operator
  84. // because the constructors are private so there is no way to mismatch
  85. // new & delete.
  86. void CrossCallParamsEx::operator delete(void* raw_memory) throw() {
  87. if (!raw_memory) {
  88. // C++ standard allows 'delete 0' behavior.
  89. return;
  90. }
  91. delete[] reinterpret_cast<char*>(raw_memory);
  92. }
  93. // This function uses a SEH try block so cannot use C++ objects that
  94. // have destructors or else you get Compiler Error C2712. So no DCHECKs
  95. // inside this function.
  96. CrossCallParamsEx* CrossCallParamsEx::CreateFromBuffer(void* buffer_base,
  97. uint32_t buffer_size,
  98. uint32_t* output_size) {
  99. // IMPORTANT: Everything inside buffer_base and derived from it such
  100. // as param_count and declared_size is untrusted.
  101. if (!buffer_base)
  102. return nullptr;
  103. if (buffer_size < sizeof(CrossCallParams))
  104. return nullptr;
  105. if (buffer_size > kMaxBufferSize)
  106. return nullptr;
  107. char* backing_mem = nullptr;
  108. uint32_t param_count = 0;
  109. uint32_t declared_size;
  110. uint32_t min_declared_size;
  111. CrossCallParamsEx* copied_params = nullptr;
  112. // Touching the untrusted buffer is done under a SEH try block. This
  113. // will catch memory access violations so we don't crash.
  114. __try {
  115. CrossCallParams* call_params =
  116. reinterpret_cast<CrossCallParams*>(buffer_base);
  117. // Check against the minimum size given the number of stated params
  118. // if too small we bail out.
  119. param_count = call_params->GetParamsCount();
  120. min_declared_size =
  121. sizeof(CrossCallParams) + ((param_count + 1) * sizeof(ParamInfo));
  122. // Initial check for the buffer being big enough to determine the actual
  123. // buffer size.
  124. if (buffer_size < min_declared_size)
  125. return nullptr;
  126. // Retrieve the declared size which if it fails returns 0.
  127. declared_size = GetActualBufferSize(param_count, buffer_base);
  128. if (!IsSizeWithinRange(buffer_size, min_declared_size, declared_size))
  129. return nullptr;
  130. // Now we copy the actual amount of the message.
  131. *output_size = declared_size;
  132. backing_mem = new char[declared_size];
  133. copied_params = reinterpret_cast<CrossCallParamsEx*>(backing_mem);
  134. memcpy(backing_mem, call_params, declared_size);
  135. // Avoid compiler optimizations across this point. Any value stored in
  136. // memory should be stored for real, and values previously read from memory
  137. // should be actually read.
  138. std::atomic_thread_fence(std::memory_order_seq_cst);
  139. min_declared_size =
  140. sizeof(CrossCallParams) + ((param_count + 1) * sizeof(ParamInfo));
  141. // Check that the copied buffer is still valid.
  142. if (copied_params->GetParamsCount() != param_count ||
  143. GetActualBufferSize(param_count, backing_mem) != declared_size ||
  144. !IsSizeWithinRange(buffer_size, min_declared_size, declared_size)) {
  145. delete[] backing_mem;
  146. return nullptr;
  147. }
  148. } __except (EXCEPTION_EXECUTE_HANDLER) {
  149. // In case of a windows exception we know it occurred while touching the
  150. // untrusted buffer so we bail out as is.
  151. delete[] backing_mem;
  152. return nullptr;
  153. }
  154. // Here and below we're making use of uintptr_t to have well-defined integer
  155. // overflow when doing pointer arithmetic.
  156. auto backing_mem_ptr = reinterpret_cast<uintptr_t>(backing_mem);
  157. auto last_byte = reinterpret_cast<uintptr_t>(&backing_mem[declared_size]);
  158. auto first_byte =
  159. reinterpret_cast<uintptr_t>(&backing_mem[min_declared_size]);
  160. // Verify here that all and each parameters make sense. This is done in the
  161. // local copy.
  162. for (uint32_t ix = 0; ix != param_count; ++ix) {
  163. uint32_t size = 0;
  164. ArgType type;
  165. auto address = reinterpret_cast<uintptr_t>(
  166. copied_params->GetRawParameter(ix, &size, &type));
  167. if ((!address) || // No null params.
  168. (INVALID_TYPE >= type) || (LAST_TYPE <= type) || // Unknown type.
  169. (address < backing_mem_ptr) || // Start cannot point before buffer.
  170. (address < first_byte) || // Start cannot point too low.
  171. (address > last_byte) || // Start cannot point past buffer.
  172. ((address + size) < address) || // Invalid size.
  173. ((address + size) > last_byte)) { // End cannot point past buffer.
  174. // Malformed.
  175. delete[] backing_mem;
  176. return nullptr;
  177. }
  178. }
  179. // The parameter buffer looks good.
  180. return copied_params;
  181. }
  182. // Accessors to the parameters in the raw buffer.
  183. void* CrossCallParamsEx::GetRawParameter(uint32_t index,
  184. uint32_t* size,
  185. ArgType* type) {
  186. if (index >= GetParamsCount())
  187. return nullptr;
  188. // The size is always computed from the parameter minus the next
  189. // parameter, this works because the message has an extra parameter slot
  190. *size = param_info_[index].size_;
  191. *type = param_info_[index].type_;
  192. return param_info_[index].offset_ + reinterpret_cast<char*>(this);
  193. }
  194. // Covers common case for 32 bit integers.
  195. bool CrossCallParamsEx::GetParameter32(uint32_t index, uint32_t* param) {
  196. uint32_t size = 0;
  197. ArgType type;
  198. void* start = GetRawParameter(index, &size, &type);
  199. if (!start || (4 != size) || (UINT32_TYPE != type))
  200. return false;
  201. // Copy the 4 bytes.
  202. *(reinterpret_cast<uint32_t*>(param)) = *(reinterpret_cast<uint32_t*>(start));
  203. return true;
  204. }
  205. bool CrossCallParamsEx::GetParameterVoidPtr(uint32_t index, void** param) {
  206. uint32_t size = 0;
  207. ArgType type;
  208. void* start = GetRawParameter(index, &size, &type);
  209. if (!start || (sizeof(void*) != size) || (VOIDPTR_TYPE != type))
  210. return false;
  211. *param = *(reinterpret_cast<void**>(start));
  212. return true;
  213. }
  214. // Covers the common case of reading a string. Note that the string is not
  215. // scanned for invalid characters.
  216. bool CrossCallParamsEx::GetParameterStr(uint32_t index, std::wstring* string) {
  217. DCHECK(string->empty());
  218. uint32_t size = 0;
  219. ArgType type;
  220. void* start = GetRawParameter(index, &size, &type);
  221. if (WCHAR_TYPE != type)
  222. return false;
  223. // Check if this is an empty string.
  224. if (size == 0) {
  225. *string = std::wstring();
  226. return true;
  227. }
  228. if (!start || ((size % sizeof(wchar_t)) != 0))
  229. return false;
  230. string->assign(reinterpret_cast<const wchar_t*>(start),
  231. size / sizeof(wchar_t));
  232. return true;
  233. }
  234. bool CrossCallParamsEx::GetParameterPtr(uint32_t index,
  235. uint32_t expected_size,
  236. void** pointer) {
  237. uint32_t size = 0;
  238. ArgType type;
  239. void* start = GetRawParameter(index, &size, &type);
  240. if ((size != expected_size) || (INOUTPTR_TYPE != type))
  241. return false;
  242. if (!start)
  243. return false;
  244. *pointer = start;
  245. return true;
  246. }
  247. void SetCallError(ResultCode error, CrossCallReturn* call_return) {
  248. call_return->call_outcome = error;
  249. call_return->extended_count = 0;
  250. }
  251. void SetCallSuccess(CrossCallReturn* call_return) {
  252. call_return->call_outcome = SBOX_ALL_OK;
  253. }
  254. Dispatcher* Dispatcher::OnMessageReady(IPCParams* ipc,
  255. CallbackGeneric* callback) {
  256. DCHECK(callback);
  257. std::vector<IPCCall>::iterator it = ipc_calls_.begin();
  258. for (; it != ipc_calls_.end(); ++it) {
  259. if (it->params.Matches(ipc)) {
  260. *callback = it->callback;
  261. return this;
  262. }
  263. }
  264. return nullptr;
  265. }
  266. Dispatcher::Dispatcher() {}
  267. Dispatcher::~Dispatcher() {}
  268. } // namespace sandbox