2 * Copyright 2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
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
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.
34 * Validate x86 instructions for Native Client
37 #include "native_client/include/portability.h"
44 #include "ncvalidate_internaltypes.h"
45 #include "nacl_cpuid.h"
46 #include "native_client/service_runtime/sel_ldr.h"
51 #define dprint(args) printf args
54 #endif /* DEBUGGING */
56 /* TODO verbosity needs to be controllable via commandline flags */
59 #define vprint(args) printf args
64 /* opcode histogram */
66 static void OpcodeHisto(const uint8_t byte1
, struct NCValidatorState
*vstate
) {
67 vstate
->opcodehisto
[byte1
] += 1;
70 static void InitOpcodeHisto(struct NCValidatorState
*vstate
) {
72 for (i
= 0; i
< 256; i
+= 1) vstate
->opcodehisto
[i
] = 0;
75 static void PrintOpcodeHisto(FILE *f
, struct NCValidatorState
*vstate
) {
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);
88 #define OpcodeHisto(b, v)
89 #define InitOpcodeHisto(v)
90 #define PrintOpcodeHisto(f, v)
91 #endif /* VERBOSE == 1 */
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;
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
);
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");
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() {
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
274 * vbase: base virtual address for code segment
275 * vlimit: size in bytes of code segment
276 * alignment: 16 or 32, specifying alignment
278 * an initialized struct NCValidatorState * if everything is okay,
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
));
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"));
304 NCDecodeRegisterCallbacks(ValidateInst
, Stats_NewSegment
,
305 Stats_SegFault
, Stats_InternalError
);
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
);
319 if (GetAdrTable(ioffset
, vstate
->vttable
)) {
320 vprint(("RememberIP: Saw inst at %08x twice\n", ip
));
321 Stats_InternalError(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
;
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)); */
351 vprint(("%08x: JUMP TARGET %08x out of range\n", src
, target
));
352 Stats_BadTarget(vstate
);
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
);
366 ClearAdrTable(ioffset
, vstate
->vttable
);
369 int NCValidateFinish(struct NCValidatorState
*vstate
) {
371 if (vstate
== NULL
) {
372 vprint(("validator not initialized. Did you call ncvalidate_init()?\n"));
373 /* non-zero indicates failure */
376 dprint(("CheckTargets: %x-%x\n", vstate
->iadrbase
, vstate
->iadrlimit
));
378 offset
< vstate
->iadrlimit
- vstate
->iadrbase
;
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
);
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
);
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
;
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
);
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
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
473 * TODO: validate or write the masks.
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
479 static void ValidateIndirect14(const struct NCDecoderState
*mstate
) {
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
);
494 /* no prefix bytes allowed; checked below */
495 jmpopcode
= mstate
->inst
.maddr
;
496 oropcode
= orinst
->inst
.maddr
;
497 andopcode
= andinst
->inst
.maddr
;
501 Stats_CheckTarget(mstate
->vstate
);
502 Stats_TargetIndirect(mstate
->vstate
);
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;
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
);
527 Stats_UnsafeIndirect(mstate
->vstate
);
532 * The NaCl five-byte safe indirect calling sequence looks like this:
533 * 83 e0 f0 and $0xfffffff0,%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
538 * TODO: validate or write the masks.
540 static void ValidateIndirect5(const struct NCDecoderState
*mstate
) {
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
);
553 jmpopcode
= mstate
->inst
.maddr
; /* note: no prefixbytes allowed */
554 andopcode
= andinst
->inst
.maddr
; /* note: no prefixbytes allowed */
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
);
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;
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
);
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
;
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
],
607 RememberIP(mstate
->inst
.vaddr
, mstate
->vstate
);
608 cpufeatures
= &(mstate
->vstate
->cpufeatures
);
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;
618 /* Other prefixes checks are encoded in the two-byte tables. */
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
);
630 if ((size_t) (mstate
->inst
.length
- mstate
->inst
.prefixbytes
)
631 > kMaxValidInstLength
) {
632 Stats_BadInstLength(mstate
->vstate
);
634 switch (mstate
->opinfo
->insttype
) {
641 ValidateJmp8(mstate
);
644 ValidateJmpz(mstate
);
647 ValidateIndirect5(mstate
);
650 squashme
= (!cpufeatures
->f_x87
);
653 squashme
= (!cpufeatures
->f_CFLUSH
);
655 case NACLi_CMPXCHG8B
:
656 squashme
= (!cpufeatures
->f_CX8
);
659 squashme
= (!cpufeatures
->f_CMOV
);
662 squashme
= (!(cpufeatures
->f_CMOV
&& cpufeatures
->f_x87
));
665 squashme
= (!cpufeatures
->f_TSC
);
668 squashme
= (!cpufeatures
->f_MMX
);
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
));
676 squashme
= (!cpufeatures
->f_SSE
);
679 squashme
= (!cpufeatures
->f_SSE2
);
682 squashme
= (!cpufeatures
->f_SSE3
);
685 squashme
= (!cpufeatures
->f_SSE4A
);
688 squashme
= (!cpufeatures
->f_POPCNT
);
691 squashme
= (!cpufeatures
->f_LZCNT
);
694 squashme
= (!cpufeatures
->f_SSSE3
);
697 squashme
= (!cpufeatures
->f_3DNOW
);
700 squashme
= (!cpufeatures
->f_E3DNOW
);
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
);
712 Stats_Return(mstate
->vstate
);
713 /* ... and fall through to illegal instruction code */
717 /* EMMX, SSE41 and SSE42 need to be supported someday but */
718 /* aren't ready yet */
730 case NACLi_CMPXCHG16B
:
732 uint8_t *opcode
= mstate
->inst
.maddr
+ mstate
->inst
.prefixbytes
;
733 Stats_IllegalInst(mstate
->vstate
);
735 printf("illegal inst at %x (%02x)\n", mstate
->inst
.vaddr
, *opcode
);
739 case NACLi_UNDEFINED
:
741 uint8_t *opcode
= mstate
->inst
.maddr
+ mstate
->inst
.prefixbytes
;
742 Stats_IllegalInst(mstate
->vstate
);
743 Stats_InternalError(mstate
->vstate
);
745 printf("undefined inst at %x (%02x)\n", mstate
->inst
.vaddr
, *opcode
);
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
) {
758 Stats_MissingFullStop(vstate
);
759 Stats_SegFault(vstate
);
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
);
770 /* TODO: enable this check */
771 if (!vstate
->cpufeatures
.f_whitelisted
) {
772 Stats_BadCPU(vstate
);
777 NCDecodeSegment(mbase
, vbase
, sz
-1, vstate
);
778 if (mbase
[sz
-1] != kNaClFullStop
) {
779 Stats_MissingFullStop(vstate
);