policy_engine_opcodes.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. // Copyright (c) 2006-2008 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/policy_engine_opcodes.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include "base/check_op.h"
  8. #include "sandbox/win/src/sandbox_nt_types.h"
  9. #include "sandbox/win/src/sandbox_nt_util.h"
  10. #include "sandbox/win/src/sandbox_types.h"
  11. namespace {
  12. const unsigned short kMaxUniStrSize = 0xfffc / sizeof(wchar_t);
  13. bool InitStringUnicode(const wchar_t* source,
  14. size_t length,
  15. UNICODE_STRING* ustring) {
  16. if (length > kMaxUniStrSize) {
  17. return false;
  18. }
  19. ustring->Buffer = const_cast<wchar_t*>(source);
  20. ustring->Length = static_cast<USHORT>(length) * sizeof(wchar_t);
  21. ustring->MaximumLength = source ? ustring->Length + sizeof(wchar_t) : 0;
  22. return true;
  23. }
  24. } // namespace
  25. namespace sandbox {
  26. // Note: The opcodes are implemented as functions (as opposed to classes derived
  27. // from PolicyOpcode) because you should not add more member variables to the
  28. // PolicyOpcode class since it would cause object slicing on the target. So to
  29. // enforce that (instead of just trusting the developer) the opcodes became
  30. // just functions.
  31. //
  32. // In the code that follows I have keep the evaluation function and the factory
  33. // function together to stress the close relationship between both. For example,
  34. // only the factory method and the evaluation function know the stored argument
  35. // order and meaning.
  36. size_t OpcodeFactory::memory_size() const {
  37. DCHECK_GE(memory_bottom_, memory_top_);
  38. return memory_bottom_ - memory_top_;
  39. }
  40. template <int>
  41. EvalResult OpcodeEval(PolicyOpcode* opcode,
  42. const ParameterSet* pp,
  43. MatchContext* match);
  44. //////////////////////////////////////////////////////////////////////////////
  45. // Opcode OpAlwaysFalse:
  46. // Does not require input parameter.
  47. PolicyOpcode* OpcodeFactory::MakeOpAlwaysFalse(uint32_t options) {
  48. return MakeBase(OP_ALWAYS_FALSE, options, -1);
  49. }
  50. template <>
  51. EvalResult OpcodeEval<OP_ALWAYS_FALSE>(PolicyOpcode* opcode,
  52. const ParameterSet* param,
  53. MatchContext* context) {
  54. return EVAL_FALSE;
  55. }
  56. //////////////////////////////////////////////////////////////////////////////
  57. // Opcode OpAlwaysTrue:
  58. // Does not require input parameter.
  59. PolicyOpcode* OpcodeFactory::MakeOpAlwaysTrue(uint32_t options) {
  60. return MakeBase(OP_ALWAYS_TRUE, options, -1);
  61. }
  62. template <>
  63. EvalResult OpcodeEval<OP_ALWAYS_TRUE>(PolicyOpcode* opcode,
  64. const ParameterSet* param,
  65. MatchContext* context) {
  66. return EVAL_TRUE;
  67. }
  68. //////////////////////////////////////////////////////////////////////////////
  69. // Opcode OpAction:
  70. // Does not require input parameter.
  71. // Argument 0 contains the actual action to return.
  72. PolicyOpcode* OpcodeFactory::MakeOpAction(EvalResult action, uint32_t options) {
  73. PolicyOpcode* opcode = MakeBase(OP_ACTION, options, 0);
  74. if (!opcode)
  75. return nullptr;
  76. opcode->SetArgument(0, action);
  77. return opcode;
  78. }
  79. template <>
  80. EvalResult OpcodeEval<OP_ACTION>(PolicyOpcode* opcode,
  81. const ParameterSet* param,
  82. MatchContext* context) {
  83. int action = 0;
  84. opcode->GetArgument(0, &action);
  85. return static_cast<EvalResult>(action);
  86. }
  87. //////////////////////////////////////////////////////////////////////////////
  88. // Opcode OpNumberMatch:
  89. // Requires a uint32_t or void* in selected_param
  90. // Argument 0 is the stored number to match.
  91. // Argument 1 is the C++ type of the 0th argument.
  92. PolicyOpcode* OpcodeFactory::MakeOpNumberMatch(int16_t selected_param,
  93. uint32_t match,
  94. uint32_t options) {
  95. PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH, options, selected_param);
  96. if (!opcode)
  97. return nullptr;
  98. opcode->SetArgument(0, match);
  99. opcode->SetArgument(1, UINT32_TYPE);
  100. return opcode;
  101. }
  102. PolicyOpcode* OpcodeFactory::MakeOpVoidPtrMatch(int16_t selected_param,
  103. const void* match,
  104. uint32_t options) {
  105. PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH, options, selected_param);
  106. if (!opcode)
  107. return nullptr;
  108. opcode->SetArgument(0, match);
  109. opcode->SetArgument(1, VOIDPTR_TYPE);
  110. return opcode;
  111. }
  112. template <>
  113. EvalResult OpcodeEval<OP_NUMBER_MATCH>(PolicyOpcode* opcode,
  114. const ParameterSet* param,
  115. MatchContext* context) {
  116. uint32_t value_uint32 = 0;
  117. if (param->Get(&value_uint32)) {
  118. uint32_t match_uint32 = 0;
  119. opcode->GetArgument(0, &match_uint32);
  120. return (match_uint32 != value_uint32) ? EVAL_FALSE : EVAL_TRUE;
  121. } else {
  122. const void* value_ptr = nullptr;
  123. if (param->Get(&value_ptr)) {
  124. const void* match_ptr = nullptr;
  125. opcode->GetArgument(0, &match_ptr);
  126. return (match_ptr != value_ptr) ? EVAL_FALSE : EVAL_TRUE;
  127. }
  128. }
  129. return EVAL_ERROR;
  130. }
  131. //////////////////////////////////////////////////////////////////////////////
  132. // Opcode OpNumberMatchRange
  133. // Requires a uint32_t in selected_param.
  134. // Argument 0 is the stored lower bound to match.
  135. // Argument 1 is the stored upper bound to match.
  136. PolicyOpcode* OpcodeFactory::MakeOpNumberMatchRange(int16_t selected_param,
  137. uint32_t lower_bound,
  138. uint32_t upper_bound,
  139. uint32_t options) {
  140. if (lower_bound > upper_bound) {
  141. return nullptr;
  142. }
  143. PolicyOpcode* opcode =
  144. MakeBase(OP_NUMBER_MATCH_RANGE, options, selected_param);
  145. if (!opcode)
  146. return nullptr;
  147. opcode->SetArgument(0, lower_bound);
  148. opcode->SetArgument(1, upper_bound);
  149. return opcode;
  150. }
  151. template <>
  152. EvalResult OpcodeEval<OP_NUMBER_MATCH_RANGE>(PolicyOpcode* opcode,
  153. const ParameterSet* param,
  154. MatchContext* context) {
  155. uint32_t value = 0;
  156. if (!param->Get(&value))
  157. return EVAL_ERROR;
  158. uint32_t lower_bound = 0;
  159. uint32_t upper_bound = 0;
  160. opcode->GetArgument(0, &lower_bound);
  161. opcode->GetArgument(1, &upper_bound);
  162. return ((lower_bound <= value) && (upper_bound >= value)) ? EVAL_TRUE
  163. : EVAL_FALSE;
  164. }
  165. //////////////////////////////////////////////////////////////////////////////
  166. // Opcode OpNumberAndMatch:
  167. // Requires a uint32_t in selected_param.
  168. // Argument 0 is the stored number to match.
  169. PolicyOpcode* OpcodeFactory::MakeOpNumberAndMatch(int16_t selected_param,
  170. uint32_t match,
  171. uint32_t options) {
  172. PolicyOpcode* opcode = MakeBase(OP_NUMBER_AND_MATCH, options, selected_param);
  173. if (!opcode)
  174. return nullptr;
  175. opcode->SetArgument(0, match);
  176. return opcode;
  177. }
  178. template <>
  179. EvalResult OpcodeEval<OP_NUMBER_AND_MATCH>(PolicyOpcode* opcode,
  180. const ParameterSet* param,
  181. MatchContext* context) {
  182. uint32_t value = 0;
  183. if (!param->Get(&value))
  184. return EVAL_ERROR;
  185. uint32_t number = 0;
  186. opcode->GetArgument(0, &number);
  187. return (number & value) ? EVAL_TRUE : EVAL_FALSE;
  188. }
  189. //////////////////////////////////////////////////////////////////////////////
  190. // Opcode OpWStringMatch:
  191. // Requires a wchar_t* in selected_param.
  192. // Argument 0 is the byte displacement of the stored string.
  193. // Argument 1 is the length in chars of the stored string.
  194. // Argument 2 is the offset to apply on the input string. It has special values.
  195. // as noted in the header file.
  196. // Argument 3 is the string matching options.
  197. PolicyOpcode* OpcodeFactory::MakeOpWStringMatch(int16_t selected_param,
  198. const wchar_t* match_str,
  199. int start_position,
  200. StringMatchOptions match_opts,
  201. uint32_t options) {
  202. if (!match_str)
  203. return nullptr;
  204. if ('\0' == match_str[0])
  205. return nullptr;
  206. int length = lstrlenW(match_str);
  207. PolicyOpcode* opcode = MakeBase(OP_WSTRING_MATCH, options, selected_param);
  208. if (!opcode)
  209. return nullptr;
  210. ptrdiff_t delta_str = AllocRelative(opcode, match_str, wcslen(match_str) + 1);
  211. if (0 == delta_str)
  212. return nullptr;
  213. opcode->SetArgument(0, delta_str);
  214. opcode->SetArgument(1, length);
  215. opcode->SetArgument(2, start_position);
  216. opcode->SetArgument(3, match_opts);
  217. return opcode;
  218. }
  219. template <>
  220. EvalResult OpcodeEval<OP_WSTRING_MATCH>(PolicyOpcode* opcode,
  221. const ParameterSet* param,
  222. MatchContext* context) {
  223. if (!context) {
  224. return EVAL_ERROR;
  225. }
  226. const wchar_t* source_str = nullptr;
  227. if (!param->Get(&source_str))
  228. return EVAL_ERROR;
  229. int start_position = 0;
  230. int match_len = 0;
  231. unsigned int match_opts = 0;
  232. opcode->GetArgument(1, &match_len);
  233. opcode->GetArgument(2, &start_position);
  234. opcode->GetArgument(3, &match_opts);
  235. const wchar_t* match_str = opcode->GetRelativeString(0);
  236. // Advance the source string to the last successfully evaluated position
  237. // according to the match context.
  238. source_str = &source_str[context->position];
  239. int source_len = static_cast<int>(GetNtExports()->wcslen(source_str));
  240. if (0 == source_len) {
  241. // If we reached the end of the source string there is nothing we can
  242. // match against.
  243. return EVAL_FALSE;
  244. }
  245. if (match_len > source_len) {
  246. // There can't be a positive match when the target string is bigger than
  247. // the source string
  248. return EVAL_FALSE;
  249. }
  250. BOOLEAN case_sensitive = (match_opts & CASE_INSENSITIVE) ? TRUE : FALSE;
  251. // We have three cases, depending on the value of start_pos:
  252. // Case 1. We skip N characters and compare once.
  253. // Case 2: We skip to the end and compare once.
  254. // Case 3: We match the first substring (if we find any).
  255. if (start_position >= 0) {
  256. if (kSeekToEnd == start_position) {
  257. start_position = source_len - match_len;
  258. } else if (match_opts & EXACT_LENGTH) {
  259. // A sub-case of case 3 is when the EXACT_LENGTH flag is on
  260. // the match needs to be not just substring but full match.
  261. if ((match_len + start_position) != source_len) {
  262. return EVAL_FALSE;
  263. }
  264. }
  265. // Advance start_pos characters. Warning! this does not consider
  266. // utf16 encodings (surrogate pairs) or other Unicode 'features'.
  267. source_str += start_position;
  268. // Since we skipped, lets reevaluate just the lengths again.
  269. if ((match_len + start_position) > source_len) {
  270. return EVAL_FALSE;
  271. }
  272. UNICODE_STRING match_ustr;
  273. UNICODE_STRING source_ustr;
  274. if (!InitStringUnicode(match_str, match_len, &match_ustr) ||
  275. !InitStringUnicode(source_str, match_len, &source_ustr))
  276. return EVAL_ERROR;
  277. if (0 == GetNtExports()->RtlCompareUnicodeString(&match_ustr, &source_ustr,
  278. case_sensitive)) {
  279. // Match! update the match context.
  280. context->position += start_position + match_len;
  281. return EVAL_TRUE;
  282. } else {
  283. return EVAL_FALSE;
  284. }
  285. } else if (start_position < 0) {
  286. UNICODE_STRING match_ustr;
  287. UNICODE_STRING source_ustr;
  288. if (!InitStringUnicode(match_str, match_len, &match_ustr) ||
  289. !InitStringUnicode(source_str, match_len, &source_ustr))
  290. return EVAL_ERROR;
  291. do {
  292. if (0 == GetNtExports()->RtlCompareUnicodeString(
  293. &match_ustr, &source_ustr, case_sensitive)) {
  294. // Match! update the match context.
  295. context->position += (source_ustr.Buffer - source_str) + match_len;
  296. return EVAL_TRUE;
  297. }
  298. ++source_ustr.Buffer;
  299. --source_len;
  300. } while (source_len >= match_len);
  301. }
  302. return EVAL_FALSE;
  303. }
  304. //////////////////////////////////////////////////////////////////////////////
  305. // OpcodeMaker (other member functions).
  306. PolicyOpcode* OpcodeFactory::MakeBase(OpcodeID opcode_id,
  307. uint32_t options,
  308. int16_t selected_param) {
  309. if (memory_size() < sizeof(PolicyOpcode))
  310. return nullptr;
  311. // Create opcode using placement-new on the buffer memory.
  312. PolicyOpcode* opcode = new (memory_top_) PolicyOpcode();
  313. // Fill in the standard fields, that every opcode has.
  314. memory_top_ += sizeof(PolicyOpcode);
  315. opcode->opcode_id_ = opcode_id;
  316. opcode->SetOptions(options);
  317. opcode->parameter_ = selected_param;
  318. return opcode;
  319. }
  320. ptrdiff_t OpcodeFactory::AllocRelative(void* start,
  321. const wchar_t* str,
  322. size_t length) {
  323. size_t bytes = length * sizeof(wchar_t);
  324. if (memory_size() < bytes)
  325. return 0;
  326. memory_bottom_ -= bytes;
  327. if (reinterpret_cast<UINT_PTR>(memory_bottom_.get()) & 1) {
  328. // TODO(cpu) replace this for something better.
  329. ::DebugBreak();
  330. }
  331. memcpy(memory_bottom_, str, bytes);
  332. ptrdiff_t delta = memory_bottom_ - reinterpret_cast<char*>(start);
  333. return delta;
  334. }
  335. //////////////////////////////////////////////////////////////////////////////
  336. // Opcode evaluation dispatchers.
  337. // This function is the one and only entry for evaluating any opcode. It is
  338. // in charge of applying any relevant opcode options and calling EvaluateInner
  339. // were the actual dispatch-by-id is made. It would seem at first glance that
  340. // the dispatch should be done by virtual function (vtable) calls but you have
  341. // to remember that the opcodes are made in the broker process and copied as
  342. // raw memory to the target process.
  343. EvalResult PolicyOpcode::Evaluate(const ParameterSet* call_params,
  344. size_t param_count,
  345. MatchContext* match) {
  346. if (!call_params)
  347. return EVAL_ERROR;
  348. const ParameterSet* selected_param = nullptr;
  349. if (parameter_ >= 0) {
  350. if (static_cast<size_t>(parameter_) >= param_count) {
  351. return EVAL_ERROR;
  352. }
  353. selected_param = &call_params[parameter_];
  354. }
  355. EvalResult result = EvaluateHelper(selected_param, match);
  356. // Apply the general options regardless of the particular type of opcode.
  357. if (kPolNone == options_) {
  358. return result;
  359. }
  360. if (options_ & kPolNegateEval) {
  361. if (EVAL_TRUE == result) {
  362. result = EVAL_FALSE;
  363. } else if (EVAL_FALSE == result) {
  364. result = EVAL_TRUE;
  365. } else if (EVAL_ERROR != result) {
  366. result = EVAL_ERROR;
  367. }
  368. }
  369. if (match) {
  370. if (options_ & kPolClearContext)
  371. match->Clear();
  372. if (options_ & kPolUseOREval)
  373. match->options = kPolUseOREval;
  374. }
  375. return result;
  376. }
  377. #define OPCODE_EVAL(op, x, y, z) \
  378. case op: \
  379. return OpcodeEval<op>(x, y, z)
  380. EvalResult PolicyOpcode::EvaluateHelper(const ParameterSet* parameters,
  381. MatchContext* match) {
  382. switch (opcode_id_) {
  383. OPCODE_EVAL(OP_ALWAYS_FALSE, this, parameters, match);
  384. OPCODE_EVAL(OP_ALWAYS_TRUE, this, parameters, match);
  385. OPCODE_EVAL(OP_NUMBER_MATCH, this, parameters, match);
  386. OPCODE_EVAL(OP_NUMBER_MATCH_RANGE, this, parameters, match);
  387. OPCODE_EVAL(OP_NUMBER_AND_MATCH, this, parameters, match);
  388. OPCODE_EVAL(OP_WSTRING_MATCH, this, parameters, match);
  389. OPCODE_EVAL(OP_ACTION, this, parameters, match);
  390. default:
  391. return EVAL_ERROR;
  392. }
  393. }
  394. #undef OPCODE_EVAL
  395. } // namespace sandbox