policy_low_level.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  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_low_level.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <map>
  8. #include <string>
  9. #include "base/compiler_specific.h"
  10. namespace {
  11. // A single rule can use at most this amount of memory.
  12. const size_t kRuleBufferSize = 1024 * 4;
  13. // The possible states of the string matching opcode generator.
  14. enum {
  15. PENDING_NONE,
  16. PENDING_ASTERISK, // Have seen an '*' but have not generated an opcode.
  17. PENDING_QMARK, // Have seen an '?' but have not generated an opcode.
  18. };
  19. // The category of the last character seen by the string matching opcode
  20. // generator.
  21. const uint32_t kLastCharIsNone = 0;
  22. const uint32_t kLastCharIsAlpha = 1;
  23. const uint32_t kLastCharIsWild = 2;
  24. const uint32_t kLastCharIsAsterisk = kLastCharIsWild + 4;
  25. const uint32_t kLastCharIsQuestionM = kLastCharIsWild + 8;
  26. } // namespace
  27. namespace sandbox {
  28. LowLevelPolicy::LowLevelPolicy(PolicyGlobal* policy_store)
  29. : policy_store_(policy_store) {}
  30. // Adding a rule is nothing more than pushing it into an stl container. Done()
  31. // is called for the rule in case the code that made the rule in the first
  32. // place has not done it.
  33. bool LowLevelPolicy::AddRule(IpcTag service, PolicyRule* rule) {
  34. if (!rule->Done()) {
  35. return false;
  36. }
  37. PolicyRule* local_rule = new PolicyRule(*rule);
  38. RuleNode node = {local_rule, service};
  39. rules_.push_back(node);
  40. return true;
  41. }
  42. LowLevelPolicy::~LowLevelPolicy() {
  43. // Delete all the rules.
  44. typedef std::list<RuleNode> RuleNodes;
  45. for (RuleNodes::iterator it = rules_.begin(); it != rules_.end(); ++it) {
  46. delete it->rule;
  47. }
  48. }
  49. // Here is where the heavy byte shuffling is done. We take all the rules and
  50. // 'compile' them into a single memory region. Now, the rules are in random
  51. // order so the first step is to reorganize them into a stl map that is keyed
  52. // by the service id and as a value contains a list with all the rules that
  53. // belong to that service. Then we enter the big for-loop where we carve a
  54. // memory zone for the opcodes and the data and call RebindCopy on each rule
  55. // so they all end up nicely packed in the policy_store_.
  56. bool LowLevelPolicy::Done() {
  57. typedef std::list<RuleNode> RuleNodes;
  58. typedef std::list<const PolicyRule*> RuleList;
  59. typedef std::map<IpcTag, RuleList> Mmap;
  60. Mmap mmap;
  61. for (RuleNodes::iterator it = rules_.begin(); it != rules_.end(); ++it) {
  62. mmap[it->service].push_back(it->rule);
  63. }
  64. PolicyBuffer* current_buffer = &policy_store_->data[0];
  65. char* buffer_end =
  66. reinterpret_cast<char*>(current_buffer) + policy_store_->data_size;
  67. size_t avail_size = policy_store_->data_size;
  68. for (Mmap::iterator it = mmap.begin(); it != mmap.end(); ++it) {
  69. IpcTag service = (*it).first;
  70. if (static_cast<size_t>(service) >= kMaxServiceCount) {
  71. return false;
  72. }
  73. policy_store_->entry[static_cast<size_t>(service)] = current_buffer;
  74. RuleList::iterator rules_it = (*it).second.begin();
  75. RuleList::iterator rules_it_end = (*it).second.end();
  76. size_t svc_opcode_count = 0;
  77. for (; rules_it != rules_it_end; ++rules_it) {
  78. const PolicyRule* rule = (*rules_it);
  79. size_t op_count = rule->GetOpcodeCount();
  80. size_t opcodes_size = op_count * sizeof(PolicyOpcode);
  81. if (avail_size < opcodes_size) {
  82. return false;
  83. }
  84. size_t data_size = avail_size - opcodes_size;
  85. PolicyOpcode* opcodes_start = &current_buffer->opcodes[svc_opcode_count];
  86. if (!rule->RebindCopy(opcodes_start, opcodes_size, buffer_end,
  87. &data_size)) {
  88. return false;
  89. }
  90. size_t used = avail_size - data_size;
  91. buffer_end -= used;
  92. avail_size -= used;
  93. svc_opcode_count += op_count;
  94. }
  95. current_buffer->opcode_count = svc_opcode_count;
  96. size_t policy_buffers_occupied =
  97. (svc_opcode_count * sizeof(PolicyOpcode)) / sizeof(current_buffer[0]);
  98. current_buffer = &current_buffer[policy_buffers_occupied + 1];
  99. }
  100. return true;
  101. }
  102. PolicyRule::PolicyRule(EvalResult action) : action_(action), done_(false) {
  103. char* memory = new char[sizeof(PolicyBuffer) + kRuleBufferSize];
  104. buffer_ = reinterpret_cast<PolicyBuffer*>(memory);
  105. buffer_->opcode_count = 0;
  106. opcode_factory_ =
  107. new OpcodeFactory(buffer_, kRuleBufferSize + sizeof(PolicyOpcode));
  108. }
  109. PolicyRule::PolicyRule(const PolicyRule& other) {
  110. if (this == &other)
  111. return;
  112. action_ = other.action_;
  113. done_ = other.done_;
  114. size_t buffer_size = sizeof(PolicyBuffer) + kRuleBufferSize;
  115. char* memory = new char[buffer_size];
  116. buffer_ = reinterpret_cast<PolicyBuffer*>(memory);
  117. memcpy(buffer_, other.buffer_, buffer_size);
  118. char* opcode_buffer = reinterpret_cast<char*>(&buffer_->opcodes[0]);
  119. char* next_opcode = &opcode_buffer[GetOpcodeCount() * sizeof(PolicyOpcode)];
  120. opcode_factory_ =
  121. new OpcodeFactory(next_opcode, other.opcode_factory_->memory_size());
  122. }
  123. // This function get called from a simple state machine implemented in
  124. // AddStringMatch() which passes the current state (in state) and it passes
  125. // true in last_call if AddStringMatch() has finished processing the input
  126. // pattern string and this would be the last call to generate any pending
  127. // opcode. The skip_count is the currently accumulated number of '?' seen so
  128. // far and once the associated opcode is generated this function sets it back
  129. // to zero.
  130. bool PolicyRule::GenStringOpcode(RuleType rule_type,
  131. StringMatchOptions match_opts,
  132. uint16_t parameter,
  133. int state,
  134. bool last_call,
  135. int* skip_count,
  136. std::wstring* fragment) {
  137. // The last opcode must:
  138. // 1) Always clear the context.
  139. // 2) Preserve the negation.
  140. // 3) Remove the 'OR' mode flag.
  141. uint32_t options = kPolNone;
  142. if (last_call) {
  143. if (IF_NOT == rule_type) {
  144. options = kPolClearContext | kPolNegateEval;
  145. } else {
  146. options = kPolClearContext;
  147. }
  148. } else if (IF_NOT == rule_type) {
  149. options = kPolUseOREval | kPolNegateEval;
  150. }
  151. PolicyOpcode* op = nullptr;
  152. // The fragment string contains the accumulated characters to match with, it
  153. // never contains wildcards (unless they have been escaped) and while there
  154. // is no fragment there is no new string match opcode to generate.
  155. if (fragment->empty()) {
  156. // There is no new opcode to generate but in the last call we have to fix
  157. // the previous opcode because it was really the last but we did not know
  158. // it at that time.
  159. if (last_call && (buffer_->opcode_count > 0)) {
  160. op = &buffer_->opcodes[buffer_->opcode_count - 1];
  161. op->SetOptions(options);
  162. }
  163. return true;
  164. }
  165. if (PENDING_ASTERISK == state) {
  166. if (last_call) {
  167. op = opcode_factory_->MakeOpWStringMatch(parameter, fragment->c_str(),
  168. kSeekToEnd, match_opts, options);
  169. } else {
  170. op = opcode_factory_->MakeOpWStringMatch(
  171. parameter, fragment->c_str(), kSeekForward, match_opts, options);
  172. }
  173. } else if (PENDING_QMARK == state) {
  174. op = opcode_factory_->MakeOpWStringMatch(parameter, fragment->c_str(),
  175. *skip_count, match_opts, options);
  176. *skip_count = 0;
  177. } else {
  178. if (last_call) {
  179. match_opts = static_cast<StringMatchOptions>(EXACT_LENGTH | match_opts);
  180. }
  181. op = opcode_factory_->MakeOpWStringMatch(parameter, fragment->c_str(), 0,
  182. match_opts, options);
  183. }
  184. if (!op)
  185. return false;
  186. ++buffer_->opcode_count;
  187. fragment->clear();
  188. return true;
  189. }
  190. bool PolicyRule::AddStringMatch(RuleType rule_type,
  191. int16_t parameter,
  192. const wchar_t* string,
  193. StringMatchOptions match_opts) {
  194. if (done_) {
  195. // Do not allow to add more rules after generating the action opcode.
  196. return false;
  197. }
  198. const wchar_t* current_char = string;
  199. uint32_t last_char = kLastCharIsNone;
  200. int state = PENDING_NONE;
  201. int skip_count = 0; // counts how many '?' we have seen in a row.
  202. std::wstring fragment; // accumulates the non-wildcard part.
  203. while (L'\0' != *current_char) {
  204. switch (*current_char) {
  205. case L'*':
  206. if (kLastCharIsWild & last_char) {
  207. // '**' and '&*' is an error.
  208. return false;
  209. }
  210. if (!GenStringOpcode(rule_type, match_opts, parameter, state, false,
  211. &skip_count, &fragment)) {
  212. return false;
  213. }
  214. last_char = kLastCharIsAsterisk;
  215. state = PENDING_ASTERISK;
  216. break;
  217. case L'?':
  218. if (kLastCharIsAsterisk == last_char) {
  219. // '*?' is an error.
  220. return false;
  221. }
  222. if (!GenStringOpcode(rule_type, match_opts, parameter, state, false,
  223. &skip_count, &fragment)) {
  224. return false;
  225. }
  226. ++skip_count;
  227. last_char = kLastCharIsQuestionM;
  228. state = PENDING_QMARK;
  229. break;
  230. case L'/':
  231. // Note: "/?" is an escaped '?'. Eat the slash and fall through.
  232. if (L'?' == current_char[1]) {
  233. ++current_char;
  234. }
  235. [[fallthrough]];
  236. default:
  237. fragment += *current_char;
  238. last_char = kLastCharIsAlpha;
  239. }
  240. ++current_char;
  241. }
  242. if (!GenStringOpcode(rule_type, match_opts, parameter, state, true,
  243. &skip_count, &fragment)) {
  244. return false;
  245. }
  246. return true;
  247. }
  248. bool PolicyRule::AddNumberMatch(RuleType rule_type,
  249. int16_t parameter,
  250. uint32_t number,
  251. RuleOp comparison_op) {
  252. if (done_) {
  253. // Do not allow to add more rules after generating the action opcode.
  254. return false;
  255. }
  256. uint32_t opts = (rule_type == IF_NOT) ? kPolNegateEval : kPolNone;
  257. if (EQUAL == comparison_op) {
  258. if (!opcode_factory_->MakeOpNumberMatch(parameter, number, opts))
  259. return false;
  260. } else if (AND == comparison_op) {
  261. if (!opcode_factory_->MakeOpNumberAndMatch(parameter, number, opts))
  262. return false;
  263. }
  264. ++buffer_->opcode_count;
  265. return true;
  266. }
  267. bool PolicyRule::Done() {
  268. if (done_) {
  269. return true;
  270. }
  271. if (!opcode_factory_->MakeOpAction(action_, kPolNone))
  272. return false;
  273. ++buffer_->opcode_count;
  274. done_ = true;
  275. return true;
  276. }
  277. bool PolicyRule::RebindCopy(PolicyOpcode* opcode_start,
  278. size_t opcode_size,
  279. char* data_start,
  280. size_t* data_size) const {
  281. size_t count = buffer_->opcode_count;
  282. for (size_t ix = 0; ix != count; ++ix) {
  283. if (opcode_size < sizeof(PolicyOpcode)) {
  284. return false;
  285. }
  286. PolicyOpcode& opcode = buffer_->opcodes[ix];
  287. *opcode_start = opcode;
  288. if (OP_WSTRING_MATCH == opcode.GetID()) {
  289. // For this opcode argument 0 is a delta to the string and argument 1
  290. // is the length (in chars) of the string.
  291. const wchar_t* str = opcode.GetRelativeString(0);
  292. size_t str_len;
  293. opcode.GetArgument(1, &str_len);
  294. str_len = str_len * sizeof(wchar_t);
  295. if ((*data_size) < str_len) {
  296. return false;
  297. }
  298. *data_size -= str_len;
  299. data_start -= str_len;
  300. memcpy(data_start, str, str_len);
  301. // Recompute the string displacement
  302. ptrdiff_t delta = data_start - reinterpret_cast<char*>(opcode_start);
  303. opcode_start->SetArgument(0, delta);
  304. }
  305. ++opcode_start;
  306. opcode_size -= sizeof(PolicyOpcode);
  307. }
  308. return true;
  309. }
  310. PolicyRule::~PolicyRule() {
  311. delete[] reinterpret_cast<char*>(buffer_.get());
  312. delete opcode_factory_;
  313. }
  314. } // namespace sandbox