Fix: $(HAMMER) -> scons
[nativeclient.git] / ncv / ncvalidate.c
blob81617abc85b10e9b45954bf500f192daef9d8558
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 /* opcode histogram */
65 #if VERBOSE == 1
66 static void OpcodeHisto(const uint8_t byte1, struct NCValidatorState *vstate) {
67 vstate->opcodehisto[byte1] += 1;
70 static void InitOpcodeHisto(struct NCValidatorState *vstate) {
71 int i;
72 for (i = 0; i < 256; i += 1) vstate->opcodehisto[i] = 0;
75 static void PrintOpcodeHisto(FILE *f, struct NCValidatorState *vstate) {
76 int i;
77 if (!VERBOSE) return;
78 fprintf(f, "\nOpcode Histogram;\n");
79 for (i = 0; i < 256; i += 4) {
80 if (vstate->opcodehisto[i] != 0) {
81 fprintf(f, "%d\t0x%02x\t%d\t0x%02x\t%d\t0x%02x\t%d\t0x%02x\n",
82 vstate->opcodehisto[i], i, vstate->opcodehisto[i+1], i+1,
83 vstate->opcodehisto[i+2], i+2, vstate->opcodehisto[i+3], i+3);
87 #else
88 #define OpcodeHisto(b, v)
89 #define InitOpcodeHisto(v)
90 #define PrintOpcodeHisto(f, v)
91 #endif /* VERBOSE == 1 */
93 /* statistics code */
94 static void Stats_Inst(struct NCValidatorState *vstate) {
95 vstate->stats.instructions += 1;
98 static void Stats_CheckTarget(struct NCValidatorState *vstate) {
99 vstate->stats.checktarget += 1;
102 static void Stats_TargetIndirect(struct NCValidatorState *vstate) {
103 vstate->stats.targetindirect += 1;
106 static void Stats_SawFailure(struct NCValidatorState *vstate) {
107 vstate->stats.sawfailure = 1;
110 static void Stats_InternalError(struct NCValidatorState *vstate) {
111 vstate->stats.internalerrors += 1;
112 Stats_SawFailure(vstate);
115 static void Stats_BadCPU(struct NCValidatorState *vstate) {
116 vstate->stats.badcpu += 1;
117 Stats_SawFailure(vstate);
120 static void Stats_BadAlignment(struct NCValidatorState *vstate) {
121 vstate->stats.badalignment += 1;
122 Stats_SawFailure(vstate);
125 static void Stats_SegFault(struct NCValidatorState *vstate) {
126 vstate->stats.segfaults += 1;
127 Stats_SawFailure(vstate);
130 static void Stats_NewSegment(struct NCValidatorState *vstate) {
131 vstate->stats.segments += 1;
132 if (vstate->stats.segments > 1) {
133 vprint(("error: multiple segments\n"));
134 Stats_SawFailure(vstate);
138 static void Stats_BadTarget(struct NCValidatorState *vstate) {
139 vstate->stats.badtarget += 1;
140 Stats_SawFailure(vstate);
143 static void Stats_UnsafeIndirect(struct NCValidatorState *vstate) {
144 vstate->stats.unsafeindirect += 1;
145 Stats_SawFailure(vstate);
148 static void Stats_MissingFullStop(struct NCValidatorState *vstate) {
149 vstate->stats.missingfullstop += 1;
150 Stats_SawFailure(vstate);
153 static void Stats_Return(struct NCValidatorState *vstate) {
154 vstate->stats.returns += 1;
155 Stats_UnsafeIndirect(vstate);
156 Stats_SawFailure(vstate);
159 static void Stats_IllegalInst(struct NCValidatorState *vstate) {
160 vstate->stats.illegalinst += 1;
161 Stats_SawFailure(vstate);
164 static void Stats_BadPrefix(struct NCValidatorState *vstate) {
165 vstate->stats.badprefix += 1;
166 Stats_SawFailure(vstate);
169 static void Stats_BadInstLength(struct NCValidatorState *vstate) {
170 vstate->stats.badinstlength += 1;
171 Stats_SawFailure(vstate);
174 static void Stats_Init(struct NCValidatorState *vstate) {
175 static int inited = 0;
176 if (inited) return;
178 vstate->stats.instructions = 0;
179 vstate->stats.segments = 0;
180 vstate->stats.checktarget = 0;
181 vstate->stats.targetindirect = 0;
182 vstate->stats.badtarget = 0;
183 vstate->stats.unsafeindirect = 0;
184 vstate->stats.returns = 0;
185 vstate->stats.illegalinst = 0;
186 vstate->stats.badalignment = 0;
187 vstate->stats.internalerrors = 0;
188 vstate->stats.badcpu = 0;
189 vstate->stats.missingfullstop = 0;
190 vstate->stats.badinstlength = 0;
191 vstate->stats.badprefix = 0;
192 vstate->stats.sawfailure = 0;
193 InitOpcodeHisto(vstate);
194 inited = 1;
197 void Stats_Print(FILE *f, struct NCValidatorState *vstate) {
198 if (!VERBOSE) return;
199 if (vstate == NULL) {
200 fprintf(f, "Analysis Summary: invalid module or internal failure\n");
201 return;
203 PrintOpcodeHisto(f, vstate);
204 fprintf(f, "Analysis Summary:\n");
205 fprintf(f, "%d Checked instructions\n", vstate->stats.instructions);
206 fprintf(f, "%d checked jump targets\n", vstate->stats.checktarget);
207 fprintf(f, "%d calls/jumps need dynamic checking (%0.2f%%)\n",
208 vstate->stats.targetindirect,
209 vstate->stats.instructions ?
210 100.0 * vstate->stats.targetindirect/vstate->stats.instructions : 0);
211 fprintf(f, "\nProblems:\n");
212 fprintf(f, "%d illegal instructions\n", vstate->stats.illegalinst);
213 fprintf(f, "%d bad jump targets\n", vstate->stats.badtarget);
214 fprintf(f, "%d illegal unprotected indirect jumps (including ret)\n",
215 vstate->stats.unsafeindirect);
216 fprintf(f, "%d instruction alignment defects\n",
217 vstate->stats.badalignment);
218 fprintf(f, "%d segmentation errors\n",
219 vstate->stats.segfaults);
220 fprintf(f, "%d bad prefix\n",
221 vstate->stats.badprefix);
222 fprintf(f, "%d bad instruction length\n",
223 vstate->stats.badinstlength);
224 fprintf(f, "%d missing full stop\n",
225 vstate->stats.missingfullstop);
226 fprintf(f, "%d internal errors\n",
227 vstate->stats.internalerrors);
228 fprintf(f, "%d bad cpu\n",
229 vstate->stats.badcpu);
232 /***********************************************************************/
233 /* jump target table */
234 static const uint8_t iadrmasks[8] = {0x01, 0x02, 0x04, 0x08,
235 0x10, 0x20, 0x40, 0x80};
236 #define IATOffset(__IA) ((__IA) >> 3)
237 #define IATMask(__IA) (iadrmasks[(__IA) & 0x7])
238 #define SetAdrTable(__IOFF, __TABLE) \
239 (__TABLE)[IATOffset(__IOFF)] |= IATMask(__IOFF)
240 #define ClearAdrTable(__IOFF, __TABLE) \
241 (__TABLE)[IATOffset(__IOFF)] &= ~(IATMask(__IOFF))
242 #define GetAdrTable(__IOFF, __TABLE) \
243 ((__TABLE)[IATOffset(__IOFF)] & IATMask(__IOFF))
245 /* forward declaration, for registration */
246 void ValidateInst(const struct NCDecoderState *mstate);
248 /* In general we are quite paranoid about what prefixes can */
249 /* be used and where. For one-byte opcodes, prefixes are */
250 /* restricted based on the NACLi_ type and the masks in */
251 /* BadPrefixMask. For two-byte opcodes, any */
252 /* prefix can be used, but they function more to define the */
253 /* opcode as opposed to modify it; hence there are separate */
254 /* tables in ncdecodetab.h for the four allowed prefix bytes. */
255 static uint32_t BadPrefixMask[kNaClInstTypeRange];
256 static void InitBadPrefixMask() {
257 int i;
259 for (i = 0; i < kNaClInstTypeRange; i++) {
260 BadPrefixMask[i] = 0xffffffff; /* all prefixes are bad */
262 BadPrefixMask[NACLi_386] = ~(kPrefixDATA16 | kPrefixSEGGS);
263 BadPrefixMask[NACLi_386L] = ~(kPrefixDATA16 | kPrefixLOCK);
264 BadPrefixMask[NACLi_386R] = ~(kPrefixDATA16 | kPrefixREP);
265 BadPrefixMask[NACLi_386RE] = ~(kPrefixDATA16 | kPrefixREP | kPrefixREPNE);
266 BadPrefixMask[NACLi_JMP8] = ~(kPrefixSEGCS | kPrefixSEGDS);
267 BadPrefixMask[NACLi_JMPZ] = ~(kPrefixSEGCS | kPrefixSEGDS);
268 BadPrefixMask[NACLi_CMPXCHG8B] = ~kPrefixLOCK;
272 * NCValidateInit: Initialize NaCl validator internal state
273 * Parameters:
274 * vbase: base virtual address for code segment
275 * vlimit: size in bytes of code segment
276 * alignment: 16 or 32, specifying alignment
277 * Returns:
278 * an initialized struct NCValidatorState * if everything is okay,
279 * else NULL
281 struct NCValidatorState *NCValidateInit(const uint32_t vbase,
282 const uint32_t vlimit,
283 const uint8_t alignment) {
284 uint32_t alignbase = vbase & (~alignment);
285 struct NCValidatorState *vstate;
287 dprint(("NCValidateInit(%08x, %08x, %08x)\n", vbase, vlimit, alignment));
288 InitBadPrefixMask();
289 do {
290 if (vlimit <= vbase) break;
291 if (alignment != 16 && alignment != 32) break;
292 dprint(("ncv_init(%x, %x)\n", vbase, vlimit));
293 vstate = (struct NCValidatorState *)calloc(1, sizeof(*vstate));
294 if (vstate == NULL) break;
295 vstate->iadrbase = alignbase;
296 vstate->iadrlimit = vlimit;
297 vstate->alignment = alignment;
298 vstate->alignmask = alignment-1;
299 vstate->vttable = (uint8_t *)calloc(IATOffset(vlimit - alignbase) + 1, 1);
300 vstate->kttable = (uint8_t *)calloc(IATOffset(vlimit - alignbase) + 1, 1);
301 if (vstate->vttable == NULL || vstate->kttable == NULL) break;
302 dprint((" allocated tables\n"));
303 Stats_Init(vstate);
304 NCDecodeRegisterCallbacks(ValidateInst, Stats_NewSegment,
305 Stats_SegFault, Stats_InternalError);
306 return vstate;
307 } while (0);
308 /* failure */
309 return NULL;
312 static void RememberIP(const uint32_t ip, struct NCValidatorState *vstate) {
313 uint32_t ioffset = ip - vstate->iadrbase;
314 if (ip < vstate->iadrbase || ip >= vstate->iadrlimit) {
315 vprint(("JUMP TARGET %08x out of range in RememberIP\n", ip));
316 Stats_BadTarget(vstate);
317 return;
319 if (GetAdrTable(ioffset, vstate->vttable)) {
320 vprint(("RememberIP: Saw inst at %08x twice\n", ip));
321 Stats_InternalError(vstate);
322 return;
324 Stats_Inst(vstate);
325 SetAdrTable(ioffset, vstate->vttable);
328 static void RememberTP(const uint32_t src, uint32_t target,
329 struct NCValidatorState *vstate) {
330 uint32_t ioffset = target - vstate->iadrbase;
332 do {
333 if (target < vstate->iadrlimit) {
334 if (target >= vstate->iadrbase) break;
336 * the trampolines need to be aligned 0mod32 regardless of the
337 * program's elf flags. This allows the same library to be used
338 * with both 16 and 32 byte aligned clients.
340 if (target >= vstate->iadrbase - NACL_TRAMPOLINE_SIZE
341 && ((target & (NACL_INSTR_BLOCK_SIZE-1)) == 0)) {
343 * TODO: once we fully support 16/32 alignment, remove this
344 * in favor of however we communicate the fixed block size.
346 /* this is an aligned target in the trampoline area; ignore */
347 /* vprint(("ignoring target %08x in trampoline\n", target)); */
348 return;
351 vprint(("%08x: JUMP TARGET %08x out of range\n", src, target));
352 Stats_BadTarget(vstate);
353 return;
354 } while (0);
355 SetAdrTable(ioffset, vstate->kttable);
358 static void ForgetIP(const uint32_t ip,
359 struct NCValidatorState *vstate) {
360 uint32_t ioffset = ip - vstate->iadrbase;
361 if (ip < vstate->iadrbase || ip >= vstate->iadrlimit) {
362 vprint(("JUMP TARGET %08x out of range in ForgetIP\n", ip));
363 Stats_BadTarget(vstate);
364 return;
366 ClearAdrTable(ioffset, vstate->vttable);
369 int NCValidateFinish(struct NCValidatorState *vstate) {
370 uint32_t offset;
371 if (vstate == NULL) {
372 vprint(("validator not initialized. Did you call ncvalidate_init()?\n"));
373 /* non-zero indicates failure */
374 return 1;
376 dprint(("CheckTargets: %x-%x\n", vstate->iadrbase, vstate->iadrlimit));
377 for (offset = 0;
378 offset < vstate->iadrlimit - vstate->iadrbase;
379 offset += 1) {
380 if (GetAdrTable(offset, vstate->kttable)) {
381 /* printf("CheckTarget %x\n", offset + iadrbase); */
382 Stats_CheckTarget(vstate);
383 if (!GetAdrTable(offset, vstate->vttable)) {
384 Stats_BadTarget(vstate);
385 vprint(("Bad jump target at %x\n", vstate->iadrbase + offset));
389 /* check basic block boundaries */
390 if (vstate->iadrbase & vstate->alignmask) {
391 vprint(("Bad base address alignment 0x%08x\n", vstate->iadrbase));
392 Stats_BadAlignment(vstate);
394 for (offset = 0; offset < vstate->iadrlimit - vstate->iadrbase;
395 offset += vstate->alignment) {
396 if (!GetAdrTable(offset, vstate->vttable)) {
397 vprint(("Bad basic block alignment at %08x\n",
398 vstate->iadrbase + offset));
399 Stats_BadAlignment(vstate);
403 /* Now that all the work is done, generate return code. */
404 /* Return zero if there are no problems. */
405 return (vstate->stats.sawfailure);
408 void NCValidateFreeState(struct NCValidatorState **vstate) {
409 if (*vstate == NULL) return;
410 free((*vstate)->vttable);
411 free((*vstate)->kttable);
412 free(*vstate);
413 *vstate = NULL;
416 static void ValidateCallAlignment(const struct NCDecoderState *mstate) {
417 uint32_t fallthru = mstate->inst.vaddr + mstate->inst.length;
418 if (fallthru & mstate->vstate->alignmask) {
419 printf("bad call alignment at %x\n", mstate->inst.vaddr);
420 /* This makes bad call alignment a fatal error. */
421 Stats_BadAlignment(mstate->vstate);
425 static void ValidateJmp8(const struct NCDecoderState *mstate) {
426 uint8_t opcode = (uint8_t)mstate->inst.maddr[mstate->inst.prefixbytes];
427 int8_t offset = (int8_t)mstate->inst.maddr[mstate->inst.prefixbytes+1];
428 uint32_t target = mstate->inst.vaddr + mstate->inst.length + offset;
429 Stats_CheckTarget(mstate->vstate);
430 if ((opcode & 0xf0) == 0x70 || opcode == 0xeb ||
431 opcode == 0xe0 || opcode == 0xe1 || opcode == 0xe2 || opcode == 0xe3) {
432 RememberTP(mstate->inst.vaddr, target, mstate->vstate);
433 } else {
434 /* If this ever happens, it's probably a decoder bug. */
435 vprint(("ERROR: JMP8 %x: %x\n", mstate->inst.vaddr, opcode));
436 Stats_InternalError(mstate->vstate);
440 static void ValidateJmpz(const struct NCDecoderState *mstate) {
441 uint8_t *opcode = mstate->inst.maddr + mstate->inst.prefixbytes;
442 int32_t offset;
443 uint32_t target;
444 Stats_CheckTarget(mstate->vstate);
445 if (*opcode == 0xe8 || *opcode == 0xe9) {
446 offset = *(int32_t *)&opcode[1];
447 target = mstate->inst.vaddr + mstate->inst.length + offset;
448 RememberTP(mstate->inst.vaddr, target, mstate->vstate);
449 /* as a courtesy, check call alignment correctness */
450 if (*opcode == 0xe8) ValidateCallAlignment(mstate);
451 } else if (*opcode == 0x0f) {
452 if ((opcode[1] & 0xf0) == 0x80) {
453 offset = *(int32_t *)&opcode[2];
454 target = mstate->inst.vaddr + mstate->inst.length + offset;
455 RememberTP(mstate->inst.vaddr, target, mstate->vstate);
457 } else {
458 /* If this ever happens, it's probably a decoder bug. */
459 vprint(("ERROR: JMPZ %x: %x %x\n",
460 mstate->inst.vaddr, opcode[0], opcode[1]));
461 Stats_InternalError(mstate->vstate);
466 * The NaCl 14-byte safe indirect calling sequence looks like this:
467 * 81 e0 ff ff ff ff and $0xffffffff,%eax
468 * 81 c8 00 00 00 00 or $0x0,%eax
469 * ff d0 call *%eax
470 * The call may be replaced with a ff e0 jmp. Any register may
471 * be used, not just eax. The validator requires exactly this
472 * sequence.
473 * TODO: validate or write the masks.
475 #ifdef NACLJMP14
476 NOTE: This routine has not been kept up to date, and should be updated
477 with respect to the five-byte version (below) if we need to use it
478 again someday.
479 static void ValidateIndirect14(const struct NCDecoderState *mstate) {
480 uint8_t *jmpopcode;
481 uint8_t *oropcode;
482 uint8_t *andopcode;
483 uint8_t mrm;
484 uint8_t reg;
486 struct NCDecoderState *andinst = PreviousInst(mstate, -2);
487 struct NCDecoderState *orinst = PreviousInst(mstate, -1);
488 assert(andinst != NULL);
489 assert(orinst != NULL);
490 if ((andinst->inst.length == 0) || (orinst->inst.length == 0)) {
491 Stats_UnsafeIndirect(mstate->vstate);
492 return;
494 /* no prefix bytes allowed; checked below */
495 jmpopcode = mstate->inst.maddr;
496 oropcode = orinst->inst.maddr;
497 andopcode = andinst->inst.maddr;
498 mrm = jmpopcode[1];
499 reg = modrm_rm(mrm);
501 Stats_CheckTarget(mstate->vstate);
502 Stats_TargetIndirect(mstate->vstate);
503 do {
504 /* check no prefix bytes */
505 if (mstate->inst.prefixbytes != 0) break;
506 if (andinst->inst.prefixbytes != 0) break;
507 if (orinst->inst.prefixbytes != 0) break;
508 /* check all the opcodes. */
509 if (jmpopcode[0] != 0xff) break;
510 if ((modrm_reg(mrm) != 2) && (modrm_reg(mrm) != 4)) break;
511 /* Issue 32: disallow unsafe call/jump indirection */
512 /* example: ff 12 call (*edx) */
513 /* Reported by defend.the.world on 11 Dec 2008 */
514 if (modrm_mod(mrm) != 3) break;
515 if (oropcode[0] != 0x81) break;
516 if (andopcode[0] != 0x81) break;
517 /* check modrm bytes of or and and instructions */
518 if (andopcode[1] != (0xe0 | reg)) break;
519 if (oropcode[1] != (0xc8 | reg)) break;
520 /* check mask */
521 assert(0); /* not implemented yet, so don't use this routine! */
522 /* All checks look good. Make the sequence 'atomic.' */
523 ForgetIP(orinst->inst.vaddr, mstate->vstate);
524 ForgetIP(mstate->inst.vaddr, mstate->vstate);
525 return;
526 } while (0);
527 Stats_UnsafeIndirect(mstate->vstate);
529 #endif
532 * The NaCl five-byte safe indirect calling sequence looks like this:
533 * 83 e0 f0 and $0xfffffff0,%eax
534 * ff d0 call *%eax
535 * The call may be replaced with a ff e0 jmp. Any register may
536 * be used, not just eax. The validator requires exactly this
537 * sequence.
538 * TODO: validate or write the masks.
540 static void ValidateIndirect5(const struct NCDecoderState *mstate) {
541 uint8_t *jmpopcode;
542 uint8_t *andopcode;
543 uint8_t mrm;
544 uint8_t targetreg;
545 const uint8_t kReg_ESP = 4;
547 struct NCDecoderState *andinst = PreviousInst(mstate, -1);
548 assert(andinst != NULL);
549 if (andinst->inst.length == 0) {
550 Stats_UnsafeIndirect(mstate->vstate);
551 return;
553 jmpopcode = mstate->inst.maddr; /* note: no prefixbytes allowed */
554 andopcode = andinst->inst.maddr; /* note: no prefixbytes allowed */
555 mrm = jmpopcode[1];
556 targetreg = modrm_rm(mrm); /* Note that the modrm_rm field holds the */
557 /* target addr the modrm_reg is the opcode. */
559 Stats_CheckTarget(mstate->vstate);
560 Stats_TargetIndirect(mstate->vstate);
561 do {
562 /* no prefix bytes allowed */
563 if (mstate->inst.prefixbytes != 0) break;
564 if (andinst->inst.prefixbytes != 0) break;
565 /* Check all the opcodes. */
566 /* In GROUP5, 2 => call, 4 => jmp */
567 if (jmpopcode[0] != 0xff) break;
568 if ((modrm_reg(mrm) != 2) && (modrm_reg(mrm) != 4)) break;
569 /* Issue 32: disallow unsafe call/jump indirection */
570 /* example: ff 12 call (*edx) */
571 /* Reported by defend.the.world on 11 Dec 2008 */
572 if (modrm_mod(mrm) != 3) break;
573 if (targetreg == kReg_ESP) break;
574 if (andopcode[0] != 0x83) break;
575 /* check modrm bytes of or and and instructions */
576 if (andopcode[1] != (0xe0 | targetreg)) break;
577 /* check mask */
578 if (andopcode[2] != (0x0ff & ~mstate->vstate->alignmask)) break;
579 /* All checks look good. Make the sequence 'atomic.' */
580 ForgetIP(mstate->inst.vaddr, mstate->vstate);
581 /* as a courtesy, check call alignment correctness */
582 if (modrm_reg(mrm) == 2) ValidateCallAlignment(mstate);
583 return;
584 } while (0);
585 Stats_UnsafeIndirect(mstate->vstate);
588 /* It appears to me that none of my favorite test programs use more */
589 /* than a single prefix byte on an instruction. It would be nice if */
590 /* we could make this a requirement. */
591 static const size_t kMaxValidPrefixBytes = 1;
592 static const size_t kMaxValidInstLength = 11;
593 static const uint8_t kNaClFullStop = 0xf4; /* x86 HALT opcode */
595 void ValidateInst(const struct NCDecoderState *mstate) {
596 /* NaCl allows at most 1 prefix byte per instruction */
597 const int kMaxValPrefixBytes = 1;
598 CPUFeatures *cpufeatures;
599 int squashme = 0;
601 /* dprint(("ValidateInst(%x, %x) at %x\n",
602 (uint32_t)mstate, (uint32_t)mstate->vstate, mstate->inst.vaddr)); */
603 if (mstate == NULL) return;
604 if (mstate->vstate == NULL) return;
605 OpcodeHisto(mstate->inst.maddr[mstate->inst.prefixbytes],
606 mstate->vstate);
607 RememberIP(mstate->inst.vaddr, mstate->vstate);
608 cpufeatures = &(mstate->vstate->cpufeatures);
609 do {
610 if (mstate->inst.prefixbytes == 0) break;
611 if (mstate->inst.prefixbytes <= kMaxValPrefixBytes) {
612 if (mstate->inst.hasopbyte2) {
613 if (mstate->inst.prefixmask & kPrefixLOCK) {
614 /* For two byte opcodes, check for use of the lock prefix. */
615 if (mstate->opinfo->insttype == NACLi_386L) break;
616 if (mstate->opinfo->insttype == NACLi_CMPXCHG8B) break;
617 } else {
618 /* Other prefixes checks are encoded in the two-byte tables. */
619 break;
621 } else {
622 /* one byte opcode */
623 if ((mstate->inst.prefixmask &
624 BadPrefixMask[mstate->opinfo->insttype]) == 0) break;
627 vprint(("BadPrefix at %08x\n", mstate->inst.vaddr));
628 Stats_BadPrefix(mstate->vstate);
629 } while (0);
630 if ((size_t) (mstate->inst.length - mstate->inst.prefixbytes)
631 > kMaxValidInstLength) {
632 Stats_BadInstLength(mstate->vstate);
634 switch (mstate->opinfo->insttype) {
635 case NACLi_386:
636 case NACLi_386L:
637 case NACLi_386R:
638 case NACLi_386RE:
639 break;
640 case NACLi_JMP8:
641 ValidateJmp8(mstate);
642 break;
643 case NACLi_JMPZ:
644 ValidateJmpz(mstate);
645 break;
646 case NACLi_INDIRECT:
647 ValidateIndirect5(mstate);
648 break;
649 case NACLi_X87:
650 squashme = (!cpufeatures->f_x87);
651 break;
652 case NACLi_CFLUSH:
653 squashme = (!cpufeatures->f_CFLUSH);
654 break;
655 case NACLi_CMPXCHG8B:
656 squashme = (!cpufeatures->f_CX8);
657 break;
658 case NACLi_CMOV:
659 squashme = (!cpufeatures->f_CMOV);
660 break;
661 case NACLi_FCMOV:
662 squashme = (!(cpufeatures->f_CMOV && cpufeatures->f_x87));
663 break;
664 case NACLi_RDTSC:
665 squashme = (!cpufeatures->f_TSC);
666 break;
667 case NACLi_MMX:
668 squashme = (!cpufeatures->f_MMX);
669 break;
670 case NACLi_MMXSSE2:
671 /* Note: We accept these instructions if either MMX or SSE2 bits */
672 /* are set, in case MMX instructions go away someday... */
673 squashme = (!(cpufeatures->f_MMX || cpufeatures->f_SSE2));
674 break;
675 case NACLi_SSE:
676 squashme = (!cpufeatures->f_SSE);
677 break;
678 case NACLi_SSE2:
679 squashme = (!cpufeatures->f_SSE2);
680 break;
681 case NACLi_SSE3:
682 squashme = (!cpufeatures->f_SSE3);
683 break;
684 case NACLi_SSE4A:
685 squashme = (!cpufeatures->f_SSE4A);
686 break;
687 case NACLi_POPCNT:
688 squashme = (!cpufeatures->f_POPCNT);
689 break;
690 case NACLi_LZCNT:
691 squashme = (!cpufeatures->f_LZCNT);
692 break;
693 case NACLi_SSSE3:
694 squashme = (!cpufeatures->f_SSSE3);
695 break;
696 case NACLi_3DNOW:
697 squashme = (!cpufeatures->f_3DNOW);
698 break;
699 case NACLi_E3DNOW:
700 squashme = (!cpufeatures->f_E3DNOW);
701 break;
702 case NACLi_SSE2x:
703 /* This case requires CPUID checking code */
704 /* DATA16 prefix required */
705 if (!(mstate->inst.prefixmask & kPrefixDATA16)) {
706 Stats_BadPrefix(mstate->vstate);
708 squashme = (!cpufeatures->f_SSE2);
709 break;
711 case NACLi_RETURN:
712 Stats_Return(mstate->vstate);
713 /* ... and fall through to illegal instruction code */
714 case NACLi_EMMX:
715 case NACLi_SSE41:
716 case NACLi_SSE42:
717 /* EMMX, SSE41 and SSE42 need to be supported someday but */
718 /* aren't ready yet */
719 case NACLi_INVALID:
720 case NACLi_ILLEGAL:
721 case NACLi_SYSTEM:
722 case NACLi_RDMSR:
723 case NACLi_RDTSCP:
724 case NACLi_SYSCALL:
725 case NACLi_SYSENTER:
726 case NACLi_LONGMODE:
727 case NACLi_SVM:
728 case NACLi_OPINMRM:
729 case NACLi_3BYTE:
730 case NACLi_CMPXCHG16B:
732 uint8_t *opcode = mstate->inst.maddr + mstate->inst.prefixbytes;
733 Stats_IllegalInst(mstate->vstate);
734 if (VERBOSE) {
735 printf("illegal inst at %x (%02x)\n", mstate->inst.vaddr, *opcode);
737 break;
739 case NACLi_UNDEFINED:
741 uint8_t *opcode = mstate->inst.maddr + mstate->inst.prefixbytes;
742 Stats_IllegalInst(mstate->vstate);
743 Stats_InternalError(mstate->vstate);
744 if (VERBOSE) {
745 printf("undefined inst at %x (%02x)\n", mstate->inst.vaddr, *opcode);
747 break;
749 /* Note that by omitting a default: case the compiler checks */
750 /* that all cases are covered. */
752 if (squashme) memset(mstate->inst.maddr, kNaClFullStop, mstate->inst.length);
755 void NCValidateSegment(uint8_t *mbase, uint32_t vbase, size_t sz,
756 struct NCValidatorState *vstate) {
757 if (sz == 0) {
758 Stats_MissingFullStop(vstate);
759 Stats_SegFault(vstate);
760 return;
762 GetCPUFeatures(&(vstate->cpufeatures));
763 /* The name of the flag is misleading; f_386 requires not just */
764 /* 386 instructions but also the CPUID instruction is supported. */
765 if (!vstate->cpufeatures.f_386) {
766 Stats_BadCPU(vstate);
767 return;
769 #if (0)
770 /* TODO: enable this check */
771 if (!vstate->cpufeatures.f_whitelisted) {
772 Stats_BadCPU(vstate);
773 return;
775 #endif
777 NCDecodeSegment(mbase, vbase, sz-1, vstate);
778 if (mbase[sz-1] != kNaClFullStop) {
779 Stats_MissingFullStop(vstate);