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
| kPrefixSEGGS
| 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(("VALIDATOR: 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(("VALIDATOR: %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(("VALIDATOR: 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(("VALIDATOR: Bad jump target at %x\n", vstate
->iadrbase
+ offset
));
389 /* check basic block boundaries */
390 if (vstate
->iadrbase
& vstate
->alignmask
) {
391 vprint(("VALIDATOR: 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(("VALIDATOR: Bad basic block alignment at %08x\n",
398 vstate
->iadrbase
+ offset
));
399 Stats_BadAlignment(vstate
);
404 /* Now that all the work is done, generate return code. */
405 /* Return zero if there are no problems. */
406 return (vstate
->stats
.sawfailure
);
409 void NCValidateFreeState(struct NCValidatorState
**vstate
) {
410 if (*vstate
== NULL
) return;
411 free((*vstate
)->vttable
);
412 free((*vstate
)->kttable
);
417 static void ValidateCallAlignment(const struct NCDecoderState
*mstate
) {
418 uint32_t fallthru
= mstate
->inst
.vaddr
+ mstate
->inst
.length
;
419 if (fallthru
& mstate
->vstate
->alignmask
) {
420 printf("VALIDATOR: bad call alignment at %x\n", mstate
->inst
.vaddr
);
421 /* This makes bad call alignment a fatal error. */
422 Stats_BadAlignment(mstate
->vstate
);
426 static void ValidateJmp8(const struct NCDecoderState
*mstate
) {
427 uint8_t opcode
= (uint8_t)mstate
->inst
.maddr
[mstate
->inst
.prefixbytes
];
428 int8_t offset
= (int8_t)mstate
->inst
.maddr
[mstate
->inst
.prefixbytes
+1];
429 uint32_t target
= mstate
->inst
.vaddr
+ mstate
->inst
.length
+ offset
;
430 Stats_CheckTarget(mstate
->vstate
);
431 if ((opcode
& 0xf0) == 0x70 || opcode
== 0xeb ||
432 opcode
== 0xe0 || opcode
== 0xe1 || opcode
== 0xe2 || opcode
== 0xe3) {
433 RememberTP(mstate
->inst
.vaddr
, target
, mstate
->vstate
);
435 /* If this ever happens, it's probably a decoder bug. */
436 vprint(("ERROR: JMP8 %x: %x\n", mstate
->inst
.vaddr
, opcode
));
437 Stats_InternalError(mstate
->vstate
);
441 static void ValidateJmpz(const struct NCDecoderState
*mstate
) {
442 uint8_t *opcode
= mstate
->inst
.maddr
+ mstate
->inst
.prefixbytes
;
445 Stats_CheckTarget(mstate
->vstate
);
446 if (*opcode
== 0xe8 || *opcode
== 0xe9) {
447 offset
= *(int32_t *)&opcode
[1];
448 target
= mstate
->inst
.vaddr
+ mstate
->inst
.length
+ offset
;
449 RememberTP(mstate
->inst
.vaddr
, target
, mstate
->vstate
);
450 /* as a courtesy, check call alignment correctness */
451 if (*opcode
== 0xe8) ValidateCallAlignment(mstate
);
452 } else if (*opcode
== 0x0f) {
453 if ((opcode
[1] & 0xf0) == 0x80) {
454 offset
= *(int32_t *)&opcode
[2];
455 target
= mstate
->inst
.vaddr
+ mstate
->inst
.length
+ offset
;
456 RememberTP(mstate
->inst
.vaddr
, target
, mstate
->vstate
);
459 /* If this ever happens, it's probably a decoder bug. */
460 vprint(("ERROR: JMPZ %x: %x %x\n",
461 mstate
->inst
.vaddr
, opcode
[0], opcode
[1]));
462 Stats_InternalError(mstate
->vstate
);
467 * The NaCl 14-byte safe indirect calling sequence looks like this:
468 * 81 e0 ff ff ff ff and $0xffffffff,%eax
469 * 81 c8 00 00 00 00 or $0x0,%eax
471 * The call may be replaced with a ff e0 jmp. Any register may
472 * be used, not just eax. The validator requires exactly this
474 * TODO: validate or write the masks.
477 NOTE
: This routine has
not been kept up to date
, and should be updated
478 with respect to the five
-byte
version (below
) if we need to use it
480 static void ValidateIndirect14(const struct NCDecoderState
*mstate
) {
487 struct NCDecoderState
*andinst
= PreviousInst(mstate
, -2);
488 struct NCDecoderState
*orinst
= PreviousInst(mstate
, -1);
489 assert(andinst
!= NULL
);
490 assert(orinst
!= NULL
);
491 if ((andinst
->inst
.length
== 0) || (orinst
->inst
.length
== 0)) {
492 Stats_UnsafeIndirect(mstate
->vstate
);
495 /* no prefix bytes allowed; checked below */
496 jmpopcode
= mstate
->inst
.maddr
;
497 oropcode
= orinst
->inst
.maddr
;
498 andopcode
= andinst
->inst
.maddr
;
502 Stats_CheckTarget(mstate
->vstate
);
503 Stats_TargetIndirect(mstate
->vstate
);
505 /* check no prefix bytes */
506 if (mstate
->inst
.prefixbytes
!= 0) break;
507 if (andinst
->inst
.prefixbytes
!= 0) break;
508 if (orinst
->inst
.prefixbytes
!= 0) break;
509 /* check all the opcodes. */
510 if (jmpopcode
[0] != 0xff) break;
511 if ((modrm_reg(mrm
) != 2) && (modrm_reg(mrm
) != 4)) break;
512 /* Issue 32: disallow unsafe call/jump indirection */
513 /* example: ff 12 call (*edx) */
514 /* Reported by defend.the.world on 11 Dec 2008 */
515 if (modrm_mod(mrm
) != 3) break;
516 if (oropcode
[0] != 0x81) break;
517 if (andopcode
[0] != 0x81) break;
518 /* check modrm bytes of or and and instructions */
519 if (andopcode
[1] != (0xe0 | reg
)) break;
520 if (oropcode
[1] != (0xc8 | reg
)) break;
522 assert(0); /* not implemented yet, so don't use this routine! */
523 /* All checks look good. Make the sequence 'atomic.' */
524 ForgetIP(orinst
->inst
.vaddr
, mstate
->vstate
);
525 ForgetIP(mstate
->inst
.vaddr
, mstate
->vstate
);
528 Stats_UnsafeIndirect(mstate
->vstate
);
533 * The NaCl five-byte safe indirect calling sequence looks like this:
534 * 83 e0 f0 and $0xfffffff0,%eax
536 * The call may be replaced with a ff e0 jmp. Any register may
537 * be used, not just eax. The validator requires exactly this
539 * TODO: validate or write the masks.
541 static void ValidateIndirect5(const struct NCDecoderState
*mstate
) {
546 const uint8_t kReg_ESP
= 4;
548 struct NCDecoderState
*andinst
= PreviousInst(mstate
, -1);
549 assert(andinst
!= NULL
);
550 if (andinst
->inst
.length
== 0) {
551 Stats_UnsafeIndirect(mstate
->vstate
);
554 jmpopcode
= mstate
->inst
.maddr
; /* note: no prefixbytes allowed */
555 andopcode
= andinst
->inst
.maddr
; /* note: no prefixbytes allowed */
557 targetreg
= modrm_rm(mrm
); /* Note that the modrm_rm field holds the */
558 /* target addr the modrm_reg is the opcode. */
560 Stats_CheckTarget(mstate
->vstate
);
561 Stats_TargetIndirect(mstate
->vstate
);
563 /* no prefix bytes allowed */
564 if (mstate
->inst
.prefixbytes
!= 0) break;
565 if (andinst
->inst
.prefixbytes
!= 0) break;
566 /* Check all the opcodes. */
567 /* In GROUP5, 2 => call, 4 => jmp */
568 if (jmpopcode
[0] != 0xff) break;
569 if ((modrm_reg(mrm
) != 2) && (modrm_reg(mrm
) != 4)) break;
570 /* Issue 32: disallow unsafe call/jump indirection */
571 /* example: ff 12 call (*edx) */
572 /* Reported by defend.the.world on 11 Dec 2008 */
573 if (modrm_mod(mrm
) != 3) break;
574 if (targetreg
== kReg_ESP
) break;
575 if (andopcode
[0] != 0x83) break;
576 /* check modrm bytes of or and and instructions */
577 if (andopcode
[1] != (0xe0 | targetreg
)) break;
579 if (andopcode
[2] != (0x0ff & ~mstate
->vstate
->alignmask
)) break;
580 /* All checks look good. Make the sequence 'atomic.' */
581 ForgetIP(mstate
->inst
.vaddr
, mstate
->vstate
);
582 /* as a courtesy, check call alignment correctness */
583 if (modrm_reg(mrm
) == 2) ValidateCallAlignment(mstate
);
586 Stats_UnsafeIndirect(mstate
->vstate
);
587 vprint(("VALIDATOR: %08x: unsafe indirect\n", mstate
->inst
.vaddr
));
590 /* It appears to me that none of my favorite test programs use more */
591 /* than a single prefix byte on an instruction. It would be nice if */
592 /* we could make this a requirement. */
593 static const size_t kMaxValidInstLength
= 11;
594 static const uint8_t kNaClFullStop
= 0xf4; /* x86 HALT opcode */
596 void ValidateInst(const struct NCDecoderState
*mstate
) {
597 const int kMaxValPrefixBytes
= 2;
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(("VALIDATOR: BadPrefix at %08x, length %i\n", mstate
->inst
.vaddr
,
628 mstate
->inst
.prefixbytes
));
629 Stats_BadPrefix(mstate
->vstate
);
631 if ((size_t) (mstate
->inst
.length
- mstate
->inst
.prefixbytes
)
632 > kMaxValidInstLength
) {
633 Stats_BadInstLength(mstate
->vstate
);
635 switch (mstate
->opinfo
->insttype
) {
642 ValidateJmp8(mstate
);
645 ValidateJmpz(mstate
);
648 ValidateIndirect5(mstate
);
651 squashme
= (!cpufeatures
->f_x87
);
654 squashme
= (!cpufeatures
->f_CFLUSH
);
656 case NACLi_CMPXCHG8B
:
657 squashme
= (!cpufeatures
->f_CX8
);
660 squashme
= (!cpufeatures
->f_CMOV
);
663 squashme
= (!(cpufeatures
->f_CMOV
&& cpufeatures
->f_x87
));
666 squashme
= (!cpufeatures
->f_TSC
);
669 squashme
= (!cpufeatures
->f_MMX
);
672 /* Note: We accept these instructions if either MMX or SSE2 bits */
673 /* are set, in case MMX instructions go away someday... */
674 squashme
= (!(cpufeatures
->f_MMX
|| cpufeatures
->f_SSE2
));
677 squashme
= (!cpufeatures
->f_SSE
);
680 squashme
= (!cpufeatures
->f_SSE2
);
683 squashme
= (!cpufeatures
->f_SSE3
);
686 squashme
= (!cpufeatures
->f_SSE4A
);
689 squashme
= (!cpufeatures
->f_POPCNT
);
692 squashme
= (!cpufeatures
->f_LZCNT
);
695 squashme
= (!cpufeatures
->f_SSSE3
);
698 squashme
= (!cpufeatures
->f_3DNOW
);
701 squashme
= (!cpufeatures
->f_E3DNOW
);
704 /* This case requires CPUID checking code */
705 /* DATA16 prefix required */
706 if (!(mstate
->inst
.prefixmask
& kPrefixDATA16
)) {
707 Stats_BadPrefix(mstate
->vstate
);
709 squashme
= (!cpufeatures
->f_SSE2
);
713 Stats_Return(mstate
->vstate
);
714 /* ... and fall through to illegal instruction code */
718 /* EMMX, SSE41 and SSE42 need to be supported someday but */
719 /* aren't ready yet */
731 case NACLi_CMPXCHG16B
:
733 uint8_t *opcode
= mstate
->inst
.maddr
+ mstate
->inst
.prefixbytes
;
734 Stats_IllegalInst(mstate
->vstate
);
736 printf("VALIDATOR: illegal inst at %x (%02x)\n", mstate
->inst
.vaddr
, *opcode
);
740 case NACLi_UNDEFINED
:
742 uint8_t *opcode
= mstate
->inst
.maddr
+ mstate
->inst
.prefixbytes
;
743 Stats_IllegalInst(mstate
->vstate
);
744 Stats_InternalError(mstate
->vstate
);
746 printf("VALIDATOR: undefined inst at %x (%02x)\n", mstate
->inst
.vaddr
, *opcode
);
750 /* Note that by omitting a default: case the compiler checks */
751 /* that all cases are covered. */
753 /* Disable this for now because we are mmapping code read-only. */
755 if (squashme
) memset(mstate
->inst
.maddr
, kNaClFullStop
, mstate
->inst
.length
);
759 void NCValidateSegment(uint8_t *mbase
, uint32_t vbase
, size_t sz
,
760 struct NCValidatorState
*vstate
) {
762 Stats_MissingFullStop(vstate
);
763 Stats_SegFault(vstate
);
766 GetCPUFeatures(&(vstate
->cpufeatures
));
767 /* The name of the flag is misleading; f_386 requires not just */
768 /* 386 instructions but also the CPUID instruction is supported. */
769 if (!vstate
->cpufeatures
.f_386
) {
770 Stats_BadCPU(vstate
);
774 /* TODO: enable this check */
775 if (!vstate
->cpufeatures
.f_whitelisted
) {
776 Stats_BadCPU(vstate
);
781 NCDecodeSegment(mbase
, vbase
, sz
-1, vstate
);
782 if (mbase
[sz
-1] != kNaClFullStop
) {
783 Stats_MissingFullStop(vstate
);