Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / validator / x86 / ncval_reg_sfi / ncvalidate_iter.c
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 /*
8  * ncvalidate_iter.c
9  * Validate x86 instructions for Native Client
10  *
11  */
12
13 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.h"
14
15 #include <assert.h>
16 #include <string.h>
17
18 #include "native_client/src/include/portability_io.h"
19 #include "native_client/src/shared/platform/nacl_check.h"
20 #include "native_client/src/shared/platform/nacl_log.h"
21 #include "native_client/src/trusted/validator/x86/decoder/ncop_exps.h"
22 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal.h"
23 #include "native_client/src/trusted/validator/x86/halt_trim.h"
24 #include "native_client/src/trusted/validator/x86/nc_segment.h"
25 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter_internal.h"
26 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncval_decode_tables.h"
27 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_illegal.h"
28 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_jumps.h"
29 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_jumps_detailed.h"
30 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_memory_protect.h"
31 #ifdef NCVAL_TESTING
32 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_postconds.h"
33 #endif
34 #include "native_client/src/trusted/validator_x86/ncdis_decode_tables.h"
35
36 /* To turn on debugging of instruction decoding, change value of
37  * DEBUGGING to 1.
38  */
39 #define DEBUGGING 0
40
41 #include "native_client/src/shared/utils/debugging.h"
42
43 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_iter_inl.c"
44
45 /* When >= 0, only print that many errors before quiting. When
46  * < 0, print all errors.
47  */
48 int NACL_FLAGS_max_reported_errors =
49 #ifdef NCVAL_TESTING
50     /* Turn off error reporting when generating pre/post conditions.
51      * Note: conditional code for NCVAL_TESTING will reset the
52      * quit flag after each instruction. Hence, by using 0, we
53      * effectively turn off printing of errors as the default. However,
54      * one can override this on the command line to force errors to
55      * be printed as well.
56      */
57     0
58 #else
59     100
60 #endif
61     ;
62
63 Bool NACL_FLAGS_validator_trace_instructions = FALSE;
64
65 Bool NACL_FLAGS_validator_trace_inst_internals = FALSE;
66
67 Bool NACL_FLAGS_ncval_annotate = TRUE;
68
69 Bool NACL_FLAGS_unsafe_single_inst_mode = FALSE;
70
71 #ifdef NCVAL_TESTING
72 Bool NACL_FLAGS_report_conditions_on_all = FALSE;
73
74 void NaClConditionAppend(char* condition,
75                          char** buffer,
76                          size_t* remaining_buffer_size) {
77   size_t bsize = strlen(condition);
78   *buffer = condition + bsize;
79   if (bsize > 0) {
80     /* Add that we are adding an alternative. */
81     SNPRINTF(*buffer, NCVAL_CONDITION_SIZE - bsize,
82              "&");
83     bsize = strlen(condition);
84     *buffer = condition + bsize;
85   }
86   *remaining_buffer_size = NCVAL_CONDITION_SIZE - bsize;
87 }
88 #endif
89
90 /* Define the stop instruction. */
91 const uint8_t kNaClFullStop = 0xf4;   /* x86 HALT opcode */
92
93 void NaClValidatorFlagsSetTraceVerbose(void) {
94   NACL_FLAGS_validator_trace_instructions = TRUE;
95   NACL_FLAGS_validator_trace_inst_internals = TRUE;
96 }
97
98 int NaClValidatorStateGetMaxReportedErrors(NaClValidatorState *vstate) {
99   return vstate->quit_after_error_count;
100 }
101
102 void NaClValidatorStateSetMaxReportedErrors(NaClValidatorState *vstate,
103                                             int new_value) {
104   vstate->quit_after_error_count = new_value;
105   vstate->quit = NaClValidatorQuit(vstate);
106 }
107
108 Bool NaClValidatorStateGetTraceInstructions(NaClValidatorState *vstate) {
109   return vstate->trace_instructions;
110 }
111
112 void NaClValidatorStateSetTraceInstructions(NaClValidatorState *vstate,
113                                             Bool new_value) {
114   vstate->trace_instructions = new_value;
115 }
116
117 Bool NaClValidatorStateGetTraceInstInternals(NaClValidatorState *vstate) {
118   return vstate->trace_inst_internals;
119 }
120
121 void NaClValidatorStateSetTraceInstInternals(NaClValidatorState *vstate,
122                                              Bool new_value) {
123   vstate->trace_inst_internals = new_value;
124 }
125
126 static INLINE Bool NaClValidatorStateTraceInline(NaClValidatorState *vstate) {
127   return vstate->trace_instructions || vstate->trace_inst_internals;
128 }
129
130
131 Bool NaClValidatorStateTrace(NaClValidatorState *vstate) {
132   return NaClValidatorStateTraceInline(vstate);
133 }
134
135 void NaClValidatorStateSetTraceVerbose(NaClValidatorState *vstate) {
136   vstate->trace_instructions = TRUE;
137   vstate->trace_inst_internals = TRUE;
138 }
139
140 int NaClValidatorStateGetLogVerbosity(NaClValidatorState *vstate) {
141   return vstate->log_verbosity;
142 }
143
144 void NaClValidatorStateSetLogVerbosity(NaClValidatorState *vstate,
145                                        Bool new_value) {
146   vstate->log_verbosity = new_value;
147 }
148
149 Bool NaClValidatorStateGetDoStubOut(NaClValidatorState *vstate) {
150   return vstate->do_stub_out;
151 }
152
153 void NaClValidatorStateSetDoStubOut(NaClValidatorState *vstate,
154                                     Bool new_value) {
155   vstate->do_stub_out = new_value;
156   /* We also turn off error diagnostics, under the assumption
157    * you don't want them. (Note: if the user wants them,
158    * you can run ncval to get them).
159    */
160   if (new_value) {
161     NaClValidatorStateSetMaxReportedErrors(vstate, 0);
162   }
163 }
164
165 static void NaClValidatorTrace(NaClValidatorState* vstate) {
166   struct Gio* g = NaClLogGetGio();
167   NaClInstState* inst_state = NaClInstIterGetStateInline(vstate->cur_iter);
168   (*vstate->error_reporter->printf)
169       (vstate->error_reporter, "-> visit: ");
170   if (NaClValidatorStateGetTraceInstructions(vstate)) {
171     (*vstate->error_reporter->print_inst)(vstate->error_reporter,
172                                          (void*) NaClInstStateInst(inst_state));
173   }
174   if (NaClValidatorStateGetTraceInstInternals(vstate)) {
175     NaClExpVectorPrint(g, inst_state);
176   }
177 }
178
179 /* TODO(karl) Move the print routines to a separate module. */
180
181 /* Returns true if an error message should be printed for the given level, in
182  * the current validator state.
183  * Parameters:
184  *   vstate - The validator state (may be NULL).
185  *   level - The log level of the validator message.
186  */
187 static INLINE Bool NaClPrintValidatorMessages(
188     NaClValidatorState *vstate, int level) {
189   if (NULL == vstate) {
190     /* Validator not defined yet, only used log verbosity to decide if message
191      * should be printed.
192      */
193     return level <= NaClLogGetVerbosity();
194   } else {
195     return (vstate->quit_after_error_count != 0) &&
196         (level <= vstate->log_verbosity) &&
197         (level <= NaClLogGetVerbosity());
198   }
199 }
200
201 static INLINE const char *NaClLogLevelLabel(int level) {
202   switch (level) {
203     case LOG_WARNING:
204       return "WARNING: ";
205     case LOG_ERROR:
206       return "ERROR: ";
207     case LOG_FATAL:
208       return "FATAL: ";
209     default:
210       return "";
211   }
212 }
213
214 /* Records that an error message has just been reported.
215  * Parameters:
216  *   vstate - The validator state (may be NULL).
217  *   level - The log level of the validator message.
218  */
219 static void NaClRecordErrorReported(NaClValidatorState *vstate, int level) {
220   if ((vstate != NULL) && ((level == LOG_ERROR) || (level == LOG_FATAL)) &&
221       (vstate->quit_after_error_count > 0) &&
222       !vstate->do_stub_out) {
223     --(vstate->quit_after_error_count);
224     vstate->quit = NaClValidatorQuit(vstate);
225     if (vstate->quit_after_error_count == 0) {
226       (*vstate->error_reporter->printf)(
227           vstate->error_reporter,
228           "%sError limit reached. Validator quitting!\n",
229           NaClLogLevelLabel(LOG_INFO));
230     }
231   }
232 }
233
234 /* Records the number of error validator messages generated for the state.
235  * Parameters:
236  *   vstate - The validator state (may be NULL).
237  *   level - The log level of the validator message.
238  * Returns - Updated error level, based on state.
239  */
240 static INLINE int NaClRecordIfValidatorError(NaClValidatorState *vstate,
241                                              int level) {
242   /* Note: don't quit if stubbing out, so all problems are fixed. */
243   if (((level == LOG_ERROR) || (level == LOG_FATAL)) &&
244       (NULL != vstate) && !vstate->do_stub_out) {
245     vstate->validates_ok = FALSE;
246     vstate->quit = NaClValidatorQuit(vstate);
247   }
248   return level;
249 }
250
251 /* The low-level implementation for stubbing out an instruction. Always use
252  * this function to (ultimately) stub out instructions. This makes it possible
253  * to detect when the validator modifies the code.
254  */
255 void NCStubOutMem(NaClValidatorState *state, void *ptr, size_t num) {
256   state->did_stub_out = TRUE;
257   memset(ptr, kNaClFullStop, num);
258 }
259
260 /* Does stub out of instruction in validator state. */
261 static void NaClStubOutInst(NaClValidatorState *state, NaClInstState* inst) {
262   NCRemainingMemory *memory = inst->bytes.memory;
263   NCStubOutMem(state, memory->mpc, memory->read_length);
264 }
265
266 /* Does a printf using the error reporter of the state if defined.
267  * Uses NaClLogGetGio() if undefined.
268  */
269 static INLINE void NaClPrintVMessage(NaClValidatorState* vstate,
270                                      const char* format,
271                                      va_list ap) {
272   if (vstate) {
273     vstate->error_reporter->printf_v(vstate->error_reporter, format, ap);
274   } else {
275     gvprintf(NaClLogGetGio(), format, ap);
276   }
277 }
278
279 /* Forward declaration to define printf arguments. */
280 static void NaClPrintMessage(NaClValidatorState* vstate,
281                              const char* format,
282                              ...) ATTRIBUTE_FORMAT_PRINTF(2, 3);
283
284 /* Does a printf using the error reporter of the state if defined.
285  * Uses NaClLogGetGio() if undefined.
286  */
287 static INLINE void NaClPrintMessage(NaClValidatorState* vstate,
288                                     const char* format,
289                                     ...) {
290   va_list ap;
291   va_start(ap, format);
292   NaClPrintVMessage(vstate, format, ap);
293   va_end(ap);
294 }
295
296 /* Print out a predefined prefix for messages, along with the serverity
297  * of the message.
298  */
299 static void NaClPrintValidatorPrefix(int level,
300                                      NaClValidatorState* vstate,
301                                      Bool visible_level) {
302   NaClPrintMessage(vstate, "VALIDATOR: ");
303   if (visible_level) NaClPrintMessage(vstate, "%s", NaClLogLevelLabel(level));
304 }
305
306 /* Prints out an instruction on behalf of the validator. */
307 static void NaClValidatorPrintInst(int level,
308                                    NaClValidatorState *vstate,
309                                    NaClInstState *inst) {
310   NaClPrintValidatorPrefix(level, vstate, FALSE);
311   if (vstate) {
312     vstate->error_reporter->print_inst(vstate->error_reporter, (void*) inst);
313   } else {
314     NaClInstStateInstPrint(NaClLogGetGio(), inst);
315   }
316 }
317
318 void NaClValidatorMessage(int level,
319                           NaClValidatorState *vstate,
320                           const char *format,
321                           ...) {
322   level = NaClRecordIfValidatorError(vstate, level);
323   if (NaClPrintValidatorMessages(vstate, level)) {
324     va_list ap;
325     NaClPrintValidatorPrefix(level, vstate, TRUE);
326     va_start(ap, format);
327     NaClPrintVMessage(vstate, format, ap);
328     va_end(ap);
329     NaClRecordErrorReported(vstate, level);
330   }
331 }
332
333 void NaClValidatorVarargMessage(int level,
334                                 NaClValidatorState *vstate,
335                                 const char *format,
336                                 va_list ap) {
337   level = NaClRecordIfValidatorError(vstate, level);
338   if (NaClPrintValidatorMessages(vstate, level)) {
339     NaClPrintValidatorPrefix(level, vstate, TRUE);
340     NaClPrintVMessage(vstate, format, ap);
341     NaClRecordErrorReported(vstate, level);
342   }
343 }
344
345 static void NaClValidatorPcAddressMess(
346     int level,
347     NaClValidatorState *vstate,
348     NaClPcAddress addr,
349     const char *format,
350     va_list ap) {
351   level = NaClRecordIfValidatorError(vstate, level);
352   if (NaClPrintValidatorMessages(vstate, level)) {
353     NaClPrintValidatorPrefix(level, vstate, !NACL_FLAGS_ncval_annotate);
354     NaClPrintMessage(vstate, "%"NACL_PRIxNaClPcAddress ": ", addr);
355     NaClPrintVMessage(vstate, format, ap);
356     NaClRecordErrorReported(vstate, level);
357   }
358 }
359
360 void NaClValidatorPcAddressMessage(int level,
361                                    NaClValidatorState *vstate,
362                                    NaClPcAddress addr,
363                                    const char *format,
364                                    ...) {
365   va_list ap;
366   va_start(ap, format);
367   NaClValidatorPcAddressMess(level, vstate, vstate->vbase + addr, format, ap);
368   va_end(ap);
369 }
370
371 void NaClValidatorInstMessage(int level,
372                               NaClValidatorState *vstate,
373                               NaClInstState *inst,
374                               const char *format,
375                               ...) {
376   if (NACL_FLAGS_ncval_annotate) {
377     va_list ap;
378     va_start(ap, format);
379     NaClValidatorPcAddressMess(level, vstate,
380                                NaClInstStatePrintableAddress(inst),
381                                format, ap);
382     va_end(ap);
383   } else {
384     level = NaClRecordIfValidatorError(vstate, level);
385     if (NaClPrintValidatorMessages(vstate, level)) {
386       va_list ap;
387       NaClValidatorPrintInst(level, vstate, inst);
388       NaClPrintValidatorPrefix(level, vstate, TRUE);
389       va_start(ap, format);
390       NaClPrintVMessage(vstate, format, ap);
391       va_end(ap);
392       NaClRecordErrorReported(vstate, level);
393     }
394   }
395   if (vstate->do_stub_out && (level <= LOG_ERROR)) {
396     NaClStubOutInst(vstate, inst);
397   }
398 }
399
400 void NaClValidatorTwoInstMessage(int level,
401                                  NaClValidatorState *vstate,
402                                  NaClInstState *inst1,
403                                  NaClInstState *inst2,
404                                  const char *format,
405                                  ...) {
406   level = NaClRecordIfValidatorError(vstate, level);
407   if (NaClPrintValidatorMessages(vstate, level)) {
408     va_list ap;
409     NaClPrintValidatorPrefix(level, vstate, TRUE);
410     va_start(ap, format);
411     NaClPrintVMessage(vstate, format, ap);
412     va_end(ap);
413     NaClPrintMessage(vstate, "\n                                   ");
414     NaClValidatorPrintInst(level, vstate, inst1);
415     NaClPrintMessage(vstate, "                                   ");
416     NaClValidatorPrintInst(level, vstate, inst2);
417     NaClRecordErrorReported(vstate, level);
418   }
419   if (vstate->do_stub_out && (level <= LOG_ERROR)) {
420     NaClStubOutInst(vstate, inst2);
421   }
422 }
423
424 Bool NaClValidatorQuit(NaClValidatorState *vstate) {
425   return !vstate->validates_ok && (vstate->quit_after_error_count == 0);
426 }
427
428 Bool NaClValidatorDidStubOut(NaClValidatorState *vstate) {
429   return vstate->did_stub_out;
430 }
431
432 static void NaClNullErrorPrintInst(NaClErrorReporter* self,
433                                    struct NaClInstState* inst) {}
434
435 NaClErrorReporter kNaClNullErrorReporter = {
436   NaClNullErrorReporter,
437   NaClNullErrorPrintf,
438   NaClNullErrorPrintfV,
439   (NaClPrintInst) NaClNullErrorPrintInst
440 };
441
442 /* Update caches associated the current instruction state associated with
443  * the iterator of the validator state. This routine should be called everytime
444  * the iterator (of the validator state) is advanced.
445  */
446 static INLINE void NaClUpdateCaches(NaClValidatorState *vstate) {
447 #ifdef NCVAL_TESTING
448   /* Initialize the pre/post conditions to the empty condition. */
449   strcpy(&vstate->precond[0], "");
450   strcpy(&vstate->postcond[0], "");
451 #endif
452   vstate->cur_inst_state = NaClInstIterGetStateInline(vstate->cur_iter);
453   vstate->cur_inst = NaClInstStateInst(vstate->cur_inst_state);
454   vstate->cur_inst_vector = NaClInstStateExpVector(vstate->cur_inst_state);
455 }
456
457 /* Returns true if the current position of the instruction iterator (for
458  * the validator state) points to an instruction (i.e. not at the end of
459  * the segment).
460  */
461 static INLINE Bool NaClValidatorStateIterHasNextInline(
462     NaClValidatorState *vstate) {
463   Bool result;
464   if (NULL == vstate->cur_iter) return FALSE;
465   result = NaClInstIterHasNextInline(vstate->cur_iter);
466   if (result && NULL == vstate->cur_inst_state) {
467     /* If reached, this is the first query to check if there is
468      * a next instruction. Update the caches to match.
469      */
470     NaClUpdateCaches(vstate);
471   }
472   return result;
473 }
474
475 Bool NaClValidatorStateIterHasNext(NaClValidatorState *vstate) {
476   return NaClValidatorStateIterHasNextInline(vstate);
477 }
478
479 /* Move past the current instruction defined by the iterator of the
480  * validator state.
481  */
482 static INLINE void NaClValidatorStateIterAdvanceInline(
483     NaClValidatorState *vstate) {
484   NaClInstIterAdvanceInline(vstate->cur_iter);
485   NaClUpdateCaches(vstate);
486 }
487
488 void NaClValidatorStateIterAdvance(NaClValidatorState *vstate) {
489   NaClValidatorStateIterAdvanceInline(vstate);
490 }
491
492 /* Iterator of the validator state is no longer needed, clean up any
493  * caches associated with the iterator.
494  */
495 static void NaClValidatorStateIterFinishInline(NaClValidatorState *vstate) {
496   vstate->cur_inst_state = NULL;
497   vstate->cur_inst = NULL;
498   vstate->cur_inst_vector = NULL;
499 }
500
501 void NaClValidatorStateIterFinish(NaClValidatorState *vstate) {
502   NaClValidatorStateIterFinishInline(vstate);
503 }
504
505 NaClValidatorState *NaClValidatorStateCreate(
506     const NaClPcAddress vbase,
507     const NaClMemorySize codesize,
508     const NaClOpKind base_register,
509     const int readonly_text,
510     const NaClCPUFeaturesX86 *features) {
511   NaClValidatorState *vstate;
512   NaClValidatorState *return_value = NULL;
513   const int bundle_size = 32;
514   DEBUG(NaClLog(LOG_INFO,
515                 "Validator Create: vbase = %"NACL_PRIxNaClPcAddress", "
516                 "sz = %"NACL_PRIxNaClMemorySize", bundle_size = %u\n",
517                 vbase, codesize, bundle_size));
518   if (features == NULL)
519     return NULL;
520   vstate = (NaClValidatorState*) malloc(sizeof(NaClValidatorState));
521   if (vstate != NULL) {
522     return_value = vstate;
523     vstate->decoder_tables = kNaClValDecoderTables;
524     vstate->vbase = vbase;
525     vstate->bundle_size = bundle_size;
526     vstate->codesize = codesize;
527     vstate->bundle_mask = bundle_size - 1;
528     NaClCopyCPUFeaturesX86(&vstate->cpu_features, features);
529     vstate->base_register = base_register;
530     vstate->validates_ok = TRUE;
531     vstate->did_stub_out = FALSE;
532     vstate->quit_after_error_count = NACL_FLAGS_max_reported_errors;
533 #ifdef NCVAL_TESTING
534     vstate->validates_ok_with_conditions = TRUE;
535     vstate->report_conditions_on_all = NACL_FLAGS_report_conditions_on_all;
536 #endif
537     vstate->error_reporter = &kNaClNullErrorReporter;
538     vstate->print_opcode_histogram = NACL_FLAGS_opcode_histogram;
539     vstate->trace_instructions = NACL_FLAGS_validator_trace_instructions;
540     vstate->trace_inst_internals = NACL_FLAGS_validator_trace_inst_internals;
541     vstate->log_verbosity = LOG_INFO;
542     vstate->cur_iter = NULL;
543     NaClValidatorStateIterFinishInline(vstate);
544     vstate->quit = NaClValidatorQuit(return_value);
545     vstate->do_stub_out = FALSE;
546     vstate->readonly_text = readonly_text;
547     vstate->do_detailed = FALSE;
548     NaClOpcodeHistogramInitialize(vstate);
549     NaClCpuCheckMemoryInitialize(vstate);
550     NaClBaseRegisterMemoryInitialize(vstate);
551     if (!NaClJumpValidatorInitialize(vstate)) {
552       NaClValidatorStateDestroy(vstate);
553       return_value = NULL;
554     }
555   }
556   return return_value;
557 }
558
559 Bool NaClValidatorStateIterReset(NaClValidatorState *vstate) {
560   /* Record infromation needed to reset the iterator, based on the
561    * current iterator
562    */
563   size_t lookback_size = lookback_size = vstate->cur_iter->buffer_size;
564   NaClSegment* segment = vstate->cur_iter->segment;
565
566   if (NULL == vstate->cur_iter) return FALSE;
567
568   /* Before deleting, be sure to clean up cached information. and
569    * the destroy the current validator. */
570   NaClValidatorStateIterFinishInline(vstate);
571   NaClInstIterDestroy(vstate->cur_iter);
572
573   /* Now create a new instruction iterator. */
574   vstate->cur_iter = NaClInstIterCreateWithLookback(
575       vstate->decoder_tables, segment, lookback_size);
576
577   if (NULL == vstate->cur_iter) return FALSE;
578   return TRUE;
579 }
580
581 #ifdef NCVAL_TESTING
582 void NaClPrintConditions(NaClValidatorState *state) {
583   /* To save space, only report on instructions that have non-empty
584    * pre/post conditions.
585    */
586   if ((strlen(state->precond) > 0) || (strlen(state->postcond) > 0)) {
587     printf("%"NACL_PRIxNaClPcAddress": ",
588            NaClInstStatePrintableAddress(state->cur_inst_state));
589     if ('\0' != state->precond[0]) {
590       printf("%s", state->precond);
591     }
592     if ('\0' != state->postcond[0]) {
593       if ('\0' != state->precond[0]) printf(" ");
594       printf("-> %s", state->postcond);
595     }
596     printf("\n");
597   }
598 }
599 #endif
600
601 /* Given we are at the instruction defined by the instruction iterator, for
602  * a segment, apply all applicable validator functions.
603  */
604 static INLINE void NaClApplyValidators(NaClValidatorState *vstate) {
605   if (vstate->quit) return;
606   DEBUG(NaClLog(LOG_INFO, "iter state:\n");
607         NaClInstStateInstPrint(NaClLogGetGio(),
608                                NaClInstIterGetState(vstate->cur_iter)));
609   if (NaClValidatorStateTraceInline(vstate)) {
610     NaClValidatorTrace(vstate);
611   }
612   NaClCpuCheck(vstate, vstate->cur_iter);
613   NaClValidateInstructionLegal(vstate);
614   NaClBaseRegisterValidator(vstate);
615   NaClMemoryReferenceValidator(vstate);
616   NaClJumpValidator(vstate);
617   if (vstate->print_opcode_histogram) {
618     NaClOpcodeHistogramRecord(vstate);
619   }
620 #ifdef NCVAL_TESTING
621   /* Collect post conditions for instructions that are non-last.
622    * Only print pre/post conditions for valid instructions (ignoring
623    * pre/post conditions).
624    */
625   if (NaClValidatesOk(vstate) || vstate->report_conditions_on_all) {
626     NaClAddAssignsRegisterWithZeroExtendsPostconds(vstate);
627     NaClAddLeaSafeAddressPostconds(vstate);
628     NaClPrintConditions(vstate);
629   }
630   /* Reset the exit flags, so that errors do not stop
631    * other instructions from firing errors. By reseting these flags,
632    * it allows us to only print pre/post conditions for instructions
633    * that are not marked illegal.
634    */
635   if (!vstate->validates_ok) vstate->validates_ok_with_conditions = FALSE;
636   vstate->validates_ok = TRUE;
637   vstate->quit = FALSE;
638 #endif
639 }
640
641 /* Given that we have just iterated through all instructions in a segment,
642  * apply post validators rules (before we collect the iterator).
643  */
644 static INLINE void NaClApplyPostValidators(NaClValidatorState *vstate) {
645   DEBUG(NaClLog(LOG_INFO, "applying post validators...\n"));
646   if (vstate->quit || (NULL == vstate->cur_iter)) return;
647
648   /* Before doing anything else, process remaining (forward) information
649    * stored by the validator, to see if any errors should be reported
650    * about the last instruction processed.
651    */
652   NaClBaseRegisterSummarize(vstate);
653
654   /* Now do the summarizing steps of the validator. */
655   if (vstate->do_detailed) {
656     NaClJumpValidatorSummarizeDetailed(vstate);
657   } else {
658     NaClJumpValidatorSummarize(vstate);
659   }
660   if (NaClValidatorStateTrace(vstate)) {
661     (vstate->error_reporter->printf)
662         (vstate->error_reporter, "<- visit\n");
663   }
664 }
665
666 /* The maximum lookback for the instruction iterator of the segment.
667  * Note: Allows for two memory patterns (4 instructions for each pattern).
668  */
669 static const size_t kLookbackSize = 8;
670
671 void NaClValidateSegment(uint8_t *mbase, NaClPcAddress vbase,
672                          NaClMemorySize size, NaClValidatorState *vstate) {
673   NaClSegment segment;
674   do {
675     /* Sanity checks */
676     /* TODO(ncbray): remove redundant vbase/size args. */
677     if ((vbase & vstate->bundle_mask) != 0) {
678       NaClValidatorMessage(LOG_ERROR, vstate,
679                            "Code segment starts at 0x%"NACL_PRIxNaClPcAddress
680                            ", which isn't aligned properly.\n",
681                            vbase);
682       break;
683     }
684     if (vbase != vstate->vbase) {
685       NaClValidatorMessage(LOG_ERROR, vstate, "Mismatched vbase address\n");
686       break;
687     }
688     if (size != vstate->codesize) {
689       NaClValidatorMessage(LOG_ERROR, vstate, "Mismatched code size\n");
690       break;
691     }
692     if (vbase > vbase + size) {
693       NaClValidatorMessage(LOG_ERROR, vstate, "Text segment too big for given "
694                            "vbase (address overflow)\n");
695       break;
696     }
697
698     size = NCHaltTrimSize(mbase, size, vstate->bundle_size);
699     vstate->codesize = size;
700
701     if (size == 0) {
702       NaClValidatorMessage(LOG_ERROR, vstate, "Bad text segment (zero size)\n");
703       break;
704     }
705
706     NaClSegmentInitialize(mbase, vbase, size, &segment);
707
708     vstate->cur_iter = NaClInstIterCreateWithLookback(vstate->decoder_tables,
709                                                       &segment, kLookbackSize);
710     if (NULL == vstate->cur_iter) {
711       NaClValidatorMessage(LOG_ERROR, vstate, "Not enough memory\n");
712       break;
713     }
714     for (; NaClValidatorStateIterHasNextInline(vstate);
715          NaClValidatorStateIterAdvanceInline(vstate)) {
716       NaClApplyValidators(vstate);
717       if (vstate->quit) break;
718     }
719     NaClValidatorStateIterFinish(vstate);
720   } while (0);
721   NaClApplyPostValidators(vstate);
722   NaClInstIterDestroy(vstate->cur_iter);
723   vstate->cur_iter = NULL;
724   if (vstate->print_opcode_histogram) {
725     NaClOpcodeHistogramPrintStats(vstate);
726   }
727 #ifdef NCVAL_TESTING
728   /* Update failure to catch instructions that may have validated
729    * incorrectly.
730    */
731   if (vstate->validates_ok)
732     vstate->validates_ok = vstate->validates_ok_with_conditions;
733 #endif
734 }
735
736 void NaClValidateSegmentUsingTables(uint8_t* mbase,
737                                     NaClPcAddress vbase,
738                                     NaClMemorySize sz,
739                                     NaClValidatorState* vstate,
740                                     const struct NaClDecodeTables* tables) {
741   vstate->decoder_tables = tables;
742   NaClValidateSegment(mbase, vbase, sz, vstate);
743 }
744
745 Bool NaClValidatesOk(NaClValidatorState *vstate) {
746   return vstate->validates_ok;
747 }
748
749 void NaClValidatorStateDestroy(NaClValidatorState *vstate) {
750   if (NULL != vstate) {
751     NaClJumpValidatorCleanUp(vstate);
752     free(vstate);
753   }
754 }
755
756 /*
757  * Check that iter_new is a valid replacement for iter_old.
758  * If a validation error occurs, vstate->validates_ok will be set to false by
759  * NaClValidatorInstMessage when it is given LOG_ERROR, see the end of this
760  * function.
761  * Return value: TRUE if the instruction was changed, FALSE if it's identical.
762  */
763 static Bool NaClValidateInstReplacement(NaClInstIter *iter_old,
764                                         NaClInstIter *iter_new,
765                                         struct NaClValidatorState *vstate) {
766   NaClInstState *istate_old, *istate_new;
767   NaClExpVector *exp_old, *exp_new;
768   uint32_t i;
769   Bool inst_changed = FALSE;
770   int parent_index;
771
772   istate_old = NaClInstIterGetStateInline(iter_old);
773   istate_new = NaClInstIterGetStateInline(iter_new);
774
775   /* Location/length must match.  Assumes vbase is the same. */
776   if (istate_new->inst_addr != istate_old->inst_addr ||
777       istate_new->bytes.length != istate_old->bytes.length) {
778     NaClValidatorTwoInstMessage(LOG_ERROR, vstate, istate_old, istate_new,
779           "Code modification: instructions length/addresses do not match");
780     inst_changed = TRUE;
781     return inst_changed;
782   }
783
784
785   do {
786     /* fast check if the replacement is identical */
787     if ((istate_old->bytes.memory->read_length ==
788          istate_new->bytes.memory->read_length) &&
789         !memcmp(istate_old->bytes.memory->mpc, istate_new->bytes.memory->mpc,
790                 istate_old->bytes.memory->read_length))
791       return inst_changed;
792
793     inst_changed = TRUE;
794
795     if (istate_old->num_prefix_bytes != istate_new->num_prefix_bytes)
796       break;
797     if (istate_old->num_rex_prefixes != istate_new->num_rex_prefixes)
798       break;
799     if (istate_old->rexprefix != istate_new->rexprefix)
800       break;
801     if (istate_old->modrm != istate_new->modrm)
802       break;
803     if (istate_old->has_sib != istate_new->has_sib)
804       break;
805     if (istate_old->has_sib && istate_old->sib != istate_new->sib)
806       break;
807     if (istate_old->operand_size != istate_new->operand_size)
808       break;
809     if (istate_old->address_size != istate_new->address_size)
810       break;
811     if (istate_old->prefix_mask != istate_new->prefix_mask)
812       break;
813
814     /*
815      * these are pointers, but they reference entries in a static table,
816      * so if the two instructions are the same, then these pointers must
817      * reference the same entry
818      */
819     if (istate_old->inst != istate_new->inst)
820       break;
821
822     exp_old = NaClInstStateExpVector(istate_old);
823     exp_new = NaClInstStateExpVector(istate_new);
824
825     /* check if the instruction operands are identical */
826     if (exp_old->number_expr_nodes != exp_new->number_expr_nodes)
827       break;
828
829     for (i = 0; i < exp_old->number_expr_nodes; i++) {
830       /* Allow nodes that are identical. */
831       if (exp_old->node[i].kind  != exp_new->node[i].kind) goto error_exit;
832       if (exp_old->node[i].flags != exp_new->node[i].flags) goto error_exit;
833       if (exp_old->node[i].value == exp_new->node[i].value) continue;
834
835       /*
836        * Only constant values may differ. However it is important not to
837        * allow constant modification of sandboxing instructions. Note neither
838        * of the instructions allowed for modification is used for sandboxing.
839        */
840       if (exp_old->node[i].kind != ExprConstant) goto error_exit;
841
842       switch (istate_old->inst->name) {
843
844         case InstCall:
845           /* allow different constants in direct calls */
846           if (!NaClHasBit(exp_old->node[i].flags, NACL_EFLAG(ExprJumpTarget)))
847             break;
848           parent_index = NaClGetExpParentIndex(exp_old, i);
849           if (parent_index < 0) break;
850           if (exp_old->node[parent_index].kind == OperandReference) continue;
851           break;
852
853         case InstMov:
854           parent_index = NaClGetExpParentIndex(exp_old, i);
855           if (parent_index < 0) break;
856           switch (exp_old->node[parent_index].kind) {
857             case OperandReference:
858               /*
859                * allow different constants in operand of mov
860                * e.g. mov $rax, 0xdeadbeef
861                */
862               if (NaClHasBit(exp_old->node[i].flags, NACL_EFLAG(ExprUsed)))
863                 continue;
864               break;
865             case ExprMemOffset:
866               /*
867                * allow different displacements in memory reference of mov
868                * instructions e.g. mov $rax, [$r15+$rbx*2+0x7fff]
869                *
870                * Note: displacement is the fourth node after ExprMemOffset*
871                * node
872                */
873               if (4 == (i - parent_index)) continue;
874               break;
875             default:
876               break;
877           }
878           break;
879         default:
880           break;
881       }
882
883       /* If reached, we found a value that differed, and wasn't one
884        * of the expected constants that can differ.
885        */
886       goto error_exit;
887     }
888
889     /* This return signifies there is no error in validation. */
890     return inst_changed;
891   } while (0);
892
893 error_exit:
894   /* This logging function is the mechanism that sets the validator state
895    * to indicate an error.
896    */
897   NaClValidatorTwoInstMessage(LOG_ERROR, vstate, istate_old, istate_new,
898                       "Code modification: failed to modify instruction");
899   return inst_changed;
900 }
901
902 /*
903  * Validate a new code block as a replacement for an existing block.
904  * Note: The code location (vbase) must be bundle aligned and the segment size
905  * must also be a multiple of bundle size (checked in
906  * NaClValidateCodeReplacement).This is to ensure all NaCl psuedo-instructions
907  * and guard sequences are properly inspected and maintained.
908  */
909 void NaClValidateSegmentPair(uint8_t *mbase_old, uint8_t *mbase_new,
910                            NaClPcAddress vbase, size_t size,
911                            struct NaClValidatorState *vstate) {
912   NaClSegment segment_old, segment_new;
913   NaClInstIter *iter_old = NULL;
914   NaClInstIter *iter_new = NULL;
915
916   NaClSegmentInitialize(mbase_old, vbase, size, &segment_old);
917   NaClSegmentInitialize(mbase_new, vbase, size, &segment_new);
918   do {
919     iter_old = NaClInstIterCreateWithLookback(vstate->decoder_tables,
920                                               &segment_old, kLookbackSize);
921     if (NULL == iter_old) break;
922     iter_new = NaClInstIterCreateWithLookback(vstate->decoder_tables,
923                                               &segment_new, kLookbackSize);
924     if (NULL == iter_new) break;
925     vstate->cur_iter = iter_new;
926     while (NaClInstIterHasNextInline(iter_old) &&
927            NaClValidatorStateIterHasNextInline(vstate)) {
928       vstate->cur_inst_state->unchanged =
929           !NaClValidateInstReplacement(iter_old, iter_new, vstate);
930       NaClApplyValidators(vstate);
931       if (vstate->quit) break;
932       NaClInstIterAdvanceInline(iter_old);
933       NaClValidatorStateIterAdvanceInline(vstate);
934     }
935     if (NaClInstIterHasNextInline(iter_old) ||
936         NaClInstIterHasNextInline(iter_new)) {
937       NaClValidatorMessage(
938           LOG_ERROR, vstate,
939           "Code modification: code segments have different "
940           "number of instructions\n");
941     }
942   } while (0);
943   NaClValidatorStateIterFinish(vstate);
944   NaClApplyPostValidators(vstate);
945   vstate->cur_iter = NULL;
946   NaClInstIterDestroy(iter_old);
947   NaClInstIterDestroy(iter_new);
948 }