Debugging: Add code to print backtrace for guest on SIGSEGV
[nativeclient.git] / ncv / ncvalidate.c
blob76be49281aedab1dd44d798f6650654cf8c6646c
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * ncvalidate.c
34 * Validate x86 instructions for Native Client
37 #include "native_client/include/portability.h"
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <errno.h>
41 #include <string.h>
42 #include <assert.h>
43 #include "ncdecode.h"
44 #include "ncvalidate_internaltypes.h"
45 #include "nacl_cpuid.h"
46 #include "native_client/service_runtime/sel_ldr.h"
48 /* debugging stuff */
49 #define DEBUGGING 0
50 #if DEBUGGING
51 #define dprint(args) printf args
52 #else
53 #define dprint(args)
54 #endif /* DEBUGGING */
56 /* TODO verbosity needs to be controllable via commandline flags */
57 #define VERBOSE 1
58 #if VERBOSE
59 #define vprint(args) printf args
60 #else
61 #define vprint(args)
62 #endif /* VERBOSE */
64 static void ValidatePrintError(const uint32_t addr, char *msg) {
65 printf("VALIDATOR: %x: %s\n", addr, msg);
68 /* opcode histogram */
69 #if VERBOSE == 1
70 static void OpcodeHisto(const uint8_t byte1, struct NCValidatorState *vstate) {
71 vstate->opcodehisto[byte1] += 1;
74 static void InitOpcodeHisto(struct NCValidatorState *vstate) {
75 int i;
76 for (i = 0; i < 256; i += 1) vstate->opcodehisto[i] = 0;
79 static void PrintOpcodeHisto(FILE *f, struct NCValidatorState *vstate) {
80 int i;
81 int printed_in_this_row = 0;
82 if (!VERBOSE) return;
83 fprintf(f, "\nOpcode Histogram;\n");
84 for (i = 0; i < 256; ++i) {
85 if (0 != vstate->opcodehisto[i]) {
86 fprintf(f, "%d\t0x%02x\t", vstate->opcodehisto[i], i);
87 ++printed_in_this_row;
88 if (printed_in_this_row > 3) {
89 printed_in_this_row = 0;
90 fprintf(f, "\n");
94 if (0 != printed_in_this_row) {
95 fprintf(f, "\n");
98 #else
99 #define OpcodeHisto(b, v)
100 #define InitOpcodeHisto(v)
101 #define PrintOpcodeHisto(f, v)
102 #endif /* VERBOSE == 1 */
104 static void LogError(struct NCValidatorState *vstate, int addr,
105 const char *desc)
107 vprint(("VALIDATOR: %08x (%08x:?): %s\n",
108 addr, addr + vstate->file_offset, desc));
111 static void LogErrorInst(const struct NCDecoderState *mstate, const char *desc)
113 struct NCValidatorState *vstate = mstate->vstate;
114 uint32_t addr = mstate->inst.vaddr;
115 vprint(("VALIDATOR: %08x (%08x:%x): %s\n",
116 addr, addr + vstate->file_offset, mstate->inst.length, desc));
119 /* statistics code */
120 static void Stats_Inst(struct NCValidatorState *vstate) {
121 vstate->stats.instructions += 1;
124 static void Stats_CheckTarget(struct NCValidatorState *vstate) {
125 vstate->stats.checktarget += 1;
128 static void Stats_TargetIndirect(struct NCValidatorState *vstate) {
129 vstate->stats.targetindirect += 1;
132 static void Stats_SawFailure(struct NCValidatorState *vstate) {
133 vstate->stats.sawfailure = 1;
136 static void Stats_InternalError(struct NCValidatorState *vstate) {
137 vstate->stats.internalerrors += 1;
138 Stats_SawFailure(vstate);
141 static void Stats_BadCPU(struct NCValidatorState *vstate) {
142 vstate->stats.badcpu += 1;
143 Stats_SawFailure(vstate);
146 static void Stats_BadAlignment(struct NCValidatorState *vstate) {
147 vstate->stats.badalignment += 1;
148 Stats_SawFailure(vstate);
151 static void Stats_SegFault(struct NCValidatorState *vstate) {
152 vstate->stats.segfaults += 1;
153 Stats_SawFailure(vstate);
156 static void Stats_NewSegment(struct NCValidatorState *vstate) {
157 vstate->stats.segments += 1;
158 if (vstate->stats.segments > 1) {
159 vprint(("error: multiple segments\n"));
160 Stats_SawFailure(vstate);
164 static void Stats_BadTarget(struct NCValidatorState *vstate) {
165 vstate->stats.badtarget += 1;
166 Stats_SawFailure(vstate);
169 static void Stats_UnsafeIndirect(struct NCValidatorState *vstate) {
170 vstate->stats.unsafeindirect += 1;
171 Stats_SawFailure(vstate);
174 static void Stats_MissingFullStop(struct NCValidatorState *vstate) {
175 vstate->stats.missingfullstop += 1;
176 Stats_SawFailure(vstate);
179 static void Stats_Return(struct NCValidatorState *vstate) {
180 vstate->stats.returns += 1;
181 Stats_UnsafeIndirect(vstate);
182 Stats_SawFailure(vstate);
185 static void Stats_IllegalInst(struct NCValidatorState *vstate) {
186 vstate->stats.illegalinst += 1;
187 Stats_SawFailure(vstate);
190 static void Stats_BadPrefix(struct NCValidatorState *vstate) {
191 vstate->stats.badprefix += 1;
192 vstate->stats.illegalinst += 1; /* a bad prefix is also an invalid inst */
193 Stats_SawFailure(vstate);
196 static void Stats_BadInstLength(struct NCValidatorState *vstate) {
197 vstate->stats.badinstlength += 1;
198 Stats_SawFailure(vstate);
201 static void Stats_Init(struct NCValidatorState *vstate) {
202 static int inited = 0;
203 if (inited) return;
205 vstate->stats.instructions = 0;
206 vstate->stats.segments = 0;
207 vstate->stats.checktarget = 0;
208 vstate->stats.targetindirect = 0;
209 vstate->stats.badtarget = 0;
210 vstate->stats.unsafeindirect = 0;
211 vstate->stats.returns = 0;
212 vstate->stats.illegalinst = 0;
213 vstate->stats.badalignment = 0;
214 vstate->stats.internalerrors = 0;
215 vstate->stats.badcpu = 0;
216 vstate->stats.missingfullstop = 0;
217 vstate->stats.badinstlength = 0;
218 vstate->stats.badprefix = 0;
219 vstate->stats.sawfailure = 0;
220 InitOpcodeHisto(vstate);
221 inited = 1;
224 void Stats_Print(FILE *f, struct NCValidatorState *vstate) {
225 if (!VERBOSE) return;
226 if (vstate == NULL) {
227 fprintf(f, "Analysis Summary: invalid module or internal failure\n");
228 return;
230 PrintOpcodeHisto(f, vstate);
231 fprintf(f, "Analysis Summary:\n");
232 fprintf(f, "%d Checked instructions\n", vstate->stats.instructions);
233 fprintf(f, "%d checked jump targets\n", vstate->stats.checktarget);
234 fprintf(f, "%d calls/jumps need dynamic checking (%0.2f%%)\n",
235 vstate->stats.targetindirect,
236 vstate->stats.instructions ?
237 100.0 * vstate->stats.targetindirect/vstate->stats.instructions : 0);
238 fprintf(f, "\nProblems:\n");
239 fprintf(f, "%d illegal instructions\n", vstate->stats.illegalinst);
240 fprintf(f, "%d bad jump targets\n", vstate->stats.badtarget);
241 fprintf(f, "%d illegal unprotected indirect jumps (including ret)\n",
242 vstate->stats.unsafeindirect);
243 fprintf(f, "%d instruction alignment defects\n",
244 vstate->stats.badalignment);
245 fprintf(f, "%d segmentation errors\n",
246 vstate->stats.segfaults);
247 fprintf(f, "%d bad prefix\n",
248 vstate->stats.badprefix);
249 fprintf(f, "%d bad instruction length\n",
250 vstate->stats.badinstlength);
251 fprintf(f, "%d missing full stop\n",
252 vstate->stats.missingfullstop);
253 fprintf(f, "%d internal errors\n",
254 vstate->stats.internalerrors);
255 fprintf(f, "%d bad cpu\n",
256 vstate->stats.badcpu);
259 /***********************************************************************/
260 /* jump target table */
261 static const uint8_t iadrmasks[8] = {0x01, 0x02, 0x04, 0x08,
262 0x10, 0x20, 0x40, 0x80};
263 #define IATOffset(__IA) ((__IA) >> 3)
264 #define IATMask(__IA) (iadrmasks[(__IA) & 0x7])
265 #define SetAdrTable(__IOFF, __TABLE) \
266 (__TABLE)[IATOffset(__IOFF)] |= IATMask(__IOFF)
267 #define ClearAdrTable(__IOFF, __TABLE) \
268 (__TABLE)[IATOffset(__IOFF)] &= ~(IATMask(__IOFF))
269 #define GetAdrTable(__IOFF, __TABLE) \
270 ((__TABLE)[IATOffset(__IOFF)] & IATMask(__IOFF))
272 /* forward declaration, for registration */
273 void ValidateInst(const struct NCDecoderState *mstate);
275 /* In general we are quite paranoid about what prefixes can */
276 /* be used and where. For one-byte opcodes, prefixes are */
277 /* restricted based on the NACLi_ type and the masks in */
278 /* BadPrefixMask. For two-byte opcodes, any */
279 /* prefix can be used, but they function more to define the */
280 /* opcode as opposed to modify it; hence there are separate */
281 /* tables in ncdecodetab.h for the four allowed prefix bytes. */
282 static uint32_t BadPrefixMask[kNaClInstTypeRange];
283 static void InitBadPrefixMask() {
284 int i;
286 for (i = 0; i < kNaClInstTypeRange; i++) {
287 BadPrefixMask[i] = 0xffffffff; /* all prefixes are bad */
289 BadPrefixMask[NACLi_386] = ~(kPrefixDATA16 | kPrefixSEGGS);
290 BadPrefixMask[NACLi_386L] = ~(kPrefixDATA16 | kPrefixSEGGS | kPrefixLOCK);
291 BadPrefixMask[NACLi_386R] = ~(kPrefixDATA16 | kPrefixREP);
292 BadPrefixMask[NACLi_386RE] = ~(kPrefixDATA16 | kPrefixREP | kPrefixREPNE);
293 /* CS and DS prefix bytes are used as branch prediction hints */
294 /* and do not affect target address computation. */
295 BadPrefixMask[NACLi_JMP8] = ~(kPrefixSEGCS | kPrefixSEGDS);
296 BadPrefixMask[NACLi_JMPZ] = ~(kPrefixSEGCS | kPrefixSEGDS);
297 BadPrefixMask[NACLi_CMPXCHG8B] = ~kPrefixLOCK;
301 * NCValidateInit: Initialize NaCl validator internal state
302 * Parameters:
303 * vbase: base virtual address for code segment
304 * vlimit: size in bytes of code segment
305 * alignment: 16 or 32, specifying alignment
306 * Returns:
307 * an initialized struct NCValidatorState * if everything is okay,
308 * else NULL
310 struct NCValidatorState *NCValidateInit(const uint32_t vbase,
311 const uint32_t vlimit,
312 const uint8_t alignment) {
313 uint32_t alignbase = vbase & (~alignment);
314 struct NCValidatorState *vstate;
316 dprint(("NCValidateInit(%08x, %08x, %08x)\n", vbase, vlimit, alignment));
317 InitBadPrefixMask();
318 do {
319 if (vlimit <= vbase) break;
320 if (alignment != 16 && alignment != 32) break;
321 dprint(("ncv_init(%x, %x)\n", vbase, vlimit));
322 vstate = (struct NCValidatorState *)calloc(1, sizeof(*vstate));
323 if (vstate == NULL) break;
324 vstate->iadrbase = alignbase;
325 vstate->iadrlimit = vlimit;
326 vstate->alignment = alignment;
327 vstate->alignmask = alignment-1;
328 vstate->vttable = (uint8_t *)calloc(IATOffset(vlimit - alignbase) + 1, 1);
329 vstate->kttable = (uint8_t *)calloc(IATOffset(vlimit - alignbase) + 1, 1);
330 if (vstate->vttable == NULL || vstate->kttable == NULL) break;
331 dprint((" allocated tables\n"));
332 Stats_Init(vstate);
333 NCDecodeRegisterCallbacks(ValidateInst, Stats_NewSegment,
334 Stats_SegFault, Stats_InternalError);
335 return vstate;
336 } while (0);
337 /* failure */
338 return NULL;
341 static void RememberIP(const uint32_t ip, struct NCValidatorState *vstate) {
342 uint32_t ioffset = ip - vstate->iadrbase;
343 if (ip < vstate->iadrbase || ip >= vstate->iadrlimit) {
344 ValidatePrintError(ip, "JUMP TARGET out of range in RememberIP");
345 Stats_BadTarget(vstate);
346 return;
348 if (GetAdrTable(ioffset, vstate->vttable)) {
349 vprint(("RememberIP: Saw inst at %08x twice\n", ip));
350 Stats_InternalError(vstate);
351 return;
353 Stats_Inst(vstate);
354 SetAdrTable(ioffset, vstate->vttable);
357 static void RememberTP(const uint32_t src, uint32_t target,
358 struct NCValidatorState *vstate) {
359 uint32_t ioffset = target - vstate->iadrbase;
361 do {
362 if (target < vstate->iadrlimit) {
363 if (target >= vstate->iadrbase) break;
364 /* Aligned targets are always OK. */
365 if (target % NACL_INSTR_BLOCK_SIZE == 0)
366 return;
368 * the trampolines need to be aligned 0mod32 regardless of the
369 * program's elf flags. This allows the same library to be used
370 * with both 16 and 32 byte aligned clients.
372 if (target >= vstate->iadrbase - NACL_TRAMPOLINE_END
373 && ((target & (NACL_INSTR_BLOCK_SIZE-1)) == 0)) {
375 * TODO: once we fully support 16/32 alignment, remove this
376 * in favor of however we communicate the fixed block size.
378 /* this is an aligned target in the trampoline area; ignore */
379 /* vprint(("ignoring target %08x in trampoline\n", target)); */
380 return;
383 //vprint(("VALIDATOR: %08x: JUMP TARGET %08x out of range\n", src, target));
384 LogError(vstate, src, "Jump target out of range");
385 Stats_BadTarget(vstate);
386 return;
387 } while (0);
388 SetAdrTable(ioffset, vstate->kttable);
391 static void ForgetIP(const uint32_t ip,
392 struct NCValidatorState *vstate) {
393 uint32_t ioffset = ip - vstate->iadrbase;
394 if (ip < vstate->iadrbase || ip >= vstate->iadrlimit) {
395 ValidatePrintError(ip, "JUMP TARGET out of range in ForgetIP");
396 Stats_BadTarget(vstate);
397 return;
399 ClearAdrTable(ioffset, vstate->vttable);
402 int NCValidateFinish(struct NCValidatorState *vstate) {
403 uint32_t offset;
404 if (vstate == NULL) {
405 vprint(("validator not initialized. Did you call ncvalidate_init()?\n"));
406 /* non-zero indicates failure */
407 return 1;
409 dprint(("CheckTargets: %x-%x\n", vstate->iadrbase, vstate->iadrlimit));
410 for (offset = 0;
411 offset < vstate->iadrlimit - vstate->iadrbase;
412 offset += 1) {
413 if (GetAdrTable(offset, vstate->kttable)) {
414 /* printf("CheckTarget %x\n", offset + iadrbase); */
415 Stats_CheckTarget(vstate);
416 if (!GetAdrTable(offset, vstate->vttable)) {
417 Stats_BadTarget(vstate);
418 ValidatePrintError(vstate->iadrbase + offset, "Bad jump target");
422 /* check basic block boundaries */
423 if (vstate->iadrbase & vstate->alignmask) {
424 ValidatePrintError(vstate->iadrbase, "Bad base address alignment");
425 Stats_BadAlignment(vstate);
427 for (offset = 0; offset < vstate->iadrlimit - vstate->iadrbase;
428 offset += vstate->alignment) {
429 if (!GetAdrTable(offset, vstate->vttable)) {
430 ValidatePrintError(vstate->iadrbase + offset, "Bad basic block alignent");
431 Stats_BadAlignment(vstate);
434 fflush(stdout);
436 /* Now that all the work is done, generate return code. */
437 /* Return zero if there are no problems. */
438 return (vstate->stats.sawfailure);
441 void NCValidateFreeState(struct NCValidatorState **vstate) {
442 if (*vstate == NULL) return;
443 free((*vstate)->vttable);
444 free((*vstate)->kttable);
445 free(*vstate);
446 *vstate = NULL;
449 static void ValidateCallAlignment(const struct NCDecoderState *mstate) {
450 uint32_t fallthru = mstate->inst.vaddr + mstate->inst.length;
451 if (fallthru & mstate->vstate->alignmask) {
452 LogErrorInst(mstate, "Bad call alignment");
453 /* This makes bad call alignment a fatal error. */
454 Stats_BadAlignment(mstate->vstate);
458 static void ValidateJmp8(const struct NCDecoderState *mstate) {
459 uint8_t opcode = (uint8_t)mstate->inst.maddr[mstate->inst.prefixbytes];
460 int8_t offset = (int8_t)mstate->inst.maddr[mstate->inst.prefixbytes+1];
461 uint32_t target = mstate->inst.vaddr + mstate->inst.length + offset;
462 Stats_CheckTarget(mstate->vstate);
463 if ((opcode & 0xf0) == 0x70 || opcode == 0xeb ||
464 opcode == 0xe0 || opcode == 0xe1 || opcode == 0xe2 || opcode == 0xe3) {
465 RememberTP(mstate->inst.vaddr, target, mstate->vstate);
466 } else {
467 /* If this ever happens, it's probably a decoder bug. */
468 vprint(("ERROR: JMP8 %x: %x\n", mstate->inst.vaddr, opcode));
469 Stats_InternalError(mstate->vstate);
473 static void ValidateJmpz(const struct NCDecoderState *mstate) {
474 uint8_t *opcode = mstate->inst.maddr + mstate->inst.prefixbytes;
475 int32_t offset;
476 uint32_t target;
477 Stats_CheckTarget(mstate->vstate);
478 if (*opcode == 0xe8 || *opcode == 0xe9) {
479 offset = *(int32_t *)&opcode[1];
480 target = mstate->inst.vaddr + mstate->inst.length + offset;
481 RememberTP(mstate->inst.vaddr, target, mstate->vstate);
482 /* as a courtesy, check call alignment correctness */
483 if (*opcode == 0xe8) ValidateCallAlignment(mstate);
484 } else if (*opcode == 0x0f) {
485 if ((opcode[1] & 0xf0) == 0x80) {
486 offset = *(int32_t *)&opcode[2];
487 target = mstate->inst.vaddr + mstate->inst.length + offset;
488 RememberTP(mstate->inst.vaddr, target, mstate->vstate);
490 } else {
491 /* If this ever happens, it's probably a decoder bug. */
492 vprint(("ERROR: JMPZ %x: %x %x\n",
493 mstate->inst.vaddr, opcode[0], opcode[1]));
494 Stats_InternalError(mstate->vstate);
499 * The NaCl 14-byte safe indirect calling sequence looks like this:
500 * 81 e0 ff ff ff ff and $0xffffffff,%eax
501 * 81 c8 00 00 00 00 or $0x0,%eax
502 * ff d0 call *%eax
503 * The call may be replaced with a ff e0 jmp. Any register may
504 * be used, not just eax. The validator requires exactly this
505 * sequence.
506 * TODO: validate or write the masks.
508 #ifdef NACLJMP14
509 NOTE: This routine has not been kept up to date, and should be updated
510 with respect to the five-byte version (below) if we need to use it
511 again someday.
512 static void ValidateIndirect14(const struct NCDecoderState *mstate) {
513 uint8_t *jmpopcode;
514 uint8_t *oropcode;
515 uint8_t *andopcode;
516 uint8_t mrm;
517 uint8_t reg;
519 struct NCDecoderState *andinst = PreviousInst(mstate, -2);
520 struct NCDecoderState *orinst = PreviousInst(mstate, -1);
521 assert(andinst != NULL);
522 assert(orinst != NULL);
523 if ((andinst->inst.length == 0) || (orinst->inst.length == 0)) {
524 Stats_UnsafeIndirect(mstate->vstate);
525 return;
527 /* no prefix bytes allowed; checked below */
528 jmpopcode = mstate->inst.maddr;
529 oropcode = orinst->inst.maddr;
530 andopcode = andinst->inst.maddr;
531 mrm = jmpopcode[1];
532 reg = modrm_rm(mrm);
534 Stats_CheckTarget(mstate->vstate);
535 Stats_TargetIndirect(mstate->vstate);
536 do {
537 /* check no prefix bytes */
538 if (mstate->inst.prefixbytes != 0) break;
539 if (andinst->inst.prefixbytes != 0) break;
540 if (orinst->inst.prefixbytes != 0) break;
541 /* check all the opcodes. */
542 if (jmpopcode[0] != 0xff) break;
543 if ((modrm_reg(mrm) != 2) && (modrm_reg(mrm) != 4)) break;
544 /* Issue 32: disallow unsafe call/jump indirection */
545 /* example: ff 12 call (*edx) */
546 /* Reported by defend.the.world on 11 Dec 2008 */
547 if (modrm_mod(mrm) != 3) break;
548 if (oropcode[0] != 0x81) break;
549 if (andopcode[0] != 0x81) break;
550 /* check modrm bytes of or and and instructions */
551 if (andopcode[1] != (0xe0 | reg)) break;
552 if (oropcode[1] != (0xc8 | reg)) break;
553 /* check mask */
554 assert(0); /* not implemented yet, so don't use this routine! */
555 /* All checks look good. Make the sequence 'atomic.' */
556 ForgetIP(orinst->inst.vaddr, mstate->vstate);
557 ForgetIP(mstate->inst.vaddr, mstate->vstate);
558 return;
559 } while (0);
560 Stats_UnsafeIndirect(mstate->vstate);
562 #endif
565 * The NaCl five-byte safe indirect calling sequence looks like this:
566 * 83 e0 f0 and $0xfffffff0,%eax
567 * ff d0 call *%eax
568 * The call may be replaced with a ff e0 jmp. Any register may
569 * be used, not just eax. The validator requires exactly this
570 * sequence.
571 * TODO: validate or write the masks.
573 static void ValidateIndirect5(const struct NCDecoderState *mstate) {
574 uint8_t *jmpopcode;
575 uint8_t *andopcode;
576 uint8_t mrm;
577 uint8_t targetreg;
578 const uint8_t kReg_ESP = 4;
580 struct NCDecoderState *andinst = PreviousInst(mstate, -1);
581 assert(andinst != NULL);
582 if (andinst->inst.length == 0) {
583 Stats_UnsafeIndirect(mstate->vstate);
584 return;
586 jmpopcode = mstate->inst.maddr; /* note: no prefixbytes allowed */
587 andopcode = andinst->inst.maddr; /* note: no prefixbytes allowed */
588 mrm = jmpopcode[1];
589 targetreg = modrm_rm(mrm); /* Note that the modrm_rm field holds the */
590 /* target addr the modrm_reg is the opcode. */
592 Stats_CheckTarget(mstate->vstate);
593 Stats_TargetIndirect(mstate->vstate);
594 do {
595 /* no prefix bytes allowed */
596 if (mstate->inst.prefixbytes != 0) break;
597 if (andinst->inst.prefixbytes != 0) break;
598 /* Check all the opcodes. */
599 /* In GROUP5, 2 => call, 4 => jmp */
600 if (jmpopcode[0] != 0xff) break;
601 if ((modrm_reg(mrm) != 2) && (modrm_reg(mrm) != 4)) break;
602 /* Issue 32: disallow unsafe call/jump indirection */
603 /* example: ff 12 call (*edx) */
604 /* Reported by defend.the.world on 11 Dec 2008 */
605 if (modrm_mod(mrm) != 3) break;
606 if (targetreg == kReg_ESP) break;
607 if (andopcode[0] != 0x83) break;
608 /* check modrm bytes of or and and instructions */
609 if (andopcode[1] != (0xe0 | targetreg)) break;
610 /* check mask */
611 if (andopcode[2] != (0x0ff & ~mstate->vstate->alignmask)) break;
612 /* All checks look good. Make the sequence 'atomic.' */
613 ForgetIP(mstate->inst.vaddr, mstate->vstate);
614 /* as a courtesy, check call alignment correctness */
615 if (modrm_reg(mrm) == 2) ValidateCallAlignment(mstate);
616 return;
617 } while (0);
618 Stats_UnsafeIndirect(mstate->vstate);
619 LogErrorInst(mstate, "Unsafe indirect jump");
622 /* It appears to me that none of my favorite test programs use more */
623 /* than a single prefix byte on an instruction. It would be nice if */
624 /* we could make this a requirement. */
625 static const size_t kMaxValidInstLength = 11;
626 static const uint8_t kNaClFullStop = 0xf4; /* x86 HALT opcode */
628 void ValidateInst(const struct NCDecoderState *mstate) {
629 const int kMaxValPrefixBytes = 2;
630 CPUFeatures *cpufeatures;
631 int squashme = 0;
633 /* dprint(("ValidateInst(%x, %x) at %x\n",
634 (uint32_t)mstate, (uint32_t)mstate->vstate, mstate->inst.vaddr)); */
635 if (mstate == NULL) return;
636 if (mstate->vstate == NULL) return;
637 OpcodeHisto(mstate->inst.maddr[mstate->inst.prefixbytes],
638 mstate->vstate);
639 RememberIP(mstate->inst.vaddr, mstate->vstate);
640 cpufeatures = &(mstate->vstate->cpufeatures);
641 do {
642 if (mstate->inst.prefixbytes == 0) break;
643 if (mstate->inst.prefixbytes <= kMaxValPrefixBytes) {
644 if (mstate->inst.hasopbyte2) {
645 if (mstate->inst.prefixmask & kPrefixLOCK) {
646 /* For two byte opcodes, check for use of the lock prefix. */
647 if (mstate->opinfo->insttype == NACLi_386L) break;
648 if (mstate->opinfo->insttype == NACLi_CMPXCHG8B) break;
649 } else {
650 /* Other prefixes checks are encoded in the two-byte tables. */
651 break;
653 } else {
654 /* one byte opcode */
655 if ((mstate->inst.prefixmask &
656 BadPrefixMask[mstate->opinfo->insttype]) == 0) break;
659 //vprint(("VALIDATOR: BadPrefix at %08x, length %i\n", mstate->inst.vaddr,
660 // mstate->inst.prefixbytes));
661 LogErrorInst(mstate, "Bad prefix");
662 Stats_BadPrefix(mstate->vstate);
663 } while (0);
664 if ((size_t) (mstate->inst.length - mstate->inst.prefixbytes)
665 > kMaxValidInstLength) {
666 Stats_BadInstLength(mstate->vstate);
668 switch (mstate->opinfo->insttype) {
669 case NACLi_386:
670 case NACLi_386L:
671 case NACLi_386R:
672 case NACLi_386RE:
673 break;
674 case NACLi_JMP8:
675 ValidateJmp8(mstate);
676 break;
677 case NACLi_JMPZ:
678 ValidateJmpz(mstate);
679 break;
680 case NACLi_INDIRECT:
681 ValidateIndirect5(mstate);
682 break;
683 case NACLi_X87:
684 squashme = (!cpufeatures->f_x87);
685 break;
686 case NACLi_CFLUSH:
687 squashme = (!cpufeatures->f_CFLUSH);
688 break;
689 case NACLi_CMPXCHG8B:
690 squashme = (!cpufeatures->f_CX8);
691 break;
692 case NACLi_CMOV:
693 squashme = (!cpufeatures->f_CMOV);
694 break;
695 case NACLi_FCMOV:
696 squashme = (!(cpufeatures->f_CMOV && cpufeatures->f_x87));
697 break;
698 case NACLi_RDTSC:
699 squashme = (!cpufeatures->f_TSC);
700 break;
701 case NACLi_MMX:
702 squashme = (!cpufeatures->f_MMX);
703 break;
704 case NACLi_MMXSSE2:
705 /* Note: We accept these instructions if either MMX or SSE2 bits */
706 /* are set, in case MMX instructions go away someday... */
707 squashme = (!(cpufeatures->f_MMX || cpufeatures->f_SSE2));
708 break;
709 case NACLi_SSE:
710 squashme = (!cpufeatures->f_SSE);
711 break;
712 case NACLi_SSE2:
713 squashme = (!cpufeatures->f_SSE2);
714 break;
715 case NACLi_SSE3:
716 squashme = (!cpufeatures->f_SSE3);
717 break;
718 case NACLi_SSE4A:
719 squashme = (!cpufeatures->f_SSE4A);
720 break;
721 case NACLi_SSE41:
722 squashme = (!cpufeatures->f_SSE41);
723 break;
724 case NACLi_SSE42:
725 squashme = (!cpufeatures->f_SSE42);
726 break;
727 case NACLi_MOVBE:
728 squashme = (!cpufeatures->f_MOVBE);
729 break;
730 case NACLi_POPCNT:
731 squashme = (!cpufeatures->f_POPCNT);
732 break;
733 case NACLi_LZCNT:
734 squashme = (!cpufeatures->f_LZCNT);
735 break;
736 case NACLi_SSSE3:
737 squashme = (!cpufeatures->f_SSSE3);
738 break;
739 case NACLi_3DNOW:
740 squashme = (!cpufeatures->f_3DNOW);
741 break;
742 case NACLi_E3DNOW:
743 squashme = (!cpufeatures->f_E3DNOW);
744 break;
745 case NACLi_SSE2x:
746 /* This case requires CPUID checking code */
747 /* DATA16 prefix required */
748 if (!(mstate->inst.prefixmask & kPrefixDATA16)) {
749 Stats_BadPrefix(mstate->vstate);
751 squashme = (!cpufeatures->f_SSE2);
752 break;
754 case NACLi_RETURN:
755 Stats_Return(mstate->vstate);
756 /* ... and fall through to illegal instruction code */
757 case NACLi_EMMX:
758 /* EMMX needs to be supported someday but isn't ready yet. */
759 case NACLi_INVALID:
760 case NACLi_ILLEGAL:
761 case NACLi_SYSTEM:
762 case NACLi_RDMSR:
763 case NACLi_RDTSCP:
764 case NACLi_SYSCALL:
765 case NACLi_SYSENTER:
766 case NACLi_LONGMODE:
767 case NACLi_SVM:
768 case NACLi_OPINMRM:
769 case NACLi_3BYTE:
770 case NACLi_CMPXCHG16B:
772 /* uint8_t *opcode = mstate->inst.maddr + mstate->inst.prefixbytes; */
773 Stats_IllegalInst(mstate->vstate);
774 LogErrorInst(mstate, "Illegal instruction");
775 break;
777 case NACLi_UNDEFINED:
779 /* uint8_t *opcode = mstate->inst.maddr + mstate->inst.prefixbytes; */
780 Stats_IllegalInst(mstate->vstate);
781 Stats_InternalError(mstate->vstate);
782 LogErrorInst(mstate, "Undefined instruction");
783 break;
785 default:
786 ValidatePrintError(mstate->inst.vaddr, "Undefined instruction type");
787 Stats_InternalError(mstate->vstate);
788 break;
790 if (squashme) memset(mstate->inst.maddr, kNaClFullStop, mstate->inst.length);
793 void NCValidateSegment(uint8_t *mbase, uint32_t vbase, size_t sz,
794 struct NCValidatorState *vstate) {
795 if (sz == 0) {
796 Stats_MissingFullStop(vstate);
797 Stats_SegFault(vstate);
798 return;
800 GetCPUFeatures(&(vstate->cpufeatures));
801 /* The name of the flag is misleading; f_386 requires not just */
802 /* 386 instructions but also the CPUID instruction is supported. */
803 if (!vstate->cpufeatures.f_386) {
804 Stats_BadCPU(vstate);
805 return;
807 #if (0)
808 /* TODO: enable this check */
809 if (!vstate->cpufeatures.f_whitelisted) {
810 Stats_BadCPU(vstate);
811 return;
813 #endif
815 NCDecodeSegment(mbase, vbase, sz-1, vstate);
816 /* The check for a terminating hlt should only be necessary if the
817 end of the x86 code segment isn't 32-byte-aligned. */
818 if (mbase[sz-1] != kNaClFullStop && (sz % NACL_PAGESIZE) != 0) {
819 Stats_MissingFullStop(vstate);