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.c
9 : * Validate x86 instructions for Native Client
10 : *
11 : */
12 :
13 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate.h"
14 :
15 : #include <stdio.h>
16 : #include <stdlib.h>
17 : #include <errno.h>
18 : #include <string.h>
19 : #include <assert.h>
20 :
21 : #include "native_client/src/include/portability.h"
22 : #include "native_client/src/shared/platform/nacl_check.h"
23 : #include "native_client/src/trusted/validator/x86/halt_trim.h"
24 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h"
25 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_internaltypes.h"
26 :
27 : #include "native_client/src/trusted/validator/x86/ncinstbuffer_inl.c"
28 : #include "native_client/src/trusted/validator/x86/x86_insts_inl.c"
29 :
30 : #if NACL_TARGET_SUBARCH == 64
31 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncbadprefixmask_64.h"
32 : #else
33 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncbadprefixmask_32.h"
34 : #endif
35 :
36 : /* debugging stuff */
37 : #define DEBUGGING 0
38 : #if DEBUGGING
39 : #define dprint(args) do { printf args; } while (0)
40 : #else
41 : #define dprint(args) do { if (0) { printf args; } } while (0)
42 : /* allows DCE but compiler can still do format string checks */
43 : #endif /* DEBUGGING */
44 :
45 : /* TODO(bradchen) verbosity needs to be controllable via commandline flags */
46 : #define VERBOSE 1
47 : #if VERBOSE
48 : #define vprint(vstate, args) \
49 : do { \
50 : NaClErrorReporter* reporter = vstate->dstate.error_reporter; \
51 : (*reporter->printf) args; \
52 : } while (0)
53 : #else
54 : #define vprint(vstate, args) \
55 : do { \
56 : if (0) { \
57 : NaClErrorReporter* reporter = vstate->dstate.error_reporter; \
58 : (*reporter->printf) args; \
59 : } \
60 : } while (0)
61 : /* allows DCE but compiler can still do format string checks */
62 : #endif /* VERBOSE */
63 :
64 : static const uint8_t kNaClFullStop = 0xf4; /* x86 HALT opcode */
65 :
66 : /* Define how many diagnostic error messages are printed by the validator.
67 : * A value of zero generates no diagnostics.
68 : * A value >0 allows up to that many diagnostic error messages.
69 : * A negative value prints all diagnostic error messages.
70 : */
71 : static int kMaxDiagnostics = 0;
72 :
73 0 : int NCValidatorGetMaxDiagnostics() {
74 0 : return kMaxDiagnostics;
75 : }
76 :
77 68 : void NCValidatorSetMaxDiagnostics(int new_value) {
78 68 : kMaxDiagnostics = new_value;
79 68 : }
80 :
81 : /* This function is intended to only be called by ValidatePrintInstructionError
82 : * and ValidatePrintOffsetError.
83 : */
84 : static void ValidatePrintError(const NaClPcAddress addr,
85 : const char *msg,
86 1376 : struct NCValidatorState *vstate) {
87 1376 : if (vstate->num_diagnostics != 0) {
88 275 : NaClErrorReporter* reporter = vstate->dstate.error_reporter;
89 275 : (*reporter->printf)(
90 : reporter,
91 : "VALIDATOR: %"NACL_PRIxNaClPcAddress": %s\n", addr, msg);
92 275 : --(vstate->num_diagnostics);
93 275 : if (vstate->num_diagnostics == 0) {
94 0 : (*reporter->printf)(
95 : reporter,
96 : "VALIDATOR: Error limit reached, turning off diagnostics!\n");
97 : }
98 : }
99 1376 : }
100 :
101 : static void ValidatePrintInstructionError(const struct NCDecoderInst *dinst,
102 : const char *msg,
103 1367 : struct NCValidatorState *vstate) {
104 1367 : ValidatePrintError(NCPrintableInstructionAddress(dinst), msg, vstate);
105 1367 : }
106 :
107 : static void ValidatePrintOffsetError(const NaClPcAddress addr,
108 : const char *msg,
109 9 : struct NCValidatorState *vstate) {
110 9 : ValidatePrintError(vstate->iadrbase + addr, msg, vstate);
111 9 : }
112 :
113 : /* The low-level implementation for stubbing out an instruction. Always use
114 : * this function to (ultimately) stub out instructions. This makes it possible
115 : * to detect when the validator modifies the code.
116 : */
117 : static void NCStubOutMem(struct NCValidatorState *vstate, void *ptr,
118 3786 : size_t num) {
119 3786 : vstate->stats.didstubout = 1;
120 3786 : memset(ptr, kNaClFullStop, num);
121 3786 : }
122 :
123 : void NCBadInstructionError(const struct NCDecoderInst *dinst,
124 1309 : const char *msg) {
125 1309 : NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
126 1309 : ValidatePrintInstructionError(dinst, msg, vstate);
127 1309 : if (vstate->do_stub_out) {
128 1002 : NCStubOutMem(vstate, dinst->dstate->memory.mpc,
129 : dinst->dstate->memory.read_length);
130 : }
131 1309 : }
132 :
133 : /* The set of cpu features to use, if non-NULL.
134 : * NOTE: This global is used to allow the injection of
135 : * a command-line override of CPU features, from that of the local
136 : * CPU id, for the tool ncval. As such, when this global is non-null,
137 : * it uses the injected value this pointer points to as the corresponding
138 : * CPU id results to use.
139 : */
140 : static NaClCPUFeaturesX86 *nc_validator_features = NULL;
141 :
142 0 : void NCValidateSetCPUFeatures(NaClCPUFeaturesX86 *new_features) {
143 0 : nc_validator_features = new_features;
144 0 : }
145 :
146 : /* opcode histogram */
147 : #if VERBOSE == 1
148 733461 : void OpcodeHisto(const uint8_t byte1, struct NCValidatorState *vstate) {
149 733461 : vstate->opcodehisto[byte1] += 1;
150 733461 : }
151 :
152 175 : static void InitOpcodeHisto(struct NCValidatorState *vstate) {
153 : int i;
154 175 : for (i = 0; i < 256; i += 1) vstate->opcodehisto[i] = 0;
155 175 : }
156 :
157 134 : static void PrintOpcodeHisto(struct NCValidatorState *vstate) {
158 : int i;
159 134 : int printed_in_this_row = 0;
160 134 : NaClErrorReporter* reporter = vstate->dstate.error_reporter;
161 : if (!VERBOSE) return;
162 134 : (*reporter->printf)(reporter, "\nOpcode Histogram;\n");
163 34438 : for (i = 0; i < 256; ++i) {
164 34304 : if (0 != vstate->opcodehisto[i]) {
165 558 : (*reporter->printf)(reporter, "%d\t0x%02x\t", vstate->opcodehisto[i], i);
166 558 : ++printed_in_this_row;
167 558 : if (printed_in_this_row > 3) {
168 79 : printed_in_this_row = 0;
169 79 : (*reporter->printf)(reporter, "\n");
170 : }
171 : }
172 : }
173 134 : if (0 != printed_in_this_row) {
174 118 : (*reporter->printf)(reporter, "\n");
175 : }
176 134 : }
177 : #else
178 : #define OpcodeHisto(b, v)
179 : #define InitOpcodeHisto(v)
180 : #define PrintOpcodeHisto(f, v)
181 : #endif /* VERBOSE == 1 */
182 :
183 : /* statistics code */
184 733461 : static void NCStatsInst(struct NCValidatorState *vstate) {
185 733461 : vstate->stats.instructions += 1;
186 733461 : }
187 :
188 80187 : static void NCStatsCheckTarget(struct NCValidatorState *vstate) {
189 80187 : vstate->stats.checktarget += 1;
190 80187 : }
191 :
192 4229 : static void NCStatsTargetIndirect(struct NCValidatorState *vstate) {
193 4229 : vstate->stats.targetindirect += 1;
194 4229 : }
195 :
196 1411 : static void NCStatsSawFailure(struct NCValidatorState *vstate) {
197 1411 : vstate->stats.sawfailure = 1;
198 1411 : }
199 :
200 16 : void NCStatsInternalError(struct NCValidatorState *vstate) {
201 16 : vstate->stats.internalerrors += 1;
202 16 : NCStatsSawFailure(vstate);
203 16 : }
204 :
205 38 : void NCStatsBadAlignment(struct NCValidatorState *vstate) {
206 38 : vstate->stats.badalignment += 1;
207 38 : NCStatsSawFailure(vstate);
208 38 : }
209 :
210 7 : static void NCStatsSegFault(struct NCValidatorState *vstate) {
211 7 : vstate->stats.segfaults += 1;
212 7 : NCStatsSawFailure(vstate);
213 7 : }
214 :
215 174 : static void NCStatsNewSegment(struct NCValidatorState *vstate) {
216 174 : vstate->stats.segments += 1;
217 174 : if (vstate->stats.segments > 1) {
218 0 : vprint(vstate, (reporter, "error: multiple segments\n"));
219 0 : NCStatsSawFailure(vstate);
220 : }
221 174 : }
222 :
223 32 : void NCStatsBadTarget(struct NCValidatorState *vstate) {
224 32 : vstate->stats.badtarget += 1;
225 32 : NCStatsSawFailure(vstate);
226 32 : }
227 :
228 22 : static void NCStatsUnsafeIndirect(struct NCValidatorState *vstate) {
229 22 : vstate->stats.unsafeindirect += 1;
230 22 : NCStatsSawFailure(vstate);
231 22 : }
232 :
233 13 : static void NCStatsReturn(struct NCValidatorState *vstate) {
234 13 : vstate->stats.returns += 1;
235 13 : NCStatsUnsafeIndirect(vstate);
236 13 : NCStatsSawFailure(vstate);
237 13 : }
238 :
239 1245 : static void NCStatsIllegalInst(struct NCValidatorState *vstate) {
240 1245 : vstate->stats.illegalinst += 1;
241 1245 : NCStatsSawFailure(vstate);
242 1245 : }
243 :
244 38 : static void NCStatsBadPrefix(struct NCValidatorState *vstate) {
245 38 : vstate->stats.badprefix += 1;
246 38 : vstate->stats.illegalinst += 1; /* a bad prefix is also an invalid inst */
247 38 : NCStatsSawFailure(vstate);
248 38 : }
249 :
250 0 : static void NCStatsBadInstLength(struct NCValidatorState *vstate) {
251 0 : vstate->stats.badinstlength += 1;
252 0 : NCStatsSawFailure(vstate);
253 0 : }
254 :
255 175 : static void NCStatsInit(struct NCValidatorState *vstate) {
256 175 : vstate->stats.instructions = 0;
257 175 : vstate->stats.segments = 0;
258 175 : vstate->stats.checktarget = 0;
259 175 : vstate->stats.targetindirect = 0;
260 175 : vstate->stats.badtarget = 0;
261 175 : vstate->stats.unsafeindirect = 0;
262 175 : vstate->stats.returns = 0;
263 175 : vstate->stats.illegalinst = 0;
264 175 : vstate->stats.badalignment = 0;
265 175 : vstate->stats.internalerrors = 0;
266 175 : vstate->stats.badinstlength = 0;
267 175 : vstate->stats.badprefix = 0;
268 175 : vstate->stats.didstubout = 0;
269 175 : vstate->stats.sawfailure = 0;
270 175 : InitOpcodeHisto(vstate);
271 175 : }
272 :
273 134 : void NCStatsPrint(struct NCValidatorState *vstate) {
274 : NaClErrorReporter* reporter;
275 134 : if (!VERBOSE || (vstate == NULL)) return;
276 134 : reporter = vstate->dstate.error_reporter;
277 134 : PrintOpcodeHisto(vstate);
278 134 : (*reporter->printf)(reporter, "Analysis Summary:\n");
279 134 : (*reporter->printf)(reporter, "%d Checked instructions\n",
280 : vstate->stats.instructions);
281 134 : (*reporter->printf)(reporter, "%d checked jump targets\n",
282 : vstate->stats.checktarget);
283 134 : (*reporter->printf)(
284 : reporter, "%d calls/jumps need dynamic checking (%0.2f%%)\n",
285 : vstate->stats.targetindirect,
286 : vstate->stats.instructions ?
287 : 100.0 * vstate->stats.targetindirect/vstate->stats.instructions : 0);
288 134 : if (vstate->stats.didstubout) {
289 1 : (*reporter->printf)(reporter, "Some instructions were replaced with HLTs");
290 : }
291 134 : (*reporter->printf)(reporter, "\nProblems:\n");
292 134 : (*reporter->printf)(reporter, "%d illegal instructions\n",
293 : vstate->stats.illegalinst);
294 134 : (*reporter->printf)(reporter,
295 : "%d bad jump targets\n", vstate->stats.badtarget);
296 134 : (*reporter->printf)(
297 : reporter, "%d illegal unprotected indirect jumps (including ret)\n",
298 : vstate->stats.unsafeindirect);
299 134 : (*reporter->printf)(reporter, "%d instruction alignment defects\n",
300 : vstate->stats.badalignment);
301 134 : (*reporter->printf)(reporter, "%d segmentation errors\n",
302 : vstate->stats.segfaults);
303 134 : (*reporter->printf)(reporter, "%d bad prefix\n",
304 : vstate->stats.badprefix);
305 134 : (*reporter->printf)(reporter, "%d bad instruction length\n",
306 : vstate->stats.badinstlength);
307 134 : (*reporter->printf)(reporter, "%d internal errors\n",
308 : vstate->stats.internalerrors);
309 : }
310 :
311 : /***********************************************************************/
312 : /* jump target table */
313 : const uint8_t nc_iadrmasks[8] = {0x01, 0x02, 0x04, 0x08,
314 : 0x10, 0x20, 0x40, 0x80};
315 :
316 : /* forward declarations, needed for registration */
317 : static Bool ValidateInst(const NCDecoderInst *dinst);
318 : static Bool ValidateInstReplacement(NCDecoderStatePair* tthis,
319 : NCDecoderInst *dinst_old,
320 : NCDecoderInst *dinst_new);
321 : static void NCJumpSummarize(struct NCValidatorState* vstate);
322 :
323 : /*
324 : * NCValidateInit: Initialize NaCl validator internal state
325 : * Parameters:
326 : * vbase: base virtual address for code segment
327 : * codesize: size in bytes of code segment
328 : * alignment: 16 or 32, specifying alignment
329 : * Returns:
330 : * an initialized struct NCValidatorState * if everything is okay,
331 : * else NULL
332 : */
333 : struct NCValidatorState *NCValidateInit(const NaClPcAddress vbase,
334 : const NaClPcAddress codesize,
335 : const uint8_t alignment,
336 177 : NaClCPUFeaturesX86 *features) {
337 177 : struct NCValidatorState *vstate = NULL;
338 :
339 : dprint(("NCValidateInit(%"NACL_PRIxNaClPcAddressAll
340 : ", %"NACL_PRIxNaClMemorySizeAll", %08x)\n", vbase, codesize,
341 : alignment));
342 : do {
343 177 : if (alignment != 16 && alignment != 32)
344 1 : break;
345 176 : if ((vbase & (alignment - 1)) != 0)
346 1 : break;
347 175 : if (features == NULL)
348 0 : break;
349 : dprint(("ncv_init(%"NACL_PRIxNaClPcAddress", %"NACL_PRIxNaClMemorySize
350 : ")\n", vbase, codesize));
351 175 : vstate = (struct NCValidatorState *)calloc(1, sizeof(*vstate));
352 175 : if (vstate == NULL)
353 0 : break;
354 : /* Record default error reporter here, since we don't construct
355 : * the decoder state until the call to NCValidateSegment. This allows
356 : * us to update the error reporter in the decoder state properly.
357 : */
358 175 : vstate->dstate.error_reporter = &kNCNullErrorReporter;
359 175 : vstate->num_diagnostics = kMaxDiagnostics;
360 175 : vstate->iadrbase = vbase;
361 175 : vstate->codesize = codesize;
362 175 : vstate->alignment = alignment;
363 175 : vstate->alignmask = alignment-1;
364 175 : vstate->vttable = (uint8_t *)calloc(NCIATOffset(codesize) + 1, 1);
365 175 : vstate->kttable = (uint8_t *)calloc(NCIATOffset(codesize) + 1, 1);
366 175 : vstate->pattern_nonfirst_insts_table = NULL;
367 175 : vstate->summarize_fn = NCJumpSummarize;
368 175 : vstate->do_stub_out = 0;
369 175 : if (vstate->vttable == NULL || vstate->kttable == NULL)
370 : break;
371 : dprint((" allocated tables\n"));
372 175 : NCStatsInit(vstate);
373 175 : NaClCopyCPUFeatures(&vstate->cpufeatures, features);
374 175 : return vstate;
375 : } while (0);
376 : /* Failure. Clean up memory before returning. */
377 2 : if (NULL != vstate) {
378 0 : if (NULL != vstate->kttable)
379 0 : free(vstate->kttable);
380 0 : if (NULL != vstate->vttable)
381 0 : free(vstate->vttable);
382 0 : free(vstate);
383 : }
384 2 : return NULL;
385 : }
386 :
387 : void NCValidateSetStubOutMode(struct NCValidatorState *vstate,
388 3 : int do_stub_out) {
389 3 : vstate->do_stub_out = do_stub_out;
390 : /* We also turn off error diagnostics, under the assumption
391 : * you don't want them. (Note: if the user wants them,
392 : * you can run ncval to get them)/
393 : */
394 3 : if (do_stub_out) {
395 3 : NCValidateSetNumDiagnostics(vstate, 0);
396 : }
397 3 : }
398 :
399 : void NCValidateSetNumDiagnostics(struct NCValidatorState* vstate,
400 6 : int num_diagnostics) {
401 6 : vstate->num_diagnostics = num_diagnostics;
402 6 : }
403 :
404 : void NCValidateSetErrorReporter(struct NCValidatorState* state,
405 168 : NaClErrorReporter* error_reporter) {
406 168 : NCDecoderStateSetErrorReporter(&state->dstate, error_reporter);
407 168 : }
408 :
409 : static INLINE void RememberInstructionBoundary(const NCDecoderInst *dinst,
410 733461 : struct NCValidatorState *vstate) {
411 : /* The decoder should never pass us an out-of-bounds instruction. */
412 733461 : CHECK(dinst->inst_addr < vstate->codesize);
413 733461 : if (NCGetAdrTable(dinst->inst_addr, vstate->vttable)) {
414 0 : vprint(vstate, (reporter,
415 : "RememberIP: Saw inst at %"NACL_PRIxNaClPcAddressAll
416 : " twice\n", NCPrintableInstructionAddress(dinst)));
417 0 : NCStatsInternalError(vstate);
418 0 : return;
419 : }
420 733461 : NCStatsInst(vstate);
421 733461 : NCSetAdrTable(dinst->inst_addr, vstate->vttable);
422 : }
423 :
424 : static void RememberJumpTarget(const NCDecoderInst *dinst, int32_t jump_offset,
425 63629 : struct NCValidatorState *vstate) {
426 : NaClPcAddress target = (dinst->inst_addr + dinst->inst.bytes.length
427 63629 : + jump_offset);
428 :
429 63629 : if (target < vstate->codesize) {
430 63417 : NCSetAdrTable(target, vstate->kttable);
431 212 : } else if ((target & vstate->alignmask) == 0) {
432 : /* Allow bundle-aligned jumps. */
433 27 : } else if (dinst->unchanged) {
434 : /* If we are replacing this instruction during dynamic code modification
435 : * and it has not changed, the jump target must be valid because the
436 : * instruction has been previously validated. However, we may be only
437 : * replacing a subsection of the code segment and therefore may not have
438 : * information about instruction boundaries outside of the code being
439 : * replaced. Therefore, we allow unaligned direct jumps outside of the code
440 : * being validated if and only if the instruction is unchanged.
441 : * If dynamic code replacement is not being performed, inst->unchanged
442 : * should always be false.
443 : */
444 : } else {
445 27 : ValidatePrintInstructionError(dinst, "JUMP TARGET out of range", vstate);
446 27 : NCStatsBadTarget(vstate);
447 : }
448 63629 : }
449 :
450 : static void ForgetInstructionBoundary(const NCDecoderInst *dinst,
451 4226 : struct NCValidatorState *vstate) {
452 : /* The decoder should never pass us an out-of-bounds instruction. */
453 4226 : CHECK(dinst->inst_addr < vstate->codesize);
454 4226 : NCClearAdrTable(dinst->inst_addr, vstate->vttable);
455 4226 : if (NULL != vstate->pattern_nonfirst_insts_table) {
456 2669 : NCSetAdrTable(dinst->inst_addr, vstate->pattern_nonfirst_insts_table);
457 : }
458 4226 : }
459 :
460 174 : int NCValidateFinish(struct NCValidatorState *vstate) {
461 174 : if (vstate == NULL) {
462 : dprint(("validator not initialized. Did you call ncvalidate_init()?\n"));
463 : /* non-zero indicates failure */
464 0 : return 1;
465 : }
466 :
467 : /* If we are stubbing out code, the following checks don't provide any
468 : * usefull information, so quit early.
469 : */
470 174 : if (vstate->do_stub_out) return vstate->stats.sawfailure;
471 :
472 : /* Double check that the base address matches the alignment constraint. */
473 171 : if (vstate->iadrbase & vstate->alignmask) {
474 : /* This should never happen because the alignment of iadrbase is */
475 : /* checked in NCValidateInit(). */
476 0 : ValidatePrintOffsetError(0, "Bad base address alignment", vstate);
477 0 : NCStatsBadAlignment(vstate);
478 : }
479 :
480 : /* Apply summary analysis to collected data during pass over
481 : * instructions.
482 : */
483 171 : (*(vstate->summarize_fn))(vstate);
484 :
485 : /* Now that all the work is done, generate return code. */
486 : /* Return zero if there are no problems. */
487 171 : return (vstate->stats.sawfailure);
488 : }
489 :
490 175 : void NCValidateFreeState(struct NCValidatorState **vstate) {
491 175 : CHECK(*vstate != NULL);
492 175 : free((*vstate)->vttable);
493 175 : free((*vstate)->kttable);
494 175 : free((*vstate)->pattern_nonfirst_insts_table);
495 175 : free(*vstate);
496 175 : *vstate = NULL;
497 175 : }
498 :
499 : /* ValidateSFenceClFlush is called for the sfence/clflush opcode 0f ae /7 */
500 : /* It returns 0 if the current instruction is implemented, and 1 if not. */
501 2 : static int ValidateSFenceClFlush(const NCDecoderInst *dinst) {
502 2 : NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
503 2 : uint8_t mrm = NCInstBytesByteInline(&dinst->inst_bytes, 2);
504 :
505 2 : if (modrm_modInline(mrm) == 3) {
506 : /* this is an sfence */
507 1 : if (NaClGetCPUFeature(&vstate->cpufeatures, NaClCPUFeature_FXSR))
508 1 : return 0;
509 0 : return 1;
510 : } else {
511 : /* this is an clflush */
512 1 : if (NaClGetCPUFeature(&vstate->cpufeatures, NaClCPUFeature_CLFLUSH))
513 1 : return 0;
514 0 : return 1;
515 : }
516 : }
517 :
518 9635 : static void ValidateCallAlignment(const NCDecoderInst *dinst) {
519 9635 : NaClPcAddress fallthru = dinst->inst_addr + dinst->inst.bytes.length;
520 9635 : struct NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
521 9635 : if (fallthru & vstate->alignmask) {
522 31 : ValidatePrintInstructionError(dinst, "Bad call alignment", vstate);
523 : /* This makes bad call alignment a fatal error. */
524 31 : NCStatsBadAlignment(vstate);
525 : }
526 9635 : }
527 :
528 32725 : static void ValidateJmp8(const NCDecoderInst *dinst) {
529 : int8_t offset = NCInstBytesByteInline(&dinst->inst_bytes,
530 32725 : dinst->inst.prefixbytes+1);
531 32725 : struct NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
532 32725 : NCStatsCheckTarget(vstate);
533 32725 : RememberJumpTarget(dinst, offset, vstate);
534 32725 : }
535 :
536 30904 : static void ValidateJmpz(const NCDecoderInst *dinst) {
537 : NCInstBytesPtr opcode;
538 : uint8_t opcode0;
539 : int32_t offset;
540 30904 : NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
541 30904 : NCInstBytesPtrInitInc(&opcode, &dinst->inst_bytes,
542 : dinst->inst.prefixbytes);
543 30904 : opcode0 = NCInstBytesByteInline(&opcode, 0);
544 30904 : NCStatsCheckTarget(vstate);
545 30904 : if (opcode0 == 0x0f) {
546 : /* Multbyte opcode. Intruction is of form:
547 : * 0F80 .. 0F8F: jCC $Jz
548 : */
549 : NCInstBytesPtr opcode_2;
550 13623 : NCInstBytesPtrInitInc(&opcode_2, &opcode, 2);
551 13623 : offset = NCInstBytesInt32(&opcode_2, dinst->inst.immbytes);
552 : } else {
553 : /* Single byte opcode. Must be one of:
554 : * E8: call $Jz
555 : * E9: jmp $Jx
556 : */
557 : NCInstBytesPtr opcode_1;
558 17281 : NCInstBytesPtrInitInc(&opcode_1, &opcode, 1);
559 17281 : offset = NCInstBytesInt32(&opcode_1, dinst->inst.immbytes);
560 : /* as a courtesy, check call alignment correctness */
561 17281 : if (opcode0 == 0xe8) ValidateCallAlignment(dinst);
562 : }
563 30904 : RememberJumpTarget(dinst, offset, vstate);
564 30904 : }
565 :
566 : /*
567 : * The NaCl five-byte safe indirect calling sequence looks like this:
568 : * 83 e0 e0 and $0xe0,%eax
569 : * ff d0 call *%eax
570 : * The call may be replaced with a ff e0 jmp. Any register may
571 : * be used, not just eax. The validator requires exactly this
572 : * sequence.
573 : * Note: The code above assumes 32-bit alignment. Change e0 as appropriate
574 : * if a different alignment is used.
575 : */
576 4235 : static void ValidateIndirect5(const NCDecoderInst *dinst) {
577 : NCInstBytesPtr jmpopcode;
578 : NCInstBytesPtr andopcode;
579 : uint8_t mrm;
580 : uint8_t targetreg;
581 4235 : const uint8_t kReg_ESP = 4;
582 4235 : NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
583 :
584 4235 : struct NCDecoderInst *andinst = PreviousInst(dinst, 1);
585 4235 : if ((andinst == NULL) || (andinst->inst.bytes.length != 3)) {
586 6 : NCBadInstructionError(dinst, "Unsafe indirect jump");
587 6 : NCStatsUnsafeIndirect(vstate);
588 6 : return;
589 : }
590 : /* note: no prefixbytes allowed */
591 4229 : NCInstBytesPtrInitInc(&jmpopcode, &dinst->inst_bytes, 0);
592 : /* note: no prefixbytes allowed */
593 4229 : NCInstBytesPtrInitInc(&andopcode, &andinst->inst_bytes, 0);
594 4229 : mrm = NCInstBytesByteInline(&jmpopcode, 1);
595 : /* Note that the modrm_rm field holds the
596 : * target addr the modrm_reg is the opcode.
597 : */
598 4229 : targetreg = modrm_rmInline(mrm);
599 4229 : NCStatsCheckTarget(vstate);
600 4229 : NCStatsTargetIndirect(vstate);
601 : do {
602 : /* no prefix bytes allowed */
603 4229 : if (dinst->inst.prefixbytes != 0) break;
604 4229 : if (dinst->inst.prefixbytes != 0) break;
605 : /* Check all the opcodes. */
606 : /* In GROUP5, 2 => call, 4 => jmp */
607 4229 : if (NCInstBytesByteInline(&jmpopcode, 0) != 0xff) break;
608 4229 : if ((modrm_regInline(mrm) != 2) && (modrm_regInline(mrm) != 4)) break;
609 : /* Issue 32: disallow unsafe call/jump indirection */
610 : /* example: ff 12 call (*edx) */
611 : /* Reported by defend.the.world on 11 Dec 2008 */
612 4229 : if (modrm_modInline(mrm) != 3) break;
613 4228 : if (targetreg == kReg_ESP) break;
614 4227 : if (NCInstBytesByteInline(&andopcode, 0) != 0x83) break;
615 : /* check modrm bytes of or and and instructions */
616 4227 : if (NCInstBytesByteInline(&andopcode, 1) != (0xe0 | targetreg)) break;
617 : /* check mask */
618 4227 : if (NCInstBytesByteInline(&andopcode, 2) !=
619 1 : (0x0ff & ~vstate->alignmask)) break;
620 : /* All checks look good. Make the sequence 'atomic.' */
621 4226 : ForgetInstructionBoundary(dinst, vstate);
622 : /* as a courtesy, check call alignment correctness */
623 4226 : if (modrm_regInline(mrm) == 2) ValidateCallAlignment(dinst);
624 4226 : return;
625 : } while (0);
626 3 : NCBadInstructionError(dinst, "Unsafe indirect jump");
627 3 : NCStatsUnsafeIndirect(vstate);
628 : }
629 :
630 : /* Checks if the set of prefixes are allowed for the instruction.
631 : * By default, we only allow prefixes if they have been allowed
632 : * by the bad prefix mask generated inside ncdecode_table.c.
633 : * These masks are defined by the NaClInstType of the instruction.
634 : * See ncdecode_table.c for more details on how these masks are set.
635 : *
636 : * Currently:
637 : * Only 386, 386L, 386R, 386RE instruction allow Data 16
638 : * (unless used as part of instruction selection in a multibyte instruction).
639 : * Only 386, JMP8, and JMPZ allow segment registers prefixes.
640 : * Only 386L and CMPXCHG8B allow the LOCK prefix.
641 : * Only 386R and 386RE instructions allow the REP prefix.
642 : * Only 386RE instructions allow the REPNE prefix.
643 : *
644 : * Note: The prefixmask does not include the prefix value (if any) used to
645 : * select multiple byte instructions. Such prefixes have been moved to
646 : * opcode_prefixmask, so that the selection (based on that prefix) has
647 : * been recorded.
648 : *
649 : * In general, we do not allow multiple prefixes. Exceptions are as
650 : * follows:
651 : * 1 - Data 16 is allowed on lock instructions, so that 2 byte values
652 : * can be locked.
653 : * 2 - Multibyte instructions that are selected
654 : * using prefix values Data 16, REP and REPNE, can only have
655 : * one of these prefixes (Combinations of these three prefixes
656 : * are not allowed for such multibyte instructions).
657 : * 3 - Locks are only allowed on instructions with type 386L. The
658 : * exception is inst cmpxch8b, which also can have a lock.
659 : * 4 - The only two prefix byte combination allowed is Data 16 and Lock.
660 : * 5 - Long nops that are hard coded can contain more than one prefix.
661 : * See ncdecode.c for details (they don't use ValidatePrefixes).
662 : */
663 733461 : static Bool ValidatePrefixes(const NCDecoderInst *dinst) {
664 733461 : if (dinst->inst.prefixbytes == 0) return TRUE;
665 :
666 4323 : if ((dinst->inst.prefixmask &
667 : BadPrefixMask[dinst->opinfo->insttype]) != 0) {
668 33 : return FALSE;
669 : }
670 :
671 : /* If a multibyte instruction is using a selection prefix, be
672 : * sure that there is no conflict with other selection prefixes.
673 : */
674 4290 : if ((dinst->inst.opcode_prefixmask != 0) &&
675 : ((dinst->inst.prefixmask &
676 : (kPrefixDATA16 | kPrefixREPNE | kPrefixREP)) != 0)) {
677 0 : return FALSE;
678 : }
679 :
680 : /* Only allow a lock if it is a 386L instruction, or the special
681 : * cmpxchg8b instruction.
682 : */
683 4290 : if (dinst->inst.prefixmask & kPrefixLOCK) {
684 115 : if ((dinst->opinfo->insttype != NACLi_386L) &&
685 : (dinst->opinfo->insttype != NACLi_CMPXCHG8B)) {
686 0 : return FALSE;
687 : }
688 : }
689 :
690 : /* Only allow more than one prefix if two prefixes, and they are
691 : * data 16 and lock.
692 : */
693 4290 : if ((dinst->inst.prefixbytes > 1) &&
694 : !((dinst->inst.prefixbytes == 2) &&
695 : (dinst->inst.prefixmask == (kPrefixLOCK | kPrefixDATA16)) &&
696 : /* Be sure data 16 (66) appears before lock (f0) prefix. */
697 : (dinst->inst.lock_prefix_index == 1))) {
698 4 : return FALSE;
699 : }
700 :
701 4286 : return TRUE;
702 : }
703 :
704 : static const size_t kMaxValidInstLength = 11;
705 :
706 : /* The modrm mod field is a two-bit value. Values 00, 01, and, 10
707 : * define memory references. Value 11 defines register accesses instead
708 : * of memory.
709 : */
710 : static const int kModRmModFieldDefinesRegisterRef = 0x3;
711 :
712 733461 : static Bool ValidateInst(const NCDecoderInst *dinst) {
713 : NaClCPUFeaturesX86 *cpufeatures;
714 733461 : int squashme = 0;
715 : NCValidatorState* vstate;
716 733461 : if (dinst == NULL) return TRUE;
717 733461 : vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
718 :
719 733461 : OpcodeHisto(NCInstBytesByteInline(&dinst->inst_bytes,
720 : dinst->inst.prefixbytes),
721 : vstate);
722 733461 : RememberInstructionBoundary(dinst, vstate);
723 :
724 733461 : cpufeatures = &(vstate->cpufeatures);
725 :
726 733461 : if (!ValidatePrefixes(dinst)) {
727 37 : NCBadInstructionError(dinst, "Bad prefix usage");
728 37 : NCStatsBadPrefix(vstate);
729 : }
730 :
731 733461 : if ((dinst->opinfo->insttype != NACLi_NOP) &&
732 : ((size_t) (dinst->inst.bytes.length - dinst->inst.prefixbytes)
733 : > kMaxValidInstLength)) {
734 0 : NCBadInstructionError(dinst, "Instruction too long");
735 0 : NCStatsBadInstLength(vstate);
736 : }
737 :
738 733461 : switch (dinst->opinfo->insttype) {
739 : case NACLi_NOP:
740 : case NACLi_386:
741 : case NACLi_386L:
742 : case NACLi_386R:
743 : case NACLi_386RE:
744 659291 : break;
745 : case NACLi_JMP8:
746 32725 : ValidateJmp8(dinst);
747 32725 : break;
748 : case NACLi_JMPZ:
749 30904 : ValidateJmpz(dinst);
750 30904 : break;
751 : case NACLi_INDIRECT:
752 4235 : ValidateIndirect5(dinst);
753 4235 : break;
754 : case NACLi_X87:
755 3605 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_x87);
756 3605 : break;
757 : case NACLi_SFENCE_CLFLUSH:
758 2 : squashme = ValidateSFenceClFlush(dinst);
759 2 : break;
760 : case NACLi_CMPXCHG8B:
761 : /* Only allow if the modrm mod field accesses memory.
762 : * This stops us from accepting f00f on multiple bytes.
763 : * http://en.wikipedia.org/wiki/Pentium_F00F_bug
764 : */
765 2 : if (modrm_modInline(dinst->inst.mrm)
766 : == kModRmModFieldDefinesRegisterRef) {
767 1 : NCBadInstructionError(dinst, "Illegal instruction");
768 1 : NCStatsIllegalInst(vstate);
769 : }
770 2 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_CX8);
771 2 : break;
772 : case NACLi_CMOV:
773 778 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_CMOV);
774 778 : break;
775 : case NACLi_FCMOV:
776 14 : squashme = !(NaClGetCPUFeature(cpufeatures, NaClCPUFeature_CMOV) &&
777 : NaClGetCPUFeature(cpufeatures, NaClCPUFeature_x87));
778 14 : break;
779 : case NACLi_RDTSC:
780 0 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_TSC);
781 0 : break;
782 : case NACLi_MMX:
783 2 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_MMX);
784 2 : break;
785 : case NACLi_MMXSSE2:
786 : /* Note: We accept these instructions if either MMX or SSE2 bits */
787 : /* are set, in case MMX instructions go away someday... */
788 1 : squashme = !(NaClGetCPUFeature(cpufeatures, NaClCPUFeature_MMX) ||
789 : NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE2));
790 1 : break;
791 : case NACLi_SSE:
792 10 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE);
793 10 : break;
794 : case NACLi_SSE2:
795 631 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE2);
796 631 : break;
797 : case NACLi_SSE3:
798 1 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE3);
799 1 : break;
800 : case NACLi_SSE4A:
801 1 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE4A);
802 1 : break;
803 : case NACLi_SSE41:
804 3 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE41);
805 3 : break;
806 : case NACLi_SSE42:
807 2 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE42);
808 2 : break;
809 : case NACLi_MOVBE:
810 0 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_MOVBE);
811 0 : break;
812 : case NACLi_POPCNT:
813 1 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_POPCNT);
814 1 : break;
815 : case NACLi_LZCNT:
816 1 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_LZCNT);
817 1 : break;
818 : case NACLi_SSSE3:
819 3 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSSE3);
820 3 : break;
821 : case NACLi_3DNOW:
822 2 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_3DNOW);
823 2 : break;
824 : case NACLi_E3DNOW:
825 1 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_E3DNOW);
826 1 : break;
827 : case NACLi_SSE2x:
828 : /* This case requires CPUID checking code */
829 : /* Note: DATA16 prefix required. The generated table
830 : * for group 14 (which the only 2 SSE2x instructions are in),
831 : * allows instructions with and without a 66 prefix. However,
832 : * the SSE2x instructions psrldq and pslldq are only allowed
833 : * with the 66 prefix. Hence, this code has been added to
834 : * do this check.
835 : */
836 2 : if (!(dinst->inst.opcode_prefixmask & kPrefixDATA16)) {
837 1 : NCBadInstructionError(dinst, "Bad prefix usage");
838 1 : NCStatsBadPrefix(vstate);
839 : }
840 2 : squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE2);
841 2 : break;
842 :
843 : case NACLi_RETURN:
844 13 : NCBadInstructionError(dinst, "ret instruction (not allowed)");
845 13 : NCStatsReturn(vstate);
846 : /* ... and fall through to illegal instruction code */
847 : case NACLi_EMMX:
848 : /* EMMX needs to be supported someday but isn't ready yet. */
849 : case NACLi_INVALID:
850 : case NACLi_ILLEGAL:
851 : case NACLi_SYSTEM:
852 : case NACLi_RDMSR:
853 : case NACLi_RDTSCP:
854 : case NACLi_SYSCALL:
855 : case NACLi_SYSENTER:
856 : case NACLi_LONGMODE:
857 : case NACLi_SVM:
858 : case NACLi_OPINMRM:
859 : case NACLi_3BYTE:
860 : case NACLi_CMPXCHG16B: {
861 1228 : NCBadInstructionError(dinst, "Illegal instruction");
862 1228 : NCStatsIllegalInst(vstate);
863 1228 : break;
864 : }
865 : case NACLi_UNDEFINED: {
866 16 : NCBadInstructionError(dinst, "Undefined instruction");
867 16 : NCStatsIllegalInst(vstate);
868 16 : NCStatsInternalError(vstate);
869 16 : break;
870 : }
871 : default:
872 0 : NCBadInstructionError(dinst, "Undefined instruction type");
873 0 : NCStatsInternalError(vstate);
874 : break;
875 : }
876 733461 : if (squashme) {
877 2784 : NCStubOutMem(vstate, dinst->dstate->memory.mpc,
878 : dinst->dstate->memory.read_length);
879 : }
880 733461 : return TRUE;
881 : }
882 :
883 : /*
884 : * Validate that two nacljmps are byte-for-byte identical. Note that
885 : * one of the individual jumps must be validated in isolation with
886 : * ValidateIndirect5() before this is called.
887 : */
888 : static void ValidateIndirect5Replacement(NCDecoderInst *dinst_old,
889 0 : NCDecoderInst *dinst_new) {
890 : do {
891 : /* check that the and-guard is 3 bytes and bit-for-bit identical */
892 0 : NCDecoderInst *andinst_old = PreviousInst(dinst_old, 1);
893 0 : NCDecoderInst *andinst_new = PreviousInst(dinst_new, 1);
894 0 : if ((andinst_old == NULL) || (andinst_old->inst.bytes.length != 3)) break;
895 0 : if ((andinst_new == NULL) || (andinst_new->inst.bytes.length != 3)) break;
896 0 : if (memcmp(andinst_old->inst.bytes.byte,
897 0 : andinst_new->inst.bytes.byte, 3) != 0) break;
898 :
899 : /* check that the indirect-jmp is 2 bytes and bit-for-bit identical */
900 0 : if (dinst_old->inst.bytes.length != 2) break;
901 0 : if (dinst_new->inst.bytes.length != 2) break;
902 0 : if (memcmp(dinst_old->inst.bytes.byte,
903 0 : dinst_new->inst.bytes.byte, 2) != 0) break;
904 :
905 0 : return;
906 : } while (0);
907 0 : NCBadInstructionError(dinst_new,
908 : "Replacement indirect jump must match original");
909 0 : NCStatsUnsafeIndirect(NCVALIDATOR_STATE_DOWNCAST(dinst_new->dstate));
910 : }
911 :
912 : /*
913 : * Check that mstate_new is a valid replacement instruction for mstate_old.
914 : * Note that mstate_old was validated when it was inserted originally.
915 : */
916 : static Bool ValidateInstReplacement(NCDecoderStatePair* tthis,
917 : NCDecoderInst *dinst_old,
918 0 : NCDecoderInst *dinst_new) {
919 0 : dinst_new->unchanged = memcmp(dinst_old->inst.bytes.byte,
920 : dinst_new->inst.bytes.byte,
921 : dinst_new->inst.bytes.length) == 0;
922 0 : ValidateInst(dinst_new);
923 :
924 0 : if (dinst_old->opinfo->insttype == NACLi_INDIRECT
925 : || dinst_new->opinfo->insttype == NACLi_INDIRECT) {
926 : /* Verify that nacljmps never change */
927 0 : ValidateIndirect5Replacement(dinst_old, dinst_new);
928 : }
929 0 : return TRUE;
930 : }
931 :
932 : /* Create the decoder state for the validator state, using the
933 : * given parameters.
934 : */
935 : static void NCValidateDStateInit(NCValidatorState *vstate,
936 : uint8_t *mbase, NaClPcAddress vbase,
937 174 : NaClMemorySize sz) {
938 174 : NCDecoderState* dstate = &vstate->dstate;
939 : /* Note: Based on the current API, we must grab the error reporter
940 : * and reinstall it, after the call to NCValidateDStateInit, so that
941 : * we don't replace it with the default error reporter.
942 : */
943 174 : NaClErrorReporter* reporter = dstate->error_reporter;
944 174 : NCDecoderStateConstruct(dstate, mbase, vbase, sz,
945 : vstate->inst_buffer, kNCValidatorInstBufferSize);
946 174 : dstate->action_fn = ValidateInst;
947 174 : dstate->new_segment_fn = (NCDecoderStateMethod) NCStatsNewSegment;
948 174 : dstate->segmentation_error_fn = (NCDecoderStateMethod) NCStatsSegFault;
949 174 : dstate->internal_error_fn = (NCDecoderStateMethod) NCStatsInternalError;
950 174 : NCDecoderStateSetErrorReporter(dstate, reporter);
951 174 : }
952 :
953 : void NCValidateSegment(uint8_t *mbase, NaClPcAddress vbase, NaClMemorySize sz,
954 174 : struct NCValidatorState *vstate) {
955 : /* Sanity checks */
956 : /* TODO(ncbray): remove redundant vbase/size args. */
957 174 : if ((vbase & (vstate->alignment - 1)) != 0) {
958 0 : ValidatePrintOffsetError(0, "Bad vbase alignment", vstate);
959 0 : NCStatsSegFault(vstate);
960 0 : return;
961 : }
962 174 : if (vbase != vstate->iadrbase) {
963 0 : ValidatePrintOffsetError(0, "Mismatched vbase addresses", vstate);
964 0 : NCStatsSegFault(vstate);
965 0 : return;
966 : }
967 174 : if (sz != vstate->codesize) {
968 0 : ValidatePrintOffsetError(0, "Mismatched code size", vstate);
969 0 : NCStatsSegFault(vstate);
970 0 : return;
971 : }
972 :
973 174 : sz = NCHaltTrimSize(mbase, sz, vstate->alignment);
974 174 : vstate->codesize = sz;
975 :
976 174 : if (sz == 0) {
977 0 : ValidatePrintOffsetError(0, "Bad text segment (zero size)", vstate);
978 0 : NCStatsSegFault(vstate);
979 0 : return;
980 : }
981 174 : NCValidateDStateInit(vstate, mbase, vbase, sz);
982 174 : NCDecoderStateDecode(&vstate->dstate);
983 174 : NCDecoderStateDestruct(&vstate->dstate);
984 : }
985 :
986 : int NCValidateSegmentPair(uint8_t *mbase_old, uint8_t *mbase_new,
987 : NaClPcAddress vbase, size_t sz, uint8_t alignment,
988 0 : NaClCPUFeaturesX86 *features) {
989 : /* TODO(karl): Refactor to use inheritance from NCDecoderStatePair? */
990 : NCDecoderStatePair pair;
991 : NCValidatorState* new_vstate;
992 : NCValidatorState* old_vstate;
993 :
994 0 : int result = 0;
995 :
996 : /* Verify that we actually have a segment to walk. */
997 0 : if (sz == 0) {
998 0 : printf("VALIDATOR: %"NACL_PRIxNaClPcAddress
999 : ": Bad text segment (zero size)\n", vbase);
1000 0 : return 0;
1001 : }
1002 :
1003 0 : old_vstate = NCValidateInit(vbase, sz, alignment, features);
1004 0 : if (old_vstate != NULL) {
1005 0 : NCValidateDStateInit(old_vstate, mbase_old, vbase, sz);
1006 0 : new_vstate = NCValidateInit(vbase, sz, alignment, features);
1007 0 : if (new_vstate != NULL) {
1008 0 : NCValidateDStateInit(new_vstate, mbase_new, vbase, sz);
1009 :
1010 0 : NCDecoderStatePairConstruct(&pair,
1011 : &old_vstate->dstate,
1012 : &new_vstate->dstate);
1013 0 : pair.action_fn = ValidateInstReplacement;
1014 0 : if (NCDecoderStatePairDecode(&pair)) {
1015 0 : result = 1;
1016 : } else {
1017 0 : ValidatePrintOffsetError(0, "Replacement not applied!\n", new_vstate);
1018 : }
1019 0 : if (NCValidateFinish(new_vstate)) {
1020 : /* Errors occurred during validation. */
1021 0 : result = 0;
1022 : }
1023 0 : NCDecoderStatePairDestruct(&pair);
1024 0 : NCDecoderStateDestruct(&new_vstate->dstate);
1025 0 : NCValidateFreeState(&new_vstate);
1026 : }
1027 0 : NCDecoderStateDestruct(&old_vstate->dstate);
1028 0 : NCValidateFreeState(&old_vstate);
1029 : }
1030 0 : return result;
1031 : }
1032 :
1033 : /* Walk the collected information on instruction boundaries and jump targets,
1034 : * and verify that they are legal.
1035 : */
1036 151 : static void NCJumpSummarize(struct NCValidatorState* vstate) {
1037 : uint32_t offset;
1038 :
1039 : /* Verify that jumps are to the beginning of instructions, and that the
1040 : * jumped to instruction is not in the middle of a native client pattern.
1041 : */
1042 : dprint(("CheckTargets: %"NACL_PRIxNaClPcAddress"-%"NACL_PRIxNaClPcAddress"\n",
1043 : vstate->iadrbase, vstate->iadrbase+vstate->codesize));
1044 573230 : for (offset = 0; offset < vstate->codesize; offset += 1) {
1045 573079 : if (NCGetAdrTable(offset, vstate->kttable)) {
1046 12329 : NCStatsCheckTarget(vstate);
1047 12329 : if (!NCGetAdrTable(offset, vstate->vttable)) {
1048 3 : ValidatePrintOffsetError(offset, "Bad jump target", vstate);
1049 3 : NCStatsBadTarget(vstate);
1050 : }
1051 : }
1052 : }
1053 :
1054 : /* check basic block boundaries */
1055 18213 : for (offset = 0; offset < vstate->codesize; offset += vstate->alignment) {
1056 18062 : if (!NCGetAdrTable(offset, vstate->vttable)) {
1057 6 : ValidatePrintOffsetError(offset, "Bad basic block alignment", vstate);
1058 6 : NCStatsBadAlignment(vstate);
1059 : }
1060 : }
1061 151 : }
|