Remove check for ABIVERSION, so that I don't have to rebuild binutils when this is...
[nativeclient.git] / ncv / ncvalidate.c
blob5d7f912b64f0e1c043b2fa9998586f8f8eb49799
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 ValidateError(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 BadPrefixMask[NACLi_JMP8] = ~(kPrefixSEGCS | kPrefixSEGDS);
294 BadPrefixMask[NACLi_JMPZ] = ~(kPrefixSEGCS | kPrefixSEGDS);
295 BadPrefixMask[NACLi_CMPXCHG8B] = ~kPrefixLOCK;
299 * NCValidateInit: Initialize NaCl validator internal state
300 * Parameters:
301 * vbase: base virtual address for code segment
302 * vlimit: size in bytes of code segment
303 * alignment: 16 or 32, specifying alignment
304 * Returns:
305 * an initialized struct NCValidatorState * if everything is okay,
306 * else NULL
308 struct NCValidatorState *NCValidateInit(const uint32_t vbase,
309 const uint32_t vlimit,
310 const uint8_t alignment) {
311 uint32_t alignbase = vbase & (~alignment);
312 struct NCValidatorState *vstate;
314 dprint(("NCValidateInit(%08x, %08x, %08x)\n", vbase, vlimit, alignment));
315 InitBadPrefixMask();
316 do {
317 if (vlimit <= vbase) break;
318 if (alignment != 16 && alignment != 32) break;
319 dprint(("ncv_init(%x, %x)\n", vbase, vlimit));
320 vstate = (struct NCValidatorState *)calloc(1, sizeof(*vstate));
321 if (vstate == NULL) break;
322 vstate->iadrbase = alignbase;
323 vstate->iadrlimit = vlimit;
324 vstate->alignment = alignment;
325 vstate->alignmask = alignment-1;
326 vstate->vttable = (uint8_t *)calloc(IATOffset(vlimit - alignbase) + 1, 1);
327 vstate->kttable = (uint8_t *)calloc(IATOffset(vlimit - alignbase) + 1, 1);
328 if (vstate->vttable == NULL || vstate->kttable == NULL) break;
329 dprint((" allocated tables\n"));
330 Stats_Init(vstate);
331 NCDecodeRegisterCallbacks(ValidateInst, Stats_NewSegment,
332 Stats_SegFault, Stats_InternalError);
333 return vstate;
334 } while (0);
335 /* failure */
336 return NULL;
339 static void RememberIP(const uint32_t ip, struct NCValidatorState *vstate) {
340 uint32_t ioffset = ip - vstate->iadrbase;
341 if (ip < vstate->iadrbase || ip >= vstate->iadrlimit) {
342 ValidateError(ip, "JUMP TARGET out of range in RememberIP");
343 Stats_BadTarget(vstate);
344 return;
346 if (GetAdrTable(ioffset, vstate->vttable)) {
347 vprint(("RememberIP: Saw inst at %08x twice\n", ip));
348 Stats_InternalError(vstate);
349 return;
351 Stats_Inst(vstate);
352 SetAdrTable(ioffset, vstate->vttable);
355 static void RememberTP(const uint32_t src, uint32_t target,
356 struct NCValidatorState *vstate) {
357 uint32_t ioffset = target - vstate->iadrbase;
359 do {
360 if (target < vstate->iadrlimit) {
361 if (target >= vstate->iadrbase) break;
362 /* Aligned targets are always OK. */
363 if (target % NACL_INSTR_BLOCK_SIZE == 0)
364 return;
366 * the trampolines need to be aligned 0mod32 regardless of the
367 * program's elf flags. This allows the same library to be used
368 * with both 16 and 32 byte aligned clients.
370 if (target >= vstate->iadrbase - NACL_TRAMPOLINE_SIZE
371 && ((target & (NACL_INSTR_BLOCK_SIZE-1)) == 0)) {
373 * TODO: once we fully support 16/32 alignment, remove this
374 * in favor of however we communicate the fixed block size.
376 /* this is an aligned target in the trampoline area; ignore */
377 /* vprint(("ignoring target %08x in trampoline\n", target)); */
378 return;
381 //vprint(("VALIDATOR: %08x: JUMP TARGET %08x out of range\n", src, target));
382 LogError(vstate, src, "Jump target out of range");
383 Stats_BadTarget(vstate);
384 return;
385 } while (0);
386 SetAdrTable(ioffset, vstate->kttable);
389 static void ForgetIP(const uint32_t ip,
390 struct NCValidatorState *vstate) {
391 uint32_t ioffset = ip - vstate->iadrbase;
392 if (ip < vstate->iadrbase || ip >= vstate->iadrlimit) {
393 ValidateError(ip, "JUMP TARGET out of range in ForgetIP");
394 Stats_BadTarget(vstate);
395 return;
397 ClearAdrTable(ioffset, vstate->vttable);
400 int NCValidateFinish(struct NCValidatorState *vstate) {
401 uint32_t offset;
402 if (vstate == NULL) {
403 vprint(("validator not initialized. Did you call ncvalidate_init()?\n"));
404 /* non-zero indicates failure */
405 return 1;
407 dprint(("CheckTargets: %x-%x\n", vstate->iadrbase, vstate->iadrlimit));
408 for (offset = 0;
409 offset < vstate->iadrlimit - vstate->iadrbase;
410 offset += 1) {
411 if (GetAdrTable(offset, vstate->kttable)) {
412 /* printf("CheckTarget %x\n", offset + iadrbase); */
413 Stats_CheckTarget(vstate);
414 if (!GetAdrTable(offset, vstate->vttable)) {
415 Stats_BadTarget(vstate);
416 ValidateError(vstate->iadrbase + offset, "Bad jump target");
420 /* check basic block boundaries */
421 if (vstate->iadrbase & vstate->alignmask) {
422 ValidateError(vstate->iadrbase, "Bad base address alignment");
423 Stats_BadAlignment(vstate);
425 for (offset = 0; offset < vstate->iadrlimit - vstate->iadrbase;
426 offset += vstate->alignment) {
427 if (!GetAdrTable(offset, vstate->vttable)) {
428 ValidateError(vstate->iadrbase + offset, "Bad basic block alignent");
429 Stats_BadAlignment(vstate);
432 fflush(stdout);
434 /* Now that all the work is done, generate return code. */
435 /* Return zero if there are no problems. */
436 return (vstate->stats.sawfailure);
439 void NCValidateFreeState(struct NCValidatorState **vstate) {
440 if (*vstate == NULL) return;
441 free((*vstate)->vttable);
442 free((*vstate)->kttable);
443 free(*vstate);
444 *vstate = NULL;
447 static void ValidateCallAlignment(const struct NCDecoderState *mstate) {
448 uint32_t fallthru = mstate->inst.vaddr + mstate->inst.length;
449 if (fallthru & mstate->vstate->alignmask) {
450 LogErrorInst(mstate, "Bad call alignment");
451 /* This makes bad call alignment a fatal error. */
452 Stats_BadAlignment(mstate->vstate);
456 static void ValidateJmp8(const struct NCDecoderState *mstate) {
457 uint8_t opcode = (uint8_t)mstate->inst.maddr[mstate->inst.prefixbytes];
458 int8_t offset = (int8_t)mstate->inst.maddr[mstate->inst.prefixbytes+1];
459 uint32_t target = mstate->inst.vaddr + mstate->inst.length + offset;
460 Stats_CheckTarget(mstate->vstate);
461 if ((opcode & 0xf0) == 0x70 || opcode == 0xeb ||
462 opcode == 0xe0 || opcode == 0xe1 || opcode == 0xe2 || opcode == 0xe3) {
463 RememberTP(mstate->inst.vaddr, target, mstate->vstate);
464 } else {
465 /* If this ever happens, it's probably a decoder bug. */
466 vprint(("ERROR: JMP8 %x: %x\n", mstate->inst.vaddr, opcode));
467 Stats_InternalError(mstate->vstate);
471 static void ValidateJmpz(const struct NCDecoderState *mstate) {
472 uint8_t *opcode = mstate->inst.maddr + mstate->inst.prefixbytes;
473 int32_t offset;
474 uint32_t target;
475 Stats_CheckTarget(mstate->vstate);
476 if (*opcode == 0xe8 || *opcode == 0xe9) {
477 offset = *(int32_t *)&opcode[1];
478 target = mstate->inst.vaddr + mstate->inst.length + offset;
479 RememberTP(mstate->inst.vaddr, target, mstate->vstate);
480 /* as a courtesy, check call alignment correctness */
481 if (*opcode == 0xe8) ValidateCallAlignment(mstate);
482 } else if (*opcode == 0x0f) {
483 if ((opcode[1] & 0xf0) == 0x80) {
484 offset = *(int32_t *)&opcode[2];
485 target = mstate->inst.vaddr + mstate->inst.length + offset;
486 RememberTP(mstate->inst.vaddr, target, mstate->vstate);
488 } else {
489 /* If this ever happens, it's probably a decoder bug. */
490 vprint(("ERROR: JMPZ %x: %x %x\n",
491 mstate->inst.vaddr, opcode[0], opcode[1]));
492 Stats_InternalError(mstate->vstate);
497 * The NaCl 14-byte safe indirect calling sequence looks like this:
498 * 81 e0 ff ff ff ff and $0xffffffff,%eax
499 * 81 c8 00 00 00 00 or $0x0,%eax
500 * ff d0 call *%eax
501 * The call may be replaced with a ff e0 jmp. Any register may
502 * be used, not just eax. The validator requires exactly this
503 * sequence.
504 * TODO: validate or write the masks.
506 #ifdef NACLJMP14
507 NOTE: This routine has not been kept up to date, and should be updated
508 with respect to the five-byte version (below) if we need to use it
509 again someday.
510 static void ValidateIndirect14(const struct NCDecoderState *mstate) {
511 uint8_t *jmpopcode;
512 uint8_t *oropcode;
513 uint8_t *andopcode;
514 uint8_t mrm;
515 uint8_t reg;
517 struct NCDecoderState *andinst = PreviousInst(mstate, -2);
518 struct NCDecoderState *orinst = PreviousInst(mstate, -1);
519 assert(andinst != NULL);
520 assert(orinst != NULL);
521 if ((andinst->inst.length == 0) || (orinst->inst.length == 0)) {
522 Stats_UnsafeIndirect(mstate->vstate);
523 return;
525 /* no prefix bytes allowed; checked below */
526 jmpopcode = mstate->inst.maddr;
527 oropcode = orinst->inst.maddr;
528 andopcode = andinst->inst.maddr;
529 mrm = jmpopcode[1];
530 reg = modrm_rm(mrm);
532 Stats_CheckTarget(mstate->vstate);
533 Stats_TargetIndirect(mstate->vstate);
534 do {
535 /* check no prefix bytes */
536 if (mstate->inst.prefixbytes != 0) break;
537 if (andinst->inst.prefixbytes != 0) break;
538 if (orinst->inst.prefixbytes != 0) break;
539 /* check all the opcodes. */
540 if (jmpopcode[0] != 0xff) break;
541 if ((modrm_reg(mrm) != 2) && (modrm_reg(mrm) != 4)) break;
542 /* Issue 32: disallow unsafe call/jump indirection */
543 /* example: ff 12 call (*edx) */
544 /* Reported by defend.the.world on 11 Dec 2008 */
545 if (modrm_mod(mrm) != 3) break;
546 if (oropcode[0] != 0x81) break;
547 if (andopcode[0] != 0x81) break;
548 /* check modrm bytes of or and and instructions */
549 if (andopcode[1] != (0xe0 | reg)) break;
550 if (oropcode[1] != (0xc8 | reg)) break;
551 /* check mask */
552 assert(0); /* not implemented yet, so don't use this routine! */
553 /* All checks look good. Make the sequence 'atomic.' */
554 ForgetIP(orinst->inst.vaddr, mstate->vstate);
555 ForgetIP(mstate->inst.vaddr, mstate->vstate);
556 return;
557 } while (0);
558 Stats_UnsafeIndirect(mstate->vstate);
560 #endif
563 * The NaCl five-byte safe indirect calling sequence looks like this:
564 * 83 e0 f0 and $0xfffffff0,%eax
565 * ff d0 call *%eax
566 * The call may be replaced with a ff e0 jmp. Any register may
567 * be used, not just eax. The validator requires exactly this
568 * sequence.
569 * TODO: validate or write the masks.
571 static void ValidateIndirect5(const struct NCDecoderState *mstate) {
572 uint8_t *jmpopcode;
573 uint8_t *andopcode;
574 uint8_t mrm;
575 uint8_t targetreg;
576 const uint8_t kReg_ESP = 4;
578 struct NCDecoderState *andinst = PreviousInst(mstate, -1);
579 assert(andinst != NULL);
580 if (andinst->inst.length == 0) {
581 Stats_UnsafeIndirect(mstate->vstate);
582 return;
584 jmpopcode = mstate->inst.maddr; /* note: no prefixbytes allowed */
585 andopcode = andinst->inst.maddr; /* note: no prefixbytes allowed */
586 mrm = jmpopcode[1];
587 targetreg = modrm_rm(mrm); /* Note that the modrm_rm field holds the */
588 /* target addr the modrm_reg is the opcode. */
590 Stats_CheckTarget(mstate->vstate);
591 Stats_TargetIndirect(mstate->vstate);
592 do {
593 /* no prefix bytes allowed */
594 if (mstate->inst.prefixbytes != 0) break;
595 if (andinst->inst.prefixbytes != 0) break;
596 /* Check all the opcodes. */
597 /* In GROUP5, 2 => call, 4 => jmp */
598 if (jmpopcode[0] != 0xff) break;
599 if ((modrm_reg(mrm) != 2) && (modrm_reg(mrm) != 4)) break;
600 /* Issue 32: disallow unsafe call/jump indirection */
601 /* example: ff 12 call (*edx) */
602 /* Reported by defend.the.world on 11 Dec 2008 */
603 if (modrm_mod(mrm) != 3) break;
604 if (targetreg == kReg_ESP) break;
605 if (andopcode[0] != 0x83) break;
606 /* check modrm bytes of or and and instructions */
607 if (andopcode[1] != (0xe0 | targetreg)) break;
608 /* check mask */
609 if (andopcode[2] != (0x0ff & ~mstate->vstate->alignmask)) break;
610 /* All checks look good. Make the sequence 'atomic.' */
611 ForgetIP(mstate->inst.vaddr, mstate->vstate);
612 /* as a courtesy, check call alignment correctness */
613 if (modrm_reg(mrm) == 2) ValidateCallAlignment(mstate);
614 return;
615 } while (0);
616 Stats_UnsafeIndirect(mstate->vstate);
617 LogErrorInst(mstate, "Unsafe indirect jump");
620 /* It appears to me that none of my favorite test programs use more */
621 /* than a single prefix byte on an instruction. It would be nice if */
622 /* we could make this a requirement. */
623 static const size_t kMaxValidInstLength = 11;
624 static const uint8_t kNaClFullStop = 0xf4; /* x86 HALT opcode */
626 void ValidateInst(const struct NCDecoderState *mstate) {
627 const int kMaxValPrefixBytes = 2;
628 CPUFeatures *cpufeatures;
629 int squashme = 0;
631 /* dprint(("ValidateInst(%x, %x) at %x\n",
632 (uint32_t)mstate, (uint32_t)mstate->vstate, mstate->inst.vaddr)); */
633 if (mstate == NULL) return;
634 if (mstate->vstate == NULL) return;
635 OpcodeHisto(mstate->inst.maddr[mstate->inst.prefixbytes],
636 mstate->vstate);
637 RememberIP(mstate->inst.vaddr, mstate->vstate);
638 cpufeatures = &(mstate->vstate->cpufeatures);
639 do {
640 if (mstate->inst.prefixbytes == 0) break;
641 if (mstate->inst.prefixbytes <= kMaxValPrefixBytes) {
642 if (mstate->inst.hasopbyte2) {
643 if (mstate->inst.prefixmask & kPrefixLOCK) {
644 /* For two byte opcodes, check for use of the lock prefix. */
645 if (mstate->opinfo->insttype == NACLi_386L) break;
646 if (mstate->opinfo->insttype == NACLi_CMPXCHG8B) break;
647 } else {
648 /* Other prefixes checks are encoded in the two-byte tables. */
649 break;
651 } else {
652 /* one byte opcode */
653 if ((mstate->inst.prefixmask &
654 BadPrefixMask[mstate->opinfo->insttype]) == 0) break;
657 //vprint(("VALIDATOR: BadPrefix at %08x, length %i\n", mstate->inst.vaddr,
658 // mstate->inst.prefixbytes));
659 LogErrorInst(mstate, "Bad prefix");
660 Stats_BadPrefix(mstate->vstate);
661 } while (0);
662 if ((size_t) (mstate->inst.length - mstate->inst.prefixbytes)
663 > kMaxValidInstLength) {
664 Stats_BadInstLength(mstate->vstate);
666 switch (mstate->opinfo->insttype) {
667 case NACLi_386:
668 case NACLi_386L:
669 case NACLi_386R:
670 case NACLi_386RE:
671 break;
672 case NACLi_JMP8:
673 ValidateJmp8(mstate);
674 break;
675 case NACLi_JMPZ:
676 ValidateJmpz(mstate);
677 break;
678 case NACLi_INDIRECT:
679 ValidateIndirect5(mstate);
680 break;
681 case NACLi_X87:
682 squashme = (!cpufeatures->f_x87);
683 break;
684 case NACLi_CFLUSH:
685 squashme = (!cpufeatures->f_CFLUSH);
686 break;
687 case NACLi_CMPXCHG8B:
688 squashme = (!cpufeatures->f_CX8);
689 break;
690 case NACLi_CMOV:
691 squashme = (!cpufeatures->f_CMOV);
692 break;
693 case NACLi_FCMOV:
694 squashme = (!(cpufeatures->f_CMOV && cpufeatures->f_x87));
695 break;
696 case NACLi_RDTSC:
697 squashme = (!cpufeatures->f_TSC);
698 break;
699 case NACLi_MMX:
700 squashme = (!cpufeatures->f_MMX);
701 break;
702 case NACLi_MMXSSE2:
703 /* Note: We accept these instructions if either MMX or SSE2 bits */
704 /* are set, in case MMX instructions go away someday... */
705 squashme = (!(cpufeatures->f_MMX || cpufeatures->f_SSE2));
706 break;
707 case NACLi_SSE:
708 squashme = (!cpufeatures->f_SSE);
709 break;
710 case NACLi_SSE2:
711 squashme = (!cpufeatures->f_SSE2);
712 break;
713 case NACLi_SSE3:
714 squashme = (!cpufeatures->f_SSE3);
715 break;
716 case NACLi_SSE4A:
717 squashme = (!cpufeatures->f_SSE4A);
718 break;
719 case NACLi_SSE41:
720 squashme = (!cpufeatures->f_SSE41);
721 break;
722 case NACLi_SSE42:
723 squashme = (!cpufeatures->f_SSE42);
724 break;
725 case NACLi_MOVBE:
726 squashme = (!cpufeatures->f_MOVBE);
727 break;
728 case NACLi_POPCNT:
729 squashme = (!cpufeatures->f_POPCNT);
730 break;
731 case NACLi_LZCNT:
732 squashme = (!cpufeatures->f_LZCNT);
733 break;
734 case NACLi_SSSE3:
735 squashme = (!cpufeatures->f_SSSE3);
736 break;
737 case NACLi_3DNOW:
738 squashme = (!cpufeatures->f_3DNOW);
739 break;
740 case NACLi_E3DNOW:
741 squashme = (!cpufeatures->f_E3DNOW);
742 break;
743 case NACLi_SSE2x:
744 /* This case requires CPUID checking code */
745 /* DATA16 prefix required */
746 if (!(mstate->inst.prefixmask & kPrefixDATA16)) {
747 Stats_BadPrefix(mstate->vstate);
749 squashme = (!cpufeatures->f_SSE2);
750 break;
752 case NACLi_RETURN:
753 Stats_Return(mstate->vstate);
754 /* ... and fall through to illegal instruction code */
755 case NACLi_EMMX:
756 /* EMMX needs to be supported someday but isn't ready yet. */
757 case NACLi_INVALID:
758 case NACLi_ILLEGAL:
759 case NACLi_SYSTEM:
760 case NACLi_RDMSR:
761 case NACLi_RDTSCP:
762 case NACLi_SYSCALL:
763 case NACLi_SYSENTER:
764 case NACLi_LONGMODE:
765 case NACLi_SVM:
766 case NACLi_OPINMRM:
767 case NACLi_3BYTE:
768 case NACLi_CMPXCHG16B:
770 uint8_t *opcode = mstate->inst.maddr + mstate->inst.prefixbytes;
771 Stats_IllegalInst(mstate->vstate);
772 if (VERBOSE) {
773 //printf("VALIDATOR: illegal inst at %x (%02x)\n", mstate->inst.vaddr, *opcode);
774 LogErrorInst(mstate, "Illegal instruction");
776 break;
778 case NACLi_UNDEFINED:
780 uint8_t *opcode = mstate->inst.maddr + mstate->inst.prefixbytes;
781 Stats_IllegalInst(mstate->vstate);
782 Stats_InternalError(mstate->vstate);
783 if (VERBOSE) {
784 //printf("VALIDATOR: undefined inst at %x (%02x)\n", mstate->inst.vaddr, *opcode);
785 LogErrorInst(mstate, "Undefined instruction");
787 break;
789 /* Note that by omitting a default: case the compiler checks */
790 /* that all cases are covered. */
792 /* Disable this for now because we are mmapping code read-only. */
793 #if 0
794 if (squashme) memset(mstate->inst.maddr, kNaClFullStop, mstate->inst.length);
795 #endif
798 void NCValidateSegment(uint8_t *mbase, uint32_t vbase, size_t sz,
799 struct NCValidatorState *vstate) {
800 if (sz == 0) {
801 Stats_MissingFullStop(vstate);
802 Stats_SegFault(vstate);
803 return;
805 GetCPUFeatures(&(vstate->cpufeatures));
806 /* The name of the flag is misleading; f_386 requires not just */
807 /* 386 instructions but also the CPUID instruction is supported. */
808 if (!vstate->cpufeatures.f_386) {
809 Stats_BadCPU(vstate);
810 return;
812 #if (0)
813 /* TODO: enable this check */
814 if (!vstate->cpufeatures.f_whitelisted) {
815 Stats_BadCPU(vstate);
816 return;
818 #endif
820 NCDecodeSegment(mbase, vbase, sz-1, vstate);
821 /* The check for a terminating hlt should only be necessary if the
822 end of the x86 code segment isn't 32-byte-aligned. */
823 if (mbase[sz-1] != kNaClFullStop && (sz % NACL_PAGESIZE) != 0) {
824 Stats_MissingFullStop(vstate);