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.
5 #include "sandbox/win/src/policy_engine_opcodes.h"
7 #include "base/basictypes.h"
8 #include "sandbox/win/src/sandbox_nt_types.h"
9 #include "sandbox/win/src/sandbox_types.h"
12 const unsigned short kMaxUniStrSize
= 0xfffc;
14 bool InitStringUnicode(const wchar_t* source
, size_t length
,
15 UNICODE_STRING
* ustring
) {
16 ustring
->Buffer
= const_cast<wchar_t*>(source
);
17 ustring
->Length
= static_cast<USHORT
>(length
) * sizeof(wchar_t);
18 if (length
> kMaxUniStrSize
) {
21 ustring
->MaximumLength
= (NULL
!= source
) ?
22 ustring
->Length
+ sizeof(wchar_t) : 0;
30 SANDBOX_INTERCEPT NtExports g_nt
;
32 // Note: The opcodes are implemented as functions (as opposed to classes derived
33 // from PolicyOpcode) because you should not add more member variables to the
34 // PolicyOpcode class since it would cause object slicing on the target. So to
35 // enforce that (instead of just trusting the developer) the opcodes became
38 // In the code that follows I have keep the evaluation function and the factory
39 // function together to stress the close relationship between both. For example,
40 // only the factory method and the evaluation function know the stored argument
44 EvalResult
OpcodeEval(PolicyOpcode
* opcode
, const ParameterSet
* pp
,
47 //////////////////////////////////////////////////////////////////////////////
48 // Opcode OpAlwaysFalse:
49 // Does not require input parameter.
51 PolicyOpcode
* OpcodeFactory::MakeOpAlwaysFalse(uint32 options
) {
52 return MakeBase(OP_ALWAYS_FALSE
, options
, -1);
56 EvalResult OpcodeEval
<OP_ALWAYS_FALSE
>(PolicyOpcode
* opcode
,
57 const ParameterSet
* param
,
58 MatchContext
* context
) {
59 UNREFERENCED_PARAMETER(opcode
);
60 UNREFERENCED_PARAMETER(param
);
61 UNREFERENCED_PARAMETER(context
);
65 //////////////////////////////////////////////////////////////////////////////
66 // Opcode OpAlwaysTrue:
67 // Does not require input parameter.
69 PolicyOpcode
* OpcodeFactory::MakeOpAlwaysTrue(uint32 options
) {
70 return MakeBase(OP_ALWAYS_TRUE
, options
, -1);
74 EvalResult OpcodeEval
<OP_ALWAYS_TRUE
>(PolicyOpcode
* opcode
,
75 const ParameterSet
* param
,
76 MatchContext
* context
) {
77 UNREFERENCED_PARAMETER(opcode
);
78 UNREFERENCED_PARAMETER(param
);
79 UNREFERENCED_PARAMETER(context
);
83 //////////////////////////////////////////////////////////////////////////////
85 // Does not require input parameter.
86 // Argument 0 contains the actual action to return.
88 PolicyOpcode
* OpcodeFactory::MakeOpAction(EvalResult action
,
90 PolicyOpcode
* opcode
= MakeBase(OP_ACTION
, options
, 0);
91 if (NULL
== opcode
) return NULL
;
92 opcode
->SetArgument(0, action
);
97 EvalResult OpcodeEval
<OP_ACTION
>(PolicyOpcode
* opcode
,
98 const ParameterSet
* param
,
99 MatchContext
* context
) {
100 UNREFERENCED_PARAMETER(param
);
101 UNREFERENCED_PARAMETER(context
);
103 opcode
->GetArgument(0, &action
);
104 return static_cast<EvalResult
>(action
);
107 //////////////////////////////////////////////////////////////////////////////
108 // Opcode OpNumberMatch:
109 // Requires a unsigned long or void* in selected_param
110 // Argument 0 is the stored number to match.
111 // Argument 1 is the C++ type of the 0th argument.
113 PolicyOpcode
* OpcodeFactory::MakeOpNumberMatch(int16 selected_param
,
116 PolicyOpcode
* opcode
= MakeBase(OP_NUMBER_MATCH
, options
, selected_param
);
117 if (NULL
== opcode
) return NULL
;
118 opcode
->SetArgument(0, match
);
119 opcode
->SetArgument(1, ULONG_TYPE
);
123 PolicyOpcode
* OpcodeFactory::MakeOpVoidPtrMatch(int16 selected_param
,
126 PolicyOpcode
* opcode
= MakeBase(OP_NUMBER_MATCH
, options
, selected_param
);
127 if (NULL
== opcode
) return NULL
;
128 opcode
->SetArgument(0, match
);
129 opcode
->SetArgument(1, VOIDPTR_TYPE
);
134 EvalResult OpcodeEval
<OP_NUMBER_MATCH
>(PolicyOpcode
* opcode
,
135 const ParameterSet
* param
,
136 MatchContext
* context
) {
137 UNREFERENCED_PARAMETER(context
);
138 unsigned long value_ulong
= 0;
139 if (param
->Get(&value_ulong
)) {
140 unsigned long match_ulong
= 0;
141 opcode
->GetArgument(0, &match_ulong
);
142 return (match_ulong
!= value_ulong
)? EVAL_FALSE
: EVAL_TRUE
;
144 const void* value_ptr
= NULL
;
145 if (param
->Get(&value_ptr
)) {
146 const void* match_ptr
= NULL
;
147 opcode
->GetArgument(0, &match_ptr
);
148 return (match_ptr
!= value_ptr
)? EVAL_FALSE
: EVAL_TRUE
;
154 //////////////////////////////////////////////////////////////////////////////
155 // Opcode OpUlongMatchRange
156 // Requires a unsigned long in selected_param.
157 // Argument 0 is the stored lower bound to match.
158 // Argument 1 is the stored upper bound to match.
160 PolicyOpcode
* OpcodeFactory::MakeOpUlongMatchRange(int16 selected_param
,
161 unsigned long lower_bound
,
162 unsigned long upper_bound
,
164 if (lower_bound
> upper_bound
) {
167 PolicyOpcode
* opcode
= MakeBase(OP_ULONG_MATCH_RANGE
, options
,
169 if (NULL
== opcode
) return NULL
;
170 opcode
->SetArgument(0, lower_bound
);
171 opcode
->SetArgument(1, upper_bound
);
176 EvalResult OpcodeEval
<OP_ULONG_MATCH_RANGE
>(PolicyOpcode
* opcode
,
177 const ParameterSet
* param
,
178 MatchContext
* context
) {
179 UNREFERENCED_PARAMETER(context
);
180 unsigned long value
= 0;
181 if (!param
->Get(&value
)) return EVAL_ERROR
;
183 unsigned long lower_bound
= 0;
184 unsigned long upper_bound
= 0;
185 opcode
->GetArgument(0, &lower_bound
);
186 opcode
->GetArgument(1, &upper_bound
);
187 return((lower_bound
<= value
) && (upper_bound
>= value
))?
188 EVAL_TRUE
: EVAL_FALSE
;
191 //////////////////////////////////////////////////////////////////////////////
192 // Opcode OpUlongAndMatch:
193 // Requires a unsigned long in selected_param.
194 // Argument 0 is the stored number to match.
196 PolicyOpcode
* OpcodeFactory::MakeOpUlongAndMatch(int16 selected_param
,
199 PolicyOpcode
* opcode
= MakeBase(OP_ULONG_AND_MATCH
, options
, selected_param
);
200 if (NULL
== opcode
) return NULL
;
201 opcode
->SetArgument(0, match
);
206 EvalResult OpcodeEval
<OP_ULONG_AND_MATCH
>(PolicyOpcode
* opcode
,
207 const ParameterSet
* param
,
208 MatchContext
* context
) {
209 UNREFERENCED_PARAMETER(context
);
210 unsigned long value
= 0;
211 if (!param
->Get(&value
)) return EVAL_ERROR
;
213 unsigned long number
= 0;
214 opcode
->GetArgument(0, &number
);
215 return (number
& value
)? EVAL_TRUE
: EVAL_FALSE
;
218 //////////////////////////////////////////////////////////////////////////////
219 // Opcode OpWStringMatch:
220 // Requires a wchar_t* in selected_param.
221 // Argument 0 is the byte displacement of the stored string.
222 // Argument 1 is the lenght in chars of the stored string.
223 // Argument 2 is the offset to apply on the input string. It has special values.
224 // as noted in the header file.
225 // Argument 3 is the string matching options.
227 PolicyOpcode
* OpcodeFactory::MakeOpWStringMatch(int16 selected_param
,
228 const wchar_t* match_str
,
230 StringMatchOptions match_opts
,
232 if (NULL
== match_str
) {
235 if ('\0' == match_str
[0]) {
239 int lenght
= lstrlenW(match_str
);
241 PolicyOpcode
* opcode
= MakeBase(OP_WSTRING_MATCH
, options
, selected_param
);
242 if (NULL
== opcode
) {
245 ptrdiff_t delta_str
= AllocRelative(opcode
, match_str
, wcslen(match_str
)+1);
246 if (0 == delta_str
) {
249 opcode
->SetArgument(0, delta_str
);
250 opcode
->SetArgument(1, lenght
);
251 opcode
->SetArgument(2, start_position
);
252 opcode
->SetArgument(3, match_opts
);
257 EvalResult OpcodeEval
<OP_WSTRING_MATCH
>(PolicyOpcode
* opcode
,
258 const ParameterSet
* param
,
259 MatchContext
* context
) {
260 if (NULL
== context
) {
263 const wchar_t* source_str
= NULL
;
264 if (!param
->Get(&source_str
)) return EVAL_ERROR
;
266 int start_position
= 0;
268 unsigned int match_opts
= 0;
269 opcode
->GetArgument(1, &match_len
);
270 opcode
->GetArgument(2, &start_position
);
271 opcode
->GetArgument(3, &match_opts
);
273 const wchar_t* match_str
= opcode
->GetRelativeString(0);
274 // Advance the source string to the last successfully evaluated position
275 // according to the match context.
276 source_str
= &source_str
[context
->position
];
277 int source_len
= static_cast<int>(g_nt
.wcslen(source_str
));
279 if (0 == source_len
) {
280 // If we reached the end of the source string there is nothing we can
284 if (match_len
> source_len
) {
285 // There can't be a positive match when the target string is bigger than
290 BOOL case_sensitive
= (match_opts
& CASE_INSENSITIVE
) ? TRUE
: FALSE
;
292 // We have three cases, depending on the value of start_pos:
293 // Case 1. We skip N characters and compare once.
294 // Case 2: We skip to the end and compare once.
295 // Case 3: We match the first substring (if we find any).
296 if (start_position
>= 0) {
297 if (kSeekToEnd
== start_position
) {
298 start_position
= source_len
- match_len
;
299 } else if (match_opts
& EXACT_LENGHT
) {
300 // A sub-case of case 3 is when the EXACT_LENGHT flag is on
301 // the match needs to be not just substring but full match.
302 if ((match_len
+ start_position
) != source_len
) {
307 // Advance start_pos characters. Warning! this does not consider
308 // utf16 encodings (surrogate pairs) or other Unicode 'features'.
309 source_str
+= start_position
;
311 // Since we skipped, lets reevaluate just the lengths again.
312 if ((match_len
+ start_position
) > source_len
) {
316 UNICODE_STRING match_ustr
;
317 InitStringUnicode(match_str
, match_len
, &match_ustr
);
318 UNICODE_STRING source_ustr
;
319 InitStringUnicode(source_str
, match_len
, &source_ustr
);
321 if (0 == g_nt
.RtlCompareUnicodeString(&match_ustr
, &source_ustr
,
323 // Match! update the match context.
324 context
->position
+= start_position
+ match_len
;
329 } else if (start_position
< 0) {
330 UNICODE_STRING match_ustr
;
331 InitStringUnicode(match_str
, match_len
, &match_ustr
);
332 UNICODE_STRING source_ustr
;
333 InitStringUnicode(source_str
, match_len
, &source_ustr
);
336 if (0 == g_nt
.RtlCompareUnicodeString(&match_ustr
, &source_ustr
,
338 // Match! update the match context.
339 context
->position
+= (source_ustr
.Buffer
- source_str
) + match_len
;
342 ++source_ustr
.Buffer
;
344 } while (source_len
>= match_len
);
349 //////////////////////////////////////////////////////////////////////////////
350 // OpcodeMaker (other member functions).
352 PolicyOpcode
* OpcodeFactory::MakeBase(OpcodeID opcode_id
,
354 int16 selected_param
) {
355 if (memory_size() < sizeof(PolicyOpcode
)) {
359 // Create opcode using placement-new on the buffer memory.
360 PolicyOpcode
* opcode
= new(memory_top_
) PolicyOpcode();
362 // Fill in the standard fields, that every opcode has.
363 memory_top_
+= sizeof(PolicyOpcode
);
364 opcode
->opcode_id_
= opcode_id
;
365 opcode
->options_
= static_cast<int16
>(options
);
366 opcode
->parameter_
= selected_param
;
370 ptrdiff_t OpcodeFactory::AllocRelative(void* start
, const wchar_t* str
,
372 size_t bytes
= lenght
* sizeof(wchar_t);
373 if (memory_size() < bytes
) {
376 memory_bottom_
-= bytes
;
377 if (reinterpret_cast<UINT_PTR
>(memory_bottom_
) & 1) {
378 // TODO(cpu) replace this for something better.
381 memcpy(memory_bottom_
, str
, bytes
);
382 ptrdiff_t delta
= memory_bottom_
- reinterpret_cast<char*>(start
);
386 //////////////////////////////////////////////////////////////////////////////
387 // Opcode evaluation dispatchers.
389 // This function is the one and only entry for evaluating any opcode. It is
390 // in charge of applying any relevant opcode options and calling EvaluateInner
391 // were the actual dispatch-by-id is made. It would seem at first glance that
392 // the dispatch should be done by virtual function (vtable) calls but you have
393 // to remember that the opcodes are made in the broker process and copied as
394 // raw memory to the target process.
396 EvalResult
PolicyOpcode::Evaluate(const ParameterSet
* call_params
,
397 size_t param_count
, MatchContext
* match
) {
398 if (NULL
== call_params
) {
401 const ParameterSet
* selected_param
= NULL
;
402 if (parameter_
>= 0) {
403 if (static_cast<size_t>(parameter_
) >= param_count
) {
406 selected_param
= &call_params
[parameter_
];
408 EvalResult result
= EvaluateHelper(selected_param
, match
);
410 // Apply the general options regardless of the particular type of opcode.
411 if (kPolNone
== options_
) {
415 if (options_
& kPolNegateEval
) {
416 if (EVAL_TRUE
== result
) {
418 } else if (EVAL_FALSE
== result
) {
420 } else if (EVAL_ERROR
!= result
) {
425 if (options_
& kPolClearContext
) {
428 if (options_
& kPolUseOREval
) {
429 match
->options
= kPolUseOREval
;
435 #define OPCODE_EVAL(op, x, y, z) case op: return OpcodeEval<op>(x, y, z)
437 EvalResult
PolicyOpcode::EvaluateHelper(const ParameterSet
* parameters
,
438 MatchContext
* match
) {
439 switch (opcode_id_
) {
440 OPCODE_EVAL(OP_ALWAYS_FALSE
, this, parameters
, match
);
441 OPCODE_EVAL(OP_ALWAYS_TRUE
, this, parameters
, match
);
442 OPCODE_EVAL(OP_NUMBER_MATCH
, this, parameters
, match
);
443 OPCODE_EVAL(OP_ULONG_MATCH_RANGE
, this, parameters
, match
);
444 OPCODE_EVAL(OP_WSTRING_MATCH
, this, parameters
, match
);
445 OPCODE_EVAL(OP_ULONG_AND_MATCH
, this, parameters
, match
);
446 OPCODE_EVAL(OP_ACTION
, this, parameters
, match
);
454 } // namespace sandbox