Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(129)

Side by Side Diff: src/trusted/validator/x86/ncval_reg_sfi/nc_protect_base.c

Issue 625923004: Delete old x86 validator. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: rebase master Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7 /* nc_protect_base.h - For 64-bit mode, verifies that no instruction
8 * changes the value of the base register, that the invariant between
9 * RSP and RBP is maintained, and that segment registers are not set.
10 */
11 #include <assert.h>
12 #include <string.h>
13
14 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_protect_base. h"
15
16 #include "native_client/src/include/portability_io.h"
17 #include "native_client/src/shared/platform/nacl_log.h"
18 #include "native_client/src/trusted/validator/x86/decoder/ncop_exps.h"
19 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal .h"
20 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_trans.h"
21 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter. h"
22 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter_ internal.h"
23 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_utils .h"
24 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_jumps.h"
25
26 /* To turn on debugging of instruction decoding, change value of
27 * DEBUGGING to 1.
28 */
29 #define DEBUGGING 0
30
31 #include "native_client/src/shared/utils/debugging.h"
32
33 #include "native_client/src/trusted/validator/x86/decoder/ncopcode_desc_inl.c"
34 #include "native_client/src/trusted/validator/x86/decoder/ncop_exps_inl.c"
35 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_iter_inl.c"
36
37 static void NaClReportIllegalChangeToRsp(NaClValidatorState* state,
38 NaClInstState* inst) {
39 NaClValidatorInstMessage(LOG_ERROR, state, inst,
40 "Illegal assignment to RSP\n");
41 }
42
43 /* Checks flags in the possible set base registers, and reports any
44 * previous instructions that were marked as bad.
45 *
46 * Parameters:
47 * state - The state of the validator.
48 */
49 static INLINE void NaClMaybeReportPreviousBad(NaClValidatorState* state) {
50 NaClInstState* prev_esp_set_inst =
51 state->set_base_registers.buffer[
52 state->set_base_registers.previous_index].esp_set_inst;
53 NaClInstState* prev_ebp_set_inst =
54 state->set_base_registers.buffer[
55 state->set_base_registers.previous_index].ebp_set_inst;
56
57 /* First check if previous register references are not followed
58 * by acceptable instructions.
59 */
60 if (NULL != prev_esp_set_inst) {
61 NaClValidatorInstMessage(LOG_ERROR,
62 state,
63 prev_esp_set_inst,
64 "Illegal assignment to ESP\n");
65 state->set_base_registers.buffer[
66 state->set_base_registers.previous_index].esp_set_inst = NULL;
67 }
68 if (NULL != prev_ebp_set_inst) {
69 NaClValidatorInstMessage(LOG_ERROR,
70 state,
71 prev_ebp_set_inst,
72 "Illegal assignment to EBP\n");
73 state->set_base_registers.buffer[
74 state->set_base_registers.previous_index].ebp_set_inst = NULL;
75 }
76
77 /* Now advance the register recording by one instruction. */
78 state->set_base_registers.previous_index =
79 state->set_base_registers.current_index;
80 state->set_base_registers.current_index =
81 ((state->set_base_registers.current_index + 1)
82 % NACL_REGISTER_LOCALS_BUFFER_SIZE);
83 }
84
85 void NaClBaseRegisterMemoryInitialize(NaClValidatorState* state) {
86 int i;
87 for (i = 0; i < NACL_REGISTER_LOCALS_BUFFER_SIZE; ++i) {
88 state->set_base_registers.buffer[i].esp_set_inst = NULL;
89 state->set_base_registers.buffer[i].ebp_set_inst = NULL;
90 }
91 state->set_base_registers.previous_index = 0;
92 state->set_base_registers.current_index = 1;
93 }
94
95 /* Returns true iff the instruction of form "lea _, [%reg+%rbase*1]" */
96 static Bool NaClIsLeaAddressRegPlusRbase(NaClValidatorState* state,
97 NaClInstState* inst_state,
98 NaClOpKind reg) {
99 const NaClInst* inst = NaClInstStateInst(inst_state);
100 Bool result = FALSE;
101 DEBUG(NaClLog(LOG_INFO, "-> LeaAddressRegPlusRbase(%s)\n",
102 NaClOpKindName(reg)));
103 if (InstLea == inst->name &&
104 2 == NaClGetInstNumberOperandsInline(inst)) {
105 NaClExpVector* vector = NaClInstStateExpVector(inst_state);
106 int op2_index =
107 NaClGetExpKidIndex(vector,
108 NaClGetNthExpKind(vector, OperandReference, 2),
109 0);
110 NaClExp* op2 = &(vector->node[op2_index]);
111 /* Only allow memory offset nodes with address size 64. */
112 if (ExprMemOffset == op2->kind &&
113 NACL_EMPTY_EFLAGS != (op2->flags & NACL_EFLAG(ExprSize64))) {
114 int base_reg_index = op2_index + 1;
115 NaClOpKind base_reg = NaClGetExpVectorRegister(vector, base_reg_index);
116 DEBUG(NaClLog(LOG_INFO, " base_reg = %s\n", NaClOpKindName(base_reg)));
117 if (base_reg == reg) {
118 int index_reg_index =
119 base_reg_index + NaClExpWidth(vector, base_reg_index);
120 NaClOpKind index_reg =
121 NaClGetExpVectorRegister(vector, index_reg_index);
122 DEBUG(NaClLog(LOG_INFO,
123 " index_reg = %s\n", NaClOpKindName(index_reg)));
124 if (index_reg == state->base_register) {
125 int scale_index =
126 index_reg_index + NaClExpWidth(vector, index_reg_index);
127 DEBUG(NaClLog(LOG_INFO, " scale_index = %d\n", scale_index));
128 if (ExprConstant == vector->node[scale_index].kind) {
129 if ((uint64_t)1 ==
130 NaClGetExprUnsignedValue(&vector->node[scale_index])) {
131 int disp_index = scale_index + NaClExpWidth(vector, scale_index);
132 DEBUG(NaClLog(LOG_INFO, " disp_index = %d\n", disp_index));
133 if (ExprConstant == vector->node[disp_index].kind) {
134 if ((uint64_t)0 ==
135 NaClGetExprSignedValue(&vector->node[disp_index])) {
136 result = TRUE;
137 } else {
138 DEBUG(NaClLog(LOG_INFO, " disp not zero!\n"));
139 }
140 }
141 } else {
142 DEBUG(NaClLog(LOG_INFO, " scale not 1!\n"));
143 }
144 }
145 }
146 }
147 }
148 }
149 /* If reached, did not match. */
150 DEBUG(NaClLog(LOG_INFO, "<-LeaAddressRegPlusRbase = %d\n", result));
151 return result;
152 }
153
154 Bool NaClAcceptLeaWithMoveLea32To64(struct NaClValidatorState* state,
155 NaClOpKind reg) {
156 NaClInstState* inst_state = state->cur_inst_state;
157 Bool result = NaClOperandOneIsRegisterSet(inst_state, reg) &&
158 NaClIsLeaAddressRegPlusRbase(state, inst_state, reg) &&
159 NaClAssignsRegisterWithZeroExtends64(state, 1, reg);
160 if (result) {
161 DEBUG({
162 const char* reg_name = NaClOpKindName(reg);
163 printf("nc protect base for 'lea %s. [%s, rbase]'\n",
164 reg_name, reg_name);
165 });
166 result = TRUE;
167 }
168 return result;
169 }
170
171 /* Check if assignments to stack register RSP is legal.
172 *
173 * Parameters are:
174 * state - The state of the validator.
175 * i - The index of the node (in the expression tree) that
176 * assigns the RSP register.
177 */
178 static void NaClCheckRspAssignments(struct NaClValidatorState* state,
179 uint32_t i) {
180 /*
181 * Only allow one of:
182 * (1) mov %rsp, %rbp
183 *
184 * Note: maintains RSP/RBP invariant, since RBP was already
185 * meeting the invariant.
186 * (2) %esp = zero extend 32-bit value
187 * OP %rsp, %rbase
188 *
189 * where OP in { or , add }.
190 * (3) An instruction that updates the stack a (small) bounded amount,
191 * and then does a memory access. This includes Push, Pop, Call,
192 *
193 * Note that entering a function corresponds to the pattern:
194 * push %rpb
195 * mov %rbp, %rsp
196 * (4) Allow stack updates of the form:
197 * OP %esp, C
198 * add %rsp, %rbase
199 * where OP is a operator in { add , sub },
200 * and C is a 32-bit constant.
201 * Note: Since add/sub are zero-extending operations for operand
202 * size 32, this doesn't have to be treated as a special case!
203 * (5) Allow "and $rsp, 0xXX" where 0xXX is an immediate 8 bit
204 * value that is negative. Used to realign the stack pointer.
205 * (6) %esp = zero extend 32-bit value.
206 * lea %rsp, [%rsp+%rbase*1]
207 *
208 * Same as (6), except that we use instructions prior to the
209 * pattern to do the add/subtract. Then let the result be
210 * (zero-extended) moved into ESP, and use the lea to fill
211 * in the top 32 bits of %rsp.
212 *
213 * Note: We require the scale to be 1, and rbase be in
214 * the index position.
215 *
216 * Note: Cases 2, 4, 5, and 6 are maintaining the invariant that
217 * the top half of RSP is the same as RBASE, and the lower half
218 * of RBASE is zero. Case (2) does this by seting the bottom 32
219 * bits with the first instruction (zeroing out the top 32 bits),
220 * and then copies (via or or add) the top 32 bits of RBASE into RSP
221 * (since the bottom 32 bits of RBASE are zero).
222 * Case (4) maintains this by first clearing the top half
223 * of RSP, and then setting the top half to match RBASE. Case (5)
224 * maintains the variant because the constant is small
225 * (-1 to -128) to that the invariant for $RSP (top half
226 * is unchanged). Case 6 uses the addition in the address calculation
227 * of lea to fill in the top 32 bits.
228 */
229 NaClInstState* inst_state = state->cur_inst_state;
230 const NaClInst* inst = state->cur_inst;
231 NaClMnemonic inst_name = inst->name;
232 NaClExpVector* vector = state->cur_inst_vector;
233 #ifdef NCVAL_TESTING
234 char* buffer;
235 size_t buffer_size;
236 #endif
237
238 switch (inst_name) {
239 case InstPush:
240 case InstPop:
241 /* Legal if index corresponds to the first (stack) argument.
242 * Note: Since the vector contains a list of operand exrpessions,
243 * the first operand reference is always at index zero, and its
244 * first child (where the stack register is defined) is at index 1.
245 */
246 if (i == 1) return;
247 break;
248 case InstCall:
249 /* Legal if index corresponds to the second (stack) argument.
250 * Note: The first operand is an operand reference to the instruction
251 * register. It consists of an operand reference at index zero,
252 * and its first child (where the instruction registers is defined)
253 * is at index 1. The node at index 2 is the operand reference to
254 * the stack register, and its first child (where the stack register is
255 * defined) is at index 3;
256 */
257 if (i == 3) return;
258 break;
259 case InstOr:
260 case InstAdd:
261 /* case 2/4 (depending on instruction name) */
262 if (NaClIsBinarySetUsingRegisters(
263 state->decoder_tables,
264 inst, inst_name, vector, RegRSP,
265 state->base_register) &&
266 NaClAssignsRegisterWithZeroExtends32(state, 1, RegESP)) {
267 #ifdef NCVAL_TESTING
268 /* Report precondition of test. */
269 NaClConditionAppend(state->precond, &buffer, &buffer_size);
270 SNPRINTF(buffer, buffer_size, "ZeroExtends(esp)");
271 #endif
272 NaClMarkInstructionJumpIllegal(state, state->cur_inst_state);
273 state->set_base_registers.buffer[
274 state->set_base_registers.previous_index].esp_set_inst = NULL;
275 return;
276 }
277 break;
278 case InstLea:
279 if (NaClAcceptLeaWithMoveLea32To64(state, RegRSP)) {
280 /* case 6. Found that the assignment to ESP in the previous
281 * instruction is legal, so long as the two instructions
282 * are atomic.
283 */
284 #ifdef NCVAL_TESTING
285 /* Report precondition of test. */
286 NaClConditionAppend(state->precond, &buffer, &buffer_size);
287 SNPRINTF(buffer, buffer_size, "ZeroExtends(esp)");
288 #endif
289 NaClMarkInstructionJumpIllegal(state, state->cur_inst_state);
290 state->set_base_registers.buffer[
291 state->set_base_registers.previous_index].esp_set_inst = NULL;
292 return;
293 }
294 break;
295 case InstAnd:
296 /* See if case 5: and $rsp, 0xXX */
297 if (NaClInstStateLength(inst_state) == 4 &&
298 NaClInstStateByte(inst_state, 0) == 0x48 &&
299 NaClInstStateByte(inst_state, 1) == 0x83 &&
300 NaClInstStateByte(inst_state, 2) == 0xe4 &&
301 /* negative byte test: check if leftmost bit set. */
302 (NaClInstStateByte(inst_state, 3) & 0x80)) {
303 return;
304 }
305 /* Intentionally fall to the next case. */
306 default:
307 if (NaClIsMovUsingRegisters(state->decoder_tables,
308 inst, vector, RegRSP, RegRBP)) {
309 /* case (1) -- see above, matching
310 * mov %rsp, %rbp
311 */
312 return;
313 }
314 break;
315 }
316 /* If reached, assume that not a special case. */
317 NaClReportIllegalChangeToRsp(state, inst_state);
318 }
319
320 /* Check if assignments to rbp resister is legal.
321 *
322 * Parameters are:
323 * state - The state of the validator.
324 * i - The index of the node (in the expression tree) that
325 * assigns the RSP register.
326 */
327 static void NaClCheckRbpAssignments(struct NaClValidatorState* state,
328 uint32_t i) {
329 /* (1) mov %rbp, %rsp
330 *
331 * Note: maintains RSP/RBP invariant, since RSP was already
332 * meeting the invariant.
333 *
334 * (2) %ebp = zero extend 32-bit value.
335 * add %rbp, %rbase
336 *
337 * Typical use in the exit from a function, restoring RBP.
338 * The ... in the MOV is gotten from a stack pop in such
339 * cases. However, for long jumps etc., the value may
340 * be gotten from memory, or even a register.
341 *
342 * (3) %ebp = zero extend 32-bit value.
343 * lea %rbp, [%rbp+%rbase*1]
344 *
345 * Same as (2), except that we use instructions prior to the
346 * pattern to do the add/subtract. Then let the result be
347 * (zero-extended) moved into EBP, and use the lea to fill
348 * in the top 32 bits of %RSP.
349 *
350 * Note: We require the scale to be 1, and rbase be in
351 * the index position.
352 */
353 NaClInstState* inst_state = state->cur_inst_state;
354 const NaClInst* inst = state->cur_inst;
355 NaClMnemonic inst_name = inst->name;
356 NaClExpVector* vector = state->cur_inst_vector;
357 #ifdef NCVAL_TESTING
358 char* buffer;
359 size_t buffer_size;
360 #endif
361
362 switch (inst_name) {
363 case InstAdd:
364 /* case 2. */
365 if (NaClIsBinarySetUsingRegisters(
366 state->decoder_tables,
367 inst, InstAdd, vector,
368 RegRBP, state->base_register) &&
369 NaClAssignsRegisterWithZeroExtends32(state, 1, RegEBP)) {
370 #ifdef NCVAL_TESTING
371 /* Report precondition of test. */
372 NaClConditionAppend(state->precond, &buffer, &buffer_size);
373 SNPRINTF(buffer, buffer_size, "ZeroExtends(ebp)");
374 #endif
375 NaClMarkInstructionJumpIllegal(state, state->cur_inst_state);
376 state->set_base_registers.buffer[
377 state->set_base_registers.previous_index].ebp_set_inst = NULL;
378 return;
379 }
380 break;
381 case InstLea:
382 /* case 3 */
383 if (NaClAcceptLeaWithMoveLea32To64(state, RegRBP)) {
384 #ifdef NCVAL_TESTING
385 /* Report precondition of test. */
386 NaClConditionAppend(state->precond, &buffer, &buffer_size);
387 SNPRINTF(buffer, buffer_size, "ZeroExtends(ebp)");
388 #endif
389 NaClMarkInstructionJumpIllegal(state, state->cur_inst_state);
390 state->set_base_registers.buffer[
391 state->set_base_registers.previous_index].ebp_set_inst = NULL;
392 return;
393 }
394 break;
395 default:
396 if (NaClIsMovUsingRegisters(inst_state->decoder_tables,
397 inst, vector, RegRBP, RegRSP)) {
398 /* case 1 */
399 return;
400 }
401 break;
402 }
403 /* If reached, not valid. */
404 NaClValidatorInstMessage(LOG_ERROR, state, inst_state,
405 "Illegal change to register RBP\n");
406 }
407
408 /* Reports error if the register name is a subregister of Rsp/Rbp/base register,
409 * under assumption that it is illegal to change the value of such registers.
410 */
411 static void NaClCheckSubregChangeOfRspRbpOrBase(
412 struct NaClValidatorState* state,
413 NaClOpKind reg_name) {
414 NaClInstState* inst_state = state->cur_inst_state;
415 if (NaClIs64Subreg(inst_state, reg_name, state->base_register)) {
416 NaClValidatorInstMessage(
417 LOG_ERROR, state, inst_state,
418 "Changing %s changes the value of %s\n",
419 NaClOpKindName(reg_name),
420 NaClOpKindName(state->base_register));
421 } else if (NaClIs64Subreg(inst_state, reg_name, RegRSP)) {
422 NaClValidatorInstMessage(
423 LOG_ERROR, state, inst_state,
424 "Changing %s changes the value of %s\n",
425 NaClOpKindName(reg_name),
426 NaClOpKindName(RegRSP));
427 } else if (NaClIs64Subreg(inst_state, reg_name, RegRBP)) {
428 NaClValidatorInstMessage(
429 LOG_ERROR, state, inst_state,
430 "Changing %s changes the value of %s\n",
431 NaClOpKindName(reg_name),
432 NaClOpKindName(RegRBP));
433 }
434 }
435
436 void NaClBaseRegisterValidator(struct NaClValidatorState* state) {
437 uint32_t i;
438 NaClInstState* inst_state = state->cur_inst_state;
439 NaClExpVector* vector = state->cur_inst_vector;
440
441 DEBUG(NaClValidatorInstMessage(
442 LOG_INFO, state, inst_state, "Checking base registers...\n"));
443
444 /* Look for assignments to registers. */
445 for (i = 0; i < vector->number_expr_nodes; ++i) {
446 NaClExp* node = &vector->node[i];
447 if (ExprRegister == node->kind) {
448 if (node->flags & NACL_EFLAG(ExprSet)) {
449 NaClOpKind reg_name = NaClGetExpRegisterInline(node);
450
451 /* If reached, found an assignment to a register.
452 * Check if its one that we care about (i.e.
453 * the base register (RBASE), RSP, RBP, or segment register).
454 */
455 if (reg_name == state->base_register) {
456 NaClValidatorInstMessage(
457 LOG_ERROR, state, inst_state,
458 "Illegal to change the value of register %s\n",
459 NaClOpKindName(state->base_register));
460 } else {
461 switch (reg_name) {
462 case RegRSP:
463 NaClCheckRspAssignments(state, i);
464 break;
465 case RegRBP:
466 NaClCheckRbpAssignments(state, i);
467 break;
468 case RegESP:
469 /* Record that we must recheck this after we have
470 * moved to the next instruction.
471 */
472 state->set_base_registers.buffer[
473 state->set_base_registers.current_index
474 ].esp_set_inst = inst_state;
475 break;
476 case RegEBP:
477 /* Record that we must recheck this after we have
478 * moved to the next instruction.
479 */
480 state->set_base_registers.buffer[
481 state->set_base_registers.current_index
482 ].ebp_set_inst = inst_state;
483 break;
484 case RegCS:
485 case RegDS:
486 case RegSS:
487 case RegES:
488 case RegFS:
489 case RegGS:
490 NaClValidatorInstMessage(
491 LOG_ERROR, state, inst_state,
492 "Illegal assignment to segment register %s\n",
493 NaClOpKindName(reg_name));
494 break;
495 default:
496 NaClCheckSubregChangeOfRspRbpOrBase(state, reg_name);
497 break;
498 }
499 }
500 }
501 }
502 }
503 /* Before moving to the next instruction, see if we need to report
504 * problems with the previous instruction.
505 */
506 NaClMaybeReportPreviousBad(state);
507 }
508
509 void NaClBaseRegisterSummarize(struct NaClValidatorState* state) {
510 /* Check if problems in last instruction of segment. */
511 NaClMaybeReportPreviousBad(state);
512 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698