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