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 static void ValidatePrintError(const uint32_t addr
, char *msg
) {
65 printf("VALIDATOR: %x: %s\n", addr
, msg
);
68 /* opcode histogram */
70 static void OpcodeHisto(const uint8_t byte1
, struct NCValidatorState
*vstate
) {
71 vstate
->opcodehisto
[byte1
] += 1;
74 static void InitOpcodeHisto(struct NCValidatorState
*vstate
) {
76 for (i
= 0; i
< 256; i
+= 1) vstate
->opcodehisto
[i
] = 0;
79 static void PrintOpcodeHisto(FILE *f
, struct NCValidatorState
*vstate
) {
81 int printed_in_this_row
= 0;
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;
94 if (0 != printed_in_this_row
) {
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
,
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;
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
);
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");
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() {
286 for (i
= 0; i
< kNaClInstTypeRange
; i
++) {
287 BadPrefixMask
[i
] = 0xffffffff; /* all prefixes are bad */
289 BadPrefixMask
[NACLi_386
] = ~(kPrefixDATA16
| kPrefixSEGGS
);
290 BadPrefixMask
[NACLi_386L
] = ~(kPrefixDATA16
| kPrefixSEGGS
| kPrefixLOCK
);
291 BadPrefixMask
[NACLi_386R
] = ~(kPrefixDATA16
| kPrefixREP
);
292 BadPrefixMask
[NACLi_386RE
] = ~(kPrefixDATA16
| kPrefixREP
| kPrefixREPNE
);
293 /* CS and DS prefix bytes are used as branch prediction hints */
294 /* and do not affect target address computation. */
295 BadPrefixMask
[NACLi_JMP8
] = ~(kPrefixSEGCS
| kPrefixSEGDS
);
296 BadPrefixMask
[NACLi_JMPZ
] = ~(kPrefixSEGCS
| kPrefixSEGDS
);
297 BadPrefixMask
[NACLi_CMPXCHG8B
] = ~kPrefixLOCK
;
301 * NCValidateInit: Initialize NaCl validator internal state
303 * vbase: base virtual address for code segment
304 * vlimit: size in bytes of code segment
305 * alignment: 16 or 32, specifying alignment
307 * an initialized struct NCValidatorState * if everything is okay,
310 struct NCValidatorState
*NCValidateInit(const uint32_t vbase
,
311 const uint32_t vlimit
,
312 const uint8_t alignment
) {
313 uint32_t alignbase
= vbase
& (~alignment
);
314 struct NCValidatorState
*vstate
;
316 dprint(("NCValidateInit(%08x, %08x, %08x)\n", vbase
, vlimit
, alignment
));
319 if (vlimit
<= vbase
) break;
320 if (alignment
!= 16 && alignment
!= 32) break;
321 dprint(("ncv_init(%x, %x)\n", vbase
, vlimit
));
322 vstate
= (struct NCValidatorState
*)calloc(1, sizeof(*vstate
));
323 if (vstate
== NULL
) break;
324 vstate
->iadrbase
= alignbase
;
325 vstate
->iadrlimit
= vlimit
;
326 vstate
->alignment
= alignment
;
327 vstate
->alignmask
= alignment
-1;
328 vstate
->vttable
= (uint8_t *)calloc(IATOffset(vlimit
- alignbase
) + 1, 1);
329 vstate
->kttable
= (uint8_t *)calloc(IATOffset(vlimit
- alignbase
) + 1, 1);
330 if (vstate
->vttable
== NULL
|| vstate
->kttable
== NULL
) break;
331 dprint((" allocated tables\n"));
333 NCDecodeRegisterCallbacks(ValidateInst
, Stats_NewSegment
,
334 Stats_SegFault
, Stats_InternalError
);
341 static void RememberIP(const uint32_t ip
, struct NCValidatorState
*vstate
) {
342 uint32_t ioffset
= ip
- vstate
->iadrbase
;
343 if (ip
< vstate
->iadrbase
|| ip
>= vstate
->iadrlimit
) {
344 ValidatePrintError(ip
, "JUMP TARGET out of range in RememberIP");
345 Stats_BadTarget(vstate
);
348 if (GetAdrTable(ioffset
, vstate
->vttable
)) {
349 vprint(("RememberIP: Saw inst at %08x twice\n", ip
));
350 Stats_InternalError(vstate
);
354 SetAdrTable(ioffset
, vstate
->vttable
);
357 static void RememberTP(const uint32_t src
, uint32_t target
,
358 struct NCValidatorState
*vstate
) {
359 uint32_t ioffset
= target
- vstate
->iadrbase
;
362 if (target
< vstate
->iadrlimit
) {
363 if (target
>= vstate
->iadrbase
) break;
364 /* Aligned targets are always OK. */
365 if (target
% NACL_INSTR_BLOCK_SIZE
== 0)
368 * the trampolines need to be aligned 0mod32 regardless of the
369 * program's elf flags. This allows the same library to be used
370 * with both 16 and 32 byte aligned clients.
372 if (target
>= vstate
->iadrbase
- NACL_TRAMPOLINE_END
373 && ((target
& (NACL_INSTR_BLOCK_SIZE
-1)) == 0)) {
375 * TODO: once we fully support 16/32 alignment, remove this
376 * in favor of however we communicate the fixed block size.
378 /* this is an aligned target in the trampoline area; ignore */
379 /* vprint(("ignoring target %08x in trampoline\n", target)); */
383 //vprint(("VALIDATOR: %08x: JUMP TARGET %08x out of range\n", src, target));
384 LogError(vstate
, src
, "Jump target out of range");
385 Stats_BadTarget(vstate
);
388 SetAdrTable(ioffset
, vstate
->kttable
);
391 static void ForgetIP(const uint32_t ip
,
392 struct NCValidatorState
*vstate
) {
393 uint32_t ioffset
= ip
- vstate
->iadrbase
;
394 if (ip
< vstate
->iadrbase
|| ip
>= vstate
->iadrlimit
) {
395 ValidatePrintError(ip
, "JUMP TARGET out of range in ForgetIP");
396 Stats_BadTarget(vstate
);
399 ClearAdrTable(ioffset
, vstate
->vttable
);
402 int NCValidateFinish(struct NCValidatorState
*vstate
) {
404 if (vstate
== NULL
) {
405 vprint(("validator not initialized. Did you call ncvalidate_init()?\n"));
406 /* non-zero indicates failure */
409 dprint(("CheckTargets: %x-%x\n", vstate
->iadrbase
, vstate
->iadrlimit
));
411 offset
< vstate
->iadrlimit
- vstate
->iadrbase
;
413 if (GetAdrTable(offset
, vstate
->kttable
)) {
414 /* printf("CheckTarget %x\n", offset + iadrbase); */
415 Stats_CheckTarget(vstate
);
416 if (!GetAdrTable(offset
, vstate
->vttable
)) {
417 Stats_BadTarget(vstate
);
418 ValidatePrintError(vstate
->iadrbase
+ offset
, "Bad jump target");
422 /* check basic block boundaries */
423 if (vstate
->iadrbase
& vstate
->alignmask
) {
424 ValidatePrintError(vstate
->iadrbase
, "Bad base address alignment");
425 Stats_BadAlignment(vstate
);
427 for (offset
= 0; offset
< vstate
->iadrlimit
- vstate
->iadrbase
;
428 offset
+= vstate
->alignment
) {
429 if (!GetAdrTable(offset
, vstate
->vttable
)) {
430 ValidatePrintError(vstate
->iadrbase
+ offset
, "Bad basic block alignent");
431 Stats_BadAlignment(vstate
);
436 /* Now that all the work is done, generate return code. */
437 /* Return zero if there are no problems. */
438 return (vstate
->stats
.sawfailure
);
441 void NCValidateFreeState(struct NCValidatorState
**vstate
) {
442 if (*vstate
== NULL
) return;
443 free((*vstate
)->vttable
);
444 free((*vstate
)->kttable
);
449 static void ValidateCallAlignment(const struct NCDecoderState
*mstate
) {
450 uint32_t fallthru
= mstate
->inst
.vaddr
+ mstate
->inst
.length
;
451 if (fallthru
& mstate
->vstate
->alignmask
) {
452 LogErrorInst(mstate
, "Bad call alignment");
453 /* This makes bad call alignment a fatal error. */
454 Stats_BadAlignment(mstate
->vstate
);
458 static void ValidateJmp8(const struct NCDecoderState
*mstate
) {
459 uint8_t opcode
= (uint8_t)mstate
->inst
.maddr
[mstate
->inst
.prefixbytes
];
460 int8_t offset
= (int8_t)mstate
->inst
.maddr
[mstate
->inst
.prefixbytes
+1];
461 uint32_t target
= mstate
->inst
.vaddr
+ mstate
->inst
.length
+ offset
;
462 Stats_CheckTarget(mstate
->vstate
);
463 if ((opcode
& 0xf0) == 0x70 || opcode
== 0xeb ||
464 opcode
== 0xe0 || opcode
== 0xe1 || opcode
== 0xe2 || opcode
== 0xe3) {
465 RememberTP(mstate
->inst
.vaddr
, target
, mstate
->vstate
);
467 /* If this ever happens, it's probably a decoder bug. */
468 vprint(("ERROR: JMP8 %x: %x\n", mstate
->inst
.vaddr
, opcode
));
469 Stats_InternalError(mstate
->vstate
);
473 static void ValidateJmpz(const struct NCDecoderState
*mstate
) {
474 uint8_t *opcode
= mstate
->inst
.maddr
+ mstate
->inst
.prefixbytes
;
477 Stats_CheckTarget(mstate
->vstate
);
478 if (*opcode
== 0xe8 || *opcode
== 0xe9) {
479 offset
= *(int32_t *)&opcode
[1];
480 target
= mstate
->inst
.vaddr
+ mstate
->inst
.length
+ offset
;
481 RememberTP(mstate
->inst
.vaddr
, target
, mstate
->vstate
);
482 /* as a courtesy, check call alignment correctness */
483 if (*opcode
== 0xe8) ValidateCallAlignment(mstate
);
484 } else if (*opcode
== 0x0f) {
485 if ((opcode
[1] & 0xf0) == 0x80) {
486 offset
= *(int32_t *)&opcode
[2];
487 target
= mstate
->inst
.vaddr
+ mstate
->inst
.length
+ offset
;
488 RememberTP(mstate
->inst
.vaddr
, target
, mstate
->vstate
);
491 /* If this ever happens, it's probably a decoder bug. */
492 vprint(("ERROR: JMPZ %x: %x %x\n",
493 mstate
->inst
.vaddr
, opcode
[0], opcode
[1]));
494 Stats_InternalError(mstate
->vstate
);
499 * The NaCl 14-byte safe indirect calling sequence looks like this:
500 * 81 e0 ff ff ff ff and $0xffffffff,%eax
501 * 81 c8 00 00 00 00 or $0x0,%eax
503 * The call may be replaced with a ff e0 jmp. Any register may
504 * be used, not just eax. The validator requires exactly this
506 * TODO: validate or write the masks.
509 NOTE
: This routine has
not been kept up to date
, and should be updated
510 with respect to the five
-byte
version (below
) if we need to use it
512 static void ValidateIndirect14(const struct NCDecoderState
*mstate
) {
519 struct NCDecoderState
*andinst
= PreviousInst(mstate
, -2);
520 struct NCDecoderState
*orinst
= PreviousInst(mstate
, -1);
521 assert(andinst
!= NULL
);
522 assert(orinst
!= NULL
);
523 if ((andinst
->inst
.length
== 0) || (orinst
->inst
.length
== 0)) {
524 Stats_UnsafeIndirect(mstate
->vstate
);
527 /* no prefix bytes allowed; checked below */
528 jmpopcode
= mstate
->inst
.maddr
;
529 oropcode
= orinst
->inst
.maddr
;
530 andopcode
= andinst
->inst
.maddr
;
534 Stats_CheckTarget(mstate
->vstate
);
535 Stats_TargetIndirect(mstate
->vstate
);
537 /* check no prefix bytes */
538 if (mstate
->inst
.prefixbytes
!= 0) break;
539 if (andinst
->inst
.prefixbytes
!= 0) break;
540 if (orinst
->inst
.prefixbytes
!= 0) break;
541 /* check all the opcodes. */
542 if (jmpopcode
[0] != 0xff) break;
543 if ((modrm_reg(mrm
) != 2) && (modrm_reg(mrm
) != 4)) break;
544 /* Issue 32: disallow unsafe call/jump indirection */
545 /* example: ff 12 call (*edx) */
546 /* Reported by defend.the.world on 11 Dec 2008 */
547 if (modrm_mod(mrm
) != 3) break;
548 if (oropcode
[0] != 0x81) break;
549 if (andopcode
[0] != 0x81) break;
550 /* check modrm bytes of or and and instructions */
551 if (andopcode
[1] != (0xe0 | reg
)) break;
552 if (oropcode
[1] != (0xc8 | reg
)) break;
554 assert(0); /* not implemented yet, so don't use this routine! */
555 /* All checks look good. Make the sequence 'atomic.' */
556 ForgetIP(orinst
->inst
.vaddr
, mstate
->vstate
);
557 ForgetIP(mstate
->inst
.vaddr
, mstate
->vstate
);
560 Stats_UnsafeIndirect(mstate
->vstate
);
565 * The NaCl five-byte safe indirect calling sequence looks like this:
566 * 83 e0 f0 and $0xfffffff0,%eax
568 * The call may be replaced with a ff e0 jmp. Any register may
569 * be used, not just eax. The validator requires exactly this
571 * TODO: validate or write the masks.
573 static void ValidateIndirect5(const struct NCDecoderState
*mstate
) {
578 const uint8_t kReg_ESP
= 4;
580 struct NCDecoderState
*andinst
= PreviousInst(mstate
, -1);
581 assert(andinst
!= NULL
);
582 if (andinst
->inst
.length
== 0) {
583 Stats_UnsafeIndirect(mstate
->vstate
);
586 jmpopcode
= mstate
->inst
.maddr
; /* note: no prefixbytes allowed */
587 andopcode
= andinst
->inst
.maddr
; /* note: no prefixbytes allowed */
589 targetreg
= modrm_rm(mrm
); /* Note that the modrm_rm field holds the */
590 /* target addr the modrm_reg is the opcode. */
592 Stats_CheckTarget(mstate
->vstate
);
593 Stats_TargetIndirect(mstate
->vstate
);
595 /* no prefix bytes allowed */
596 if (mstate
->inst
.prefixbytes
!= 0) break;
597 if (andinst
->inst
.prefixbytes
!= 0) break;
598 /* Check all the opcodes. */
599 /* In GROUP5, 2 => call, 4 => jmp */
600 if (jmpopcode
[0] != 0xff) break;
601 if ((modrm_reg(mrm
) != 2) && (modrm_reg(mrm
) != 4)) break;
602 /* Issue 32: disallow unsafe call/jump indirection */
603 /* example: ff 12 call (*edx) */
604 /* Reported by defend.the.world on 11 Dec 2008 */
605 if (modrm_mod(mrm
) != 3) break;
606 if (targetreg
== kReg_ESP
) break;
607 if (andopcode
[0] != 0x83) break;
608 /* check modrm bytes of or and and instructions */
609 if (andopcode
[1] != (0xe0 | targetreg
)) break;
611 if (andopcode
[2] != (0x0ff & ~mstate
->vstate
->alignmask
)) break;
612 /* All checks look good. Make the sequence 'atomic.' */
613 ForgetIP(mstate
->inst
.vaddr
, mstate
->vstate
);
614 /* as a courtesy, check call alignment correctness */
615 if (modrm_reg(mrm
) == 2) ValidateCallAlignment(mstate
);
618 Stats_UnsafeIndirect(mstate
->vstate
);
619 LogErrorInst(mstate
, "Unsafe indirect jump");
622 /* It appears to me that none of my favorite test programs use more */
623 /* than a single prefix byte on an instruction. It would be nice if */
624 /* we could make this a requirement. */
625 static const size_t kMaxValidInstLength
= 11;
626 static const uint8_t kNaClFullStop
= 0xf4; /* x86 HALT opcode */
628 void ValidateInst(const struct NCDecoderState
*mstate
) {
629 const int kMaxValPrefixBytes
= 2;
630 CPUFeatures
*cpufeatures
;
633 /* dprint(("ValidateInst(%x, %x) at %x\n",
634 (uint32_t)mstate, (uint32_t)mstate->vstate, mstate->inst.vaddr)); */
635 if (mstate
== NULL
) return;
636 if (mstate
->vstate
== NULL
) return;
637 OpcodeHisto(mstate
->inst
.maddr
[mstate
->inst
.prefixbytes
],
639 RememberIP(mstate
->inst
.vaddr
, mstate
->vstate
);
640 cpufeatures
= &(mstate
->vstate
->cpufeatures
);
642 if (mstate
->inst
.prefixbytes
== 0) break;
643 if (mstate
->inst
.prefixbytes
<= kMaxValPrefixBytes
) {
644 if (mstate
->inst
.hasopbyte2
) {
645 if (mstate
->inst
.prefixmask
& kPrefixLOCK
) {
646 /* For two byte opcodes, check for use of the lock prefix. */
647 if (mstate
->opinfo
->insttype
== NACLi_386L
) break;
648 if (mstate
->opinfo
->insttype
== NACLi_CMPXCHG8B
) break;
650 /* Other prefixes checks are encoded in the two-byte tables. */
654 /* one byte opcode */
655 if ((mstate
->inst
.prefixmask
&
656 BadPrefixMask
[mstate
->opinfo
->insttype
]) == 0) break;
659 //vprint(("VALIDATOR: BadPrefix at %08x, length %i\n", mstate->inst.vaddr,
660 // mstate->inst.prefixbytes));
661 LogErrorInst(mstate
, "Bad prefix");
662 Stats_BadPrefix(mstate
->vstate
);
664 if ((size_t) (mstate
->inst
.length
- mstate
->inst
.prefixbytes
)
665 > kMaxValidInstLength
) {
666 Stats_BadInstLength(mstate
->vstate
);
668 switch (mstate
->opinfo
->insttype
) {
675 ValidateJmp8(mstate
);
678 ValidateJmpz(mstate
);
681 ValidateIndirect5(mstate
);
684 squashme
= (!cpufeatures
->f_x87
);
687 squashme
= (!cpufeatures
->f_CFLUSH
);
689 case NACLi_CMPXCHG8B
:
690 squashme
= (!cpufeatures
->f_CX8
);
693 squashme
= (!cpufeatures
->f_CMOV
);
696 squashme
= (!(cpufeatures
->f_CMOV
&& cpufeatures
->f_x87
));
699 squashme
= (!cpufeatures
->f_TSC
);
702 squashme
= (!cpufeatures
->f_MMX
);
705 /* Note: We accept these instructions if either MMX or SSE2 bits */
706 /* are set, in case MMX instructions go away someday... */
707 squashme
= (!(cpufeatures
->f_MMX
|| cpufeatures
->f_SSE2
));
710 squashme
= (!cpufeatures
->f_SSE
);
713 squashme
= (!cpufeatures
->f_SSE2
);
716 squashme
= (!cpufeatures
->f_SSE3
);
719 squashme
= (!cpufeatures
->f_SSE4A
);
722 squashme
= (!cpufeatures
->f_SSE41
);
725 squashme
= (!cpufeatures
->f_SSE42
);
728 squashme
= (!cpufeatures
->f_MOVBE
);
731 squashme
= (!cpufeatures
->f_POPCNT
);
734 squashme
= (!cpufeatures
->f_LZCNT
);
737 squashme
= (!cpufeatures
->f_SSSE3
);
740 squashme
= (!cpufeatures
->f_3DNOW
);
743 squashme
= (!cpufeatures
->f_E3DNOW
);
746 /* This case requires CPUID checking code */
747 /* DATA16 prefix required */
748 if (!(mstate
->inst
.prefixmask
& kPrefixDATA16
)) {
749 Stats_BadPrefix(mstate
->vstate
);
751 squashme
= (!cpufeatures
->f_SSE2
);
755 Stats_Return(mstate
->vstate
);
756 /* ... and fall through to illegal instruction code */
758 /* EMMX needs to be supported someday but isn't ready yet. */
770 case NACLi_CMPXCHG16B
:
772 /* uint8_t *opcode = mstate->inst.maddr + mstate->inst.prefixbytes; */
773 Stats_IllegalInst(mstate
->vstate
);
774 LogErrorInst(mstate
, "Illegal instruction");
777 case NACLi_UNDEFINED
:
779 /* uint8_t *opcode = mstate->inst.maddr + mstate->inst.prefixbytes; */
780 Stats_IllegalInst(mstate
->vstate
);
781 Stats_InternalError(mstate
->vstate
);
782 LogErrorInst(mstate
, "Undefined instruction");
786 ValidatePrintError(mstate
->inst
.vaddr
, "Undefined instruction type");
787 Stats_InternalError(mstate
->vstate
);
790 if (squashme
) memset(mstate
->inst
.maddr
, kNaClFullStop
, mstate
->inst
.length
);
793 void NCValidateSegment(uint8_t *mbase
, uint32_t vbase
, size_t sz
,
794 struct NCValidatorState
*vstate
) {
796 Stats_MissingFullStop(vstate
);
797 Stats_SegFault(vstate
);
800 GetCPUFeatures(&(vstate
->cpufeatures
));
801 /* The name of the flag is misleading; f_386 requires not just */
802 /* 386 instructions but also the CPUID instruction is supported. */
803 if (!vstate
->cpufeatures
.f_386
) {
804 Stats_BadCPU(vstate
);
808 /* TODO: enable this check */
809 if (!vstate
->cpufeatures
.f_whitelisted
) {
810 Stats_BadCPU(vstate
);
815 NCDecodeSegment(mbase
, vbase
, sz
-1, vstate
);
816 /* The check for a terminating hlt should only be necessary if the
817 end of the x86 code segment isn't 32-byte-aligned. */
818 if (mbase
[sz
-1] != kNaClFullStop
&& (sz
% NACL_PAGESIZE
) != 0) {
819 Stats_MissingFullStop(vstate
);