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_low_level.h"
10 #include "base/basictypes.h"
14 // A single rule can use at most this amount of memory.
15 const size_t kRuleBufferSize
= 1024*4;
17 // The possible states of the string matching opcode generator.
20 PENDING_ASTERISK
, // Have seen an '*' but have not generated an opcode.
21 PENDING_QMARK
, // Have seen an '?' but have not generated an opcode.
24 // The category of the last character seen by the string matching opcode
26 const uint32 kLastCharIsNone
= 0;
27 const uint32 kLastCharIsAlpha
= 1;
28 const uint32 kLastCharIsWild
= 2;
29 const uint32 kLastCharIsAsterisk
= kLastCharIsWild
+ 4;
30 const uint32 kLastCharIsQuestionM
= kLastCharIsWild
+ 8;
35 LowLevelPolicy::LowLevelPolicy(PolicyGlobal
* policy_store
)
36 : policy_store_(policy_store
) {
39 // Adding a rule is nothing more than pushing it into an stl container. Done()
40 // is called for the rule in case the code that made the rule in the first
41 // place has not done it.
42 bool LowLevelPolicy::AddRule(int service
, PolicyRule
* rule
) {
47 PolicyRule
* local_rule
= new PolicyRule(*rule
);
48 RuleNode node
= {local_rule
, service
};
49 rules_
.push_back(node
);
53 LowLevelPolicy::~LowLevelPolicy() {
54 // Delete all the rules.
55 typedef std::list
<RuleNode
> RuleNodes
;
56 for (RuleNodes::iterator it
= rules_
.begin(); it
!= rules_
.end(); ++it
) {
61 // Here is where the heavy byte shuffling is done. We take all the rules and
62 // 'compile' them into a single memory region. Now, the rules are in random
63 // order so the first step is to reorganize them into a stl map that is keyed
64 // by the service id and as a value contains a list with all the rules that
65 // belong to that service. Then we enter the big for-loop where we carve a
66 // memory zone for the opcodes and the data and call RebindCopy on each rule
67 // so they all end up nicely packed in the policy_store_.
68 bool LowLevelPolicy::Done() {
69 typedef std::list
<RuleNode
> RuleNodes
;
70 typedef std::list
<const PolicyRule
*> RuleList
;
71 typedef std::map
<uint32
, RuleList
> Mmap
;
74 for (RuleNodes::iterator it
= rules_
.begin(); it
!= rules_
.end(); ++it
) {
75 mmap
[it
->service
].push_back(it
->rule
);
78 PolicyBuffer
* current_buffer
= &policy_store_
->data
[0];
79 char* buffer_end
= reinterpret_cast<char*>(current_buffer
) +
80 policy_store_
->data_size
;
81 size_t avail_size
= policy_store_
->data_size
;
83 for (Mmap::iterator it
= mmap
.begin(); it
!= mmap
.end(); ++it
) {
84 uint32 service
= (*it
).first
;
85 if (service
>= kMaxServiceCount
) {
88 policy_store_
->entry
[service
] = current_buffer
;
90 RuleList::iterator rules_it
= (*it
).second
.begin();
91 RuleList::iterator rules_it_end
= (*it
).second
.end();
93 size_t svc_opcode_count
= 0;
95 for (; rules_it
!= rules_it_end
; ++rules_it
) {
96 const PolicyRule
* rule
= (*rules_it
);
97 size_t op_count
= rule
->GetOpcodeCount();
99 size_t opcodes_size
= op_count
* sizeof(PolicyOpcode
);
100 if (avail_size
< opcodes_size
) {
103 size_t data_size
= avail_size
- opcodes_size
;
104 PolicyOpcode
* opcodes_start
= ¤t_buffer
->opcodes
[svc_opcode_count
];
105 if (!rule
->RebindCopy(opcodes_start
, opcodes_size
,
106 buffer_end
, &data_size
)) {
109 size_t used
= avail_size
- data_size
;
112 svc_opcode_count
+= op_count
;
115 current_buffer
->opcode_count
+= svc_opcode_count
;
116 size_t policy_byte_count
= (svc_opcode_count
* sizeof(PolicyOpcode
))
117 / sizeof(current_buffer
[0]);
118 current_buffer
= ¤t_buffer
[policy_byte_count
+ 1];
124 PolicyRule::PolicyRule(EvalResult action
)
125 : action_(action
), done_(false) {
126 char* memory
= new char[sizeof(PolicyBuffer
) + kRuleBufferSize
];
127 buffer_
= reinterpret_cast<PolicyBuffer
*>(memory
);
128 buffer_
->opcode_count
= 0;
129 opcode_factory_
= new OpcodeFactory(buffer_
,
130 kRuleBufferSize
+ sizeof(PolicyOpcode
));
133 PolicyRule::PolicyRule(const PolicyRule
& other
) {
136 action_
= other
.action_
;
138 size_t buffer_size
= sizeof(PolicyBuffer
) + kRuleBufferSize
;
139 char* memory
= new char[buffer_size
];
140 buffer_
= reinterpret_cast<PolicyBuffer
*>(memory
);
141 memcpy(buffer_
, other
.buffer_
, buffer_size
);
143 char* opcode_buffer
= reinterpret_cast<char*>(&buffer_
->opcodes
[0]);
144 char* next_opcode
= &opcode_buffer
[GetOpcodeCount() * sizeof(PolicyOpcode
)];
146 new OpcodeFactory(next_opcode
, other
.opcode_factory_
->memory_size());
149 // This function get called from a simple state machine implemented in
150 // AddStringMatch() which passes the current state (in state) and it passes
151 // true in last_call if AddStringMatch() has finished processing the input
152 // pattern string and this would be the last call to generate any pending
153 // opcode. The skip_count is the currently accumulated number of '?' seen so
154 // far and once the associated opcode is generated this function sets it back
156 bool PolicyRule::GenStringOpcode(RuleType rule_type
,
157 StringMatchOptions match_opts
,
158 uint16 parameter
, int state
, bool last_call
,
159 int* skip_count
, base::string16
* fragment
) {
161 // The last opcode must:
162 // 1) Always clear the context.
163 // 2) Preserve the negation.
164 // 3) Remove the 'OR' mode flag.
165 uint32 options
= kPolNone
;
167 if (IF_NOT
== rule_type
) {
168 options
= kPolClearContext
| kPolNegateEval
;
170 options
= kPolClearContext
;
172 } else if (IF_NOT
== rule_type
) {
173 options
= kPolUseOREval
| kPolNegateEval
;
176 PolicyOpcode
* op
= NULL
;
178 // The fragment string contains the accumulated characters to match with, it
179 // never contains wildcards (unless they have been escaped) and while there
180 // is no fragment there is no new string match opcode to generate.
181 if (fragment
->empty()) {
182 // There is no new opcode to generate but in the last call we have to fix
183 // the previous opcode because it was really the last but we did not know
185 if (last_call
&& (buffer_
->opcode_count
> 0)) {
186 op
= &buffer_
->opcodes
[buffer_
->opcode_count
- 1];
187 op
->SetOptions(options
);
192 if (PENDING_ASTERISK
== state
) {
194 op
= opcode_factory_
->MakeOpWStringMatch(parameter
, fragment
->c_str(),
195 kSeekToEnd
, match_opts
,
198 op
= opcode_factory_
->MakeOpWStringMatch(parameter
, fragment
->c_str(),
199 kSeekForward
, match_opts
,
203 } else if (PENDING_QMARK
== state
) {
204 op
= opcode_factory_
->MakeOpWStringMatch(parameter
, fragment
->c_str(),
205 *skip_count
, match_opts
, options
);
209 match_opts
= static_cast<StringMatchOptions
>(EXACT_LENGHT
| match_opts
);
211 op
= opcode_factory_
->MakeOpWStringMatch(parameter
, fragment
->c_str(), 0,
212 match_opts
, options
);
217 ++buffer_
->opcode_count
;
222 bool PolicyRule::AddStringMatch(RuleType rule_type
, int16 parameter
,
223 const wchar_t* string
,
224 StringMatchOptions match_opts
) {
226 // Do not allow to add more rules after generating the action opcode.
230 const wchar_t* current_char
= string
;
231 uint32 last_char
= kLastCharIsNone
;
232 int state
= PENDING_NONE
;
233 int skip_count
= 0; // counts how many '?' we have seen in a row.
234 base::string16 fragment
; // accumulates the non-wildcard part.
236 while (L
'\0' != *current_char
) {
237 switch (*current_char
) {
239 if (kLastCharIsWild
& last_char
) {
240 // '**' and '&*' is an error.
243 if (!GenStringOpcode(rule_type
, match_opts
, parameter
,
244 state
, false, &skip_count
, &fragment
)) {
247 last_char
= kLastCharIsAsterisk
;
248 state
= PENDING_ASTERISK
;
251 if (kLastCharIsAsterisk
== last_char
) {
255 if (!GenStringOpcode(rule_type
, match_opts
, parameter
,
256 state
, false, &skip_count
, &fragment
)) {
260 last_char
= kLastCharIsQuestionM
;
261 state
= PENDING_QMARK
;
264 // Note: "/?" is an escaped '?'. Eat the slash and fall through.
265 if (L
'?' == current_char
[1]) {
269 fragment
+= *current_char
;
270 last_char
= kLastCharIsAlpha
;
275 if (!GenStringOpcode(rule_type
, match_opts
, parameter
,
276 state
, true, &skip_count
, &fragment
)) {
282 bool PolicyRule::AddNumberMatch(RuleType rule_type
,
285 RuleOp comparison_op
) {
287 // Do not allow to add more rules after generating the action opcode.
290 uint32 opts
= (rule_type
== IF_NOT
)? kPolNegateEval
: kPolNone
;
292 if (EQUAL
== comparison_op
) {
293 if (NULL
== opcode_factory_
->MakeOpNumberMatch(parameter
, number
, opts
)) {
296 } else if (AND
== comparison_op
) {
297 if (NULL
== opcode_factory_
->MakeOpNumberAndMatch(parameter
, number
,
302 ++buffer_
->opcode_count
;
306 bool PolicyRule::Done() {
310 if (NULL
== opcode_factory_
->MakeOpAction(action_
, kPolNone
)) {
313 ++buffer_
->opcode_count
;
318 bool PolicyRule::RebindCopy(PolicyOpcode
* opcode_start
, size_t opcode_size
,
319 char* data_start
, size_t* data_size
) const {
320 size_t count
= buffer_
->opcode_count
;
321 for (size_t ix
= 0; ix
!= count
; ++ix
) {
322 if (opcode_size
< sizeof(PolicyOpcode
)) {
325 PolicyOpcode
& opcode
= buffer_
->opcodes
[ix
];
326 *opcode_start
= opcode
;
327 if (OP_WSTRING_MATCH
== opcode
.GetID()) {
328 // For this opcode argument 0 is a delta to the string and argument 1
329 // is the length (in chars) of the string.
330 const wchar_t* str
= opcode
.GetRelativeString(0);
332 opcode
.GetArgument(1, &str_len
);
333 str_len
= str_len
* sizeof(wchar_t);
334 if ((*data_size
) < str_len
) {
337 *data_size
-= str_len
;
338 data_start
-= str_len
;
339 memcpy(data_start
, str
, str_len
);
340 // Recompute the string displacement
341 ptrdiff_t delta
= data_start
- reinterpret_cast<char*>(opcode_start
);
342 opcode_start
->SetArgument(0, delta
);
345 opcode_size
-= sizeof(PolicyOpcode
);
351 PolicyRule::~PolicyRule() {
352 delete [] reinterpret_cast<char*>(buffer_
);
353 delete opcode_factory_
;
356 } // namespace sandbox