1 #include <assert.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <inttypes.h>
5 #include <limits.h>
6 #include <stdbool.h>
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <sys/mman.h>
13 #include <unistd.h>
14 #include <xen/xen.h>
15
16 #include "x86-emulate.h"
17 /*
18 * include "x86-emulate.h" prior to <stdio.h> and <string.h>:
19 * x86-emulate.h disables use of SSE registers, while <stdio.h> and <string.h>
20 * declare functions that may be always_inline and use those registers
21 * unless they have been disabled earlier, which can fail to compile.
22 */
23 #include <stdio.h>
24 #include <string.h>
25 #include "fuzz-emul.h"
26
27 #define MSR_INDEX_MAX 16
28
29 #define SEG_NUM x86_seg_none
30
31 /* Layout of data expected as fuzzing input. */
32 struct fuzz_corpus
33 {
34 unsigned long cr[5];
35 uint64_t msr[MSR_INDEX_MAX];
36 struct cpu_user_regs regs;
37 struct segment_register segments[SEG_NUM];
38 unsigned long options;
39 unsigned char data[INPUT_SIZE];
40 } input;
41 #define DATA_OFFSET offsetof(struct fuzz_corpus, data)
42 #define FUZZ_CORPUS_SIZE (sizeof(struct fuzz_corpus))
43
44 /*
45 * Internal state of the fuzzing harness. Calculated initially from the input
46 * corpus, and later mutates by the emulation callbacks.
47 */
48 struct fuzz_state
49 {
50 /* Fuzzer's input data. */
51 struct fuzz_corpus *corpus;
52
53 /* Real amount of data backing corpus->data[]. */
54 size_t data_num;
55
56 /* Amount of corpus->data[] consumed thus far. */
57 size_t data_index;
58
59 /* Emulation ops, some of which are disabled based on corpus->options. */
60 struct x86_emulate_ops ops;
61 };
62
input_avail(const struct fuzz_state * s,size_t size)63 static inline bool input_avail(const struct fuzz_state *s, size_t size)
64 {
65 return s->data_index + size <= s->data_num;
66 }
67
input_read(struct fuzz_state * s,void * dst,size_t size)68 static inline bool input_read(struct fuzz_state *s, void *dst, size_t size)
69 {
70 if ( !input_avail(s, size) )
71 return false;
72
73 memcpy(dst, &s->corpus->data[s->data_index], size);
74 s->data_index += size;
75
76 return true;
77 }
78
79 static bool check_state(struct x86_emulate_ctxt *ctxt);
80
81 static const char* const x86emul_return_string[] = {
82 [X86EMUL_OKAY] = "X86EMUL_OKAY",
83 [X86EMUL_UNHANDLEABLE] = "X86EMUL_UNHANDLEABLE",
84 [X86EMUL_EXCEPTION] = "X86EMUL_EXCEPTION",
85 [X86EMUL_RETRY] = "X86EMUL_RETRY",
86 [X86EMUL_DONE] = "X86EMUL_DONE",
87 };
88
89 /*
90 * Randomly return success or failure when processing data. If
91 * `exception` is false, this function turns _EXCEPTION to _OKAY.
92 */
maybe_fail(struct x86_emulate_ctxt * ctxt,const char * why,bool exception)93 static int maybe_fail(struct x86_emulate_ctxt *ctxt,
94 const char *why, bool exception)
95 {
96 struct fuzz_state *s = ctxt->data;
97 unsigned char c;
98 int rc;
99
100 if ( !input_read(s, &c, sizeof(c)) )
101 rc = X86EMUL_EXCEPTION;
102 else
103 {
104 /* Randomly returns value:
105 * 50% okay
106 * 25% unhandlable
107 * 25% exception
108 */
109 if ( c > 0xc0 )
110 rc = X86EMUL_EXCEPTION;
111 else if ( c > 0x80 )
112 rc = X86EMUL_UNHANDLEABLE;
113 else
114 rc = X86EMUL_OKAY;
115 }
116
117 if ( rc == X86EMUL_EXCEPTION && !exception )
118 rc = X86EMUL_OKAY;
119
120 printf("maybe_fail %s: %s\n", why, x86emul_return_string[rc]);
121
122 if ( rc == X86EMUL_EXCEPTION )
123 /* Fake up a pagefault. */
124 x86_emul_pagefault(0, 0, ctxt);
125
126 return rc;
127 }
128
data_read(struct x86_emulate_ctxt * ctxt,enum x86_segment seg,const char * why,void * dst,unsigned int bytes)129 static int data_read(struct x86_emulate_ctxt *ctxt,
130 enum x86_segment seg,
131 const char *why, void *dst, unsigned int bytes)
132 {
133 struct fuzz_state *s = ctxt->data;
134 unsigned int i;
135 int rc;
136
137 if ( !input_avail(s, bytes) )
138 {
139 /*
140 * Fake up a segment limit violation. System segment limit volations
141 * are reported by X86EMUL_EXCEPTION alone, so the emulator can fill
142 * in the correct context.
143 */
144 if ( !is_x86_system_segment(seg) )
145 x86_emul_hw_exception(13, 0, ctxt);
146
147 rc = X86EMUL_EXCEPTION;
148 printf("data_read %s: X86EMUL_EXCEPTION (end of input)\n", why);
149 }
150 else
151 rc = maybe_fail(ctxt, why, true);
152
153 if ( rc == X86EMUL_OKAY )
154 {
155 input_read(s, dst, bytes);
156
157 printf("%s: ", why);
158 for ( i = 0; i < bytes; i++ )
159 printf(" %02x", *(unsigned char *)(dst + i));
160 printf("\n");
161 }
162
163 return rc;
164 }
165
fuzz_read(enum x86_segment seg,unsigned long offset,void * p_data,unsigned int bytes,struct x86_emulate_ctxt * ctxt)166 static int fuzz_read(
167 enum x86_segment seg,
168 unsigned long offset,
169 void *p_data,
170 unsigned int bytes,
171 struct x86_emulate_ctxt *ctxt)
172 {
173 /* Reads expected for all user and system segments. */
174 if ( is_x86_user_segment(seg) )
175 assert(ctxt->addr_size == 64 || !(offset >> 32));
176 else if ( seg == x86_seg_tr )
177 /*
178 * The TSS is special in that accesses below the segment base are
179 * possible, as the Interrupt Redirection Bitmap starts 32 bytes
180 * ahead of the I/O Bitmap, regardless of the value of the latter.
181 */
182 assert((long)offset < 0 ? (long)offset > -32 : !(offset >> 17));
183 else
184 assert(is_x86_system_segment(seg) &&
185 (ctxt->lma ? offset <= 0x10007 : !(offset >> 16)));
186
187 return data_read(ctxt, seg, "read", p_data, bytes);
188 }
189
fuzz_read_io(unsigned int port,unsigned int bytes,unsigned long * val,struct x86_emulate_ctxt * ctxt)190 static int fuzz_read_io(
191 unsigned int port,
192 unsigned int bytes,
193 unsigned long *val,
194 struct x86_emulate_ctxt *ctxt)
195 {
196 return data_read(ctxt, x86_seg_none, "read_io", val, bytes);
197 }
198
fuzz_insn_fetch(unsigned long offset,void * p_data,unsigned int bytes,struct x86_emulate_ctxt * ctxt)199 static int fuzz_insn_fetch(
200 unsigned long offset,
201 void *p_data,
202 unsigned int bytes,
203 struct x86_emulate_ctxt *ctxt)
204 {
205 /* Minimal segment limit checking, until full one is being put in place. */
206 if ( ctxt->addr_size < 64 && (offset >> 32) )
207 {
208 x86_emul_hw_exception(13, 0, ctxt);
209 return X86EMUL_EXCEPTION;
210 }
211
212 /*
213 * Zero-length instruction fetches are made at the destination of jumps,
214 * to perform segmentation checks. No data needs returning.
215 */
216 if ( bytes == 0 )
217 {
218 assert(p_data == NULL);
219 return maybe_fail(ctxt, "insn_fetch", true);
220 }
221
222 return data_read(ctxt, x86_seg_cs, "insn_fetch", p_data, bytes);
223 }
224
_fuzz_rep_read(struct x86_emulate_ctxt * ctxt,const char * why,unsigned long * reps)225 static int _fuzz_rep_read(struct x86_emulate_ctxt *ctxt,
226 const char *why, unsigned long *reps)
227 {
228 int rc;
229 unsigned long bytes_read = 0;
230
231 rc = data_read(ctxt, x86_seg_none, why, &bytes_read, sizeof(bytes_read));
232
233 if ( bytes_read <= *reps )
234 *reps = bytes_read;
235
236 switch ( rc )
237 {
238 case X86EMUL_UNHANDLEABLE:
239 /* No work is done in this case */
240 *reps = 0;
241 break;
242 case X86EMUL_EXCEPTION:
243 case X86EMUL_RETRY:
244 /* Halve the amount in this case */
245 *reps /= 2;
246 break;
247 }
248
249 return rc;
250 }
251
_fuzz_rep_write(struct x86_emulate_ctxt * ctxt,const char * why,unsigned long * reps)252 static int _fuzz_rep_write(struct x86_emulate_ctxt *ctxt,
253 const char *why, unsigned long *reps)
254 {
255 int rc = maybe_fail(ctxt, why, true);
256
257 switch ( rc )
258 {
259 case X86EMUL_UNHANDLEABLE:
260 /* No work is done in this case */
261 *reps = 0;
262 break;
263 case X86EMUL_EXCEPTION:
264 case X86EMUL_RETRY:
265 /* Halve the amount in this case */
266 *reps /= 2;
267 break;
268 }
269
270 return rc;
271 }
272
fuzz_rep_ins(uint16_t src_port,enum x86_segment dst_seg,unsigned long dst_offset,unsigned int bytes_per_rep,unsigned long * reps,struct x86_emulate_ctxt * ctxt)273 static int fuzz_rep_ins(
274 uint16_t src_port,
275 enum x86_segment dst_seg,
276 unsigned long dst_offset,
277 unsigned int bytes_per_rep,
278 unsigned long *reps,
279 struct x86_emulate_ctxt *ctxt)
280 {
281 assert(dst_seg == x86_seg_es);
282 assert(ctxt->addr_size == 64 || !(dst_offset >> 32));
283
284 return _fuzz_rep_read(ctxt, "rep_ins", reps);
285 }
286
fuzz_rep_movs(enum x86_segment src_seg,unsigned long src_offset,enum x86_segment dst_seg,unsigned long dst_offset,unsigned int bytes_per_rep,unsigned long * reps,struct x86_emulate_ctxt * ctxt)287 static int fuzz_rep_movs(
288 enum x86_segment src_seg,
289 unsigned long src_offset,
290 enum x86_segment dst_seg,
291 unsigned long dst_offset,
292 unsigned int bytes_per_rep,
293 unsigned long *reps,
294 struct x86_emulate_ctxt *ctxt)
295 {
296 assert(is_x86_user_segment(src_seg));
297 assert(dst_seg == x86_seg_es);
298 assert(ctxt->addr_size == 64 || !((src_offset | dst_offset) >> 32));
299
300 return _fuzz_rep_read(ctxt, "rep_movs", reps);
301 }
302
fuzz_rep_outs(enum x86_segment src_seg,unsigned long src_offset,uint16_t dst_port,unsigned int bytes_per_rep,unsigned long * reps,struct x86_emulate_ctxt * ctxt)303 static int fuzz_rep_outs(
304 enum x86_segment src_seg,
305 unsigned long src_offset,
306 uint16_t dst_port,
307 unsigned int bytes_per_rep,
308 unsigned long *reps,
309 struct x86_emulate_ctxt *ctxt)
310 {
311 assert(is_x86_user_segment(src_seg));
312 assert(ctxt->addr_size == 64 || !(src_offset >> 32));
313
314 return _fuzz_rep_write(ctxt, "rep_outs", reps);
315 }
316
fuzz_rep_stos(void * p_data,enum x86_segment seg,unsigned long offset,unsigned int bytes_per_rep,unsigned long * reps,struct x86_emulate_ctxt * ctxt)317 static int fuzz_rep_stos(
318 void *p_data,
319 enum x86_segment seg,
320 unsigned long offset,
321 unsigned int bytes_per_rep,
322 unsigned long *reps,
323 struct x86_emulate_ctxt *ctxt)
324 {
325 /*
326 * STOS itself may only have an %es segment, but the stos() hook is reused
327 * for CLZERO.
328 */
329 assert(is_x86_user_segment(seg));
330 assert(ctxt->addr_size == 64 || !(offset >> 32));
331
332 return _fuzz_rep_write(ctxt, "rep_stos", reps);
333 }
334
fuzz_write(enum x86_segment seg,unsigned long offset,void * p_data,unsigned int bytes,struct x86_emulate_ctxt * ctxt)335 static int fuzz_write(
336 enum x86_segment seg,
337 unsigned long offset,
338 void *p_data,
339 unsigned int bytes,
340 struct x86_emulate_ctxt *ctxt)
341 {
342 /* Writes not expected for any system segments. */
343 assert(is_x86_user_segment(seg));
344 assert(ctxt->addr_size == 64 || !(offset >> 32));
345
346 return maybe_fail(ctxt, "write", true);
347 }
348
fuzz_cmpxchg(enum x86_segment seg,unsigned long offset,void * old,void * new,unsigned int bytes,bool lock,struct x86_emulate_ctxt * ctxt)349 static int fuzz_cmpxchg(
350 enum x86_segment seg,
351 unsigned long offset,
352 void *old,
353 void *new,
354 unsigned int bytes,
355 bool lock,
356 struct x86_emulate_ctxt *ctxt)
357 {
358 /*
359 * Cmpxchg expected for user segments, and setting accessed/busy bits in
360 * GDT/LDT enties, but not expected for any IDT or TR accesses.
361 */
362 if ( is_x86_user_segment(seg) )
363 assert(ctxt->addr_size == 64 || !(offset >> 32));
364 else
365 assert((seg == x86_seg_gdtr || seg == x86_seg_ldtr) && !(offset >> 16));
366
367 return maybe_fail(ctxt, "cmpxchg", true);
368 }
369
fuzz_tlb_op(enum x86emul_tlb_op op,unsigned long addr,unsigned long aux,struct x86_emulate_ctxt * ctxt)370 static int fuzz_tlb_op(
371 enum x86emul_tlb_op op,
372 unsigned long addr,
373 unsigned long aux,
374 struct x86_emulate_ctxt *ctxt)
375 {
376 switch ( op )
377 {
378 case x86emul_invlpg:
379 assert(is_x86_user_segment(aux));
380 /* fall through */
381 case x86emul_invlpga:
382 case x86emul_invpcid:
383 assert(ctxt->addr_size == 64 || !(addr >> 32));
384 break;
385 }
386
387 return maybe_fail(ctxt, "TLB-management", false);
388 }
389
fuzz_cache_op(enum x86emul_cache_op op,enum x86_segment seg,unsigned long offset,struct x86_emulate_ctxt * ctxt)390 static int fuzz_cache_op(
391 enum x86emul_cache_op op,
392 enum x86_segment seg,
393 unsigned long offset,
394 struct x86_emulate_ctxt *ctxt)
395 {
396 return maybe_fail(ctxt, "cache-management", true);
397 }
398
fuzz_write_io(unsigned int port,unsigned int bytes,unsigned long val,struct x86_emulate_ctxt * ctxt)399 static int fuzz_write_io(
400 unsigned int port,
401 unsigned int bytes,
402 unsigned long val,
403 struct x86_emulate_ctxt *ctxt)
404 {
405 return maybe_fail(ctxt, "write_io", true);
406 }
407
fuzz_read_segment(enum x86_segment seg,struct segment_register * reg,struct x86_emulate_ctxt * ctxt)408 static int fuzz_read_segment(
409 enum x86_segment seg,
410 struct segment_register *reg,
411 struct x86_emulate_ctxt *ctxt)
412 {
413 const struct fuzz_state *s = ctxt->data;
414 const struct fuzz_corpus *c = s->corpus;
415
416 assert(is_x86_user_segment(seg) || is_x86_system_segment(seg));
417
418 *reg = c->segments[seg];
419
420 return X86EMUL_OKAY;
421 }
422
fuzz_write_segment(enum x86_segment seg,const struct segment_register * reg,struct x86_emulate_ctxt * ctxt)423 static int fuzz_write_segment(
424 enum x86_segment seg,
425 const struct segment_register *reg,
426 struct x86_emulate_ctxt *ctxt)
427 {
428 struct fuzz_state *s = ctxt->data;
429 struct fuzz_corpus *c = s->corpus;
430 int rc;
431
432 assert(is_x86_user_segment(seg) || is_x86_system_segment(seg));
433
434 rc = maybe_fail(ctxt, "write_segment", true);
435
436 if ( rc == X86EMUL_OKAY )
437 {
438 struct segment_register old = c->segments[seg];
439
440 c->segments[seg] = *reg;
441
442 if ( !check_state(ctxt) )
443 {
444 c->segments[seg] = old;
445 x86_emul_hw_exception(13 /* #GP */, 0, ctxt);
446 rc = X86EMUL_EXCEPTION;
447 }
448 }
449
450 return rc;
451 }
452
fuzz_read_cr(unsigned int reg,unsigned long * val,struct x86_emulate_ctxt * ctxt)453 static int fuzz_read_cr(
454 unsigned int reg,
455 unsigned long *val,
456 struct x86_emulate_ctxt *ctxt)
457 {
458 const struct fuzz_state *s = ctxt->data;
459 const struct fuzz_corpus *c = s->corpus;
460
461 if ( reg >= ARRAY_SIZE(c->cr) )
462 return X86EMUL_UNHANDLEABLE;
463
464 *val = c->cr[reg];
465
466 return X86EMUL_OKAY;
467 }
468
fuzz_write_cr(unsigned int reg,unsigned long val,struct x86_emulate_ctxt * ctxt)469 static int fuzz_write_cr(
470 unsigned int reg,
471 unsigned long val,
472 struct x86_emulate_ctxt *ctxt)
473 {
474 struct fuzz_state *s = ctxt->data;
475 struct fuzz_corpus *c = s->corpus;
476 unsigned long old;
477 int rc;
478
479 if ( reg >= ARRAY_SIZE(c->cr) )
480 return X86EMUL_UNHANDLEABLE;
481
482 rc = maybe_fail(ctxt, "write_cr", true);
483 if ( rc != X86EMUL_OKAY )
484 return rc;
485
486 old = c->cr[reg];
487 c->cr[reg] = val;
488
489 if ( !check_state(ctxt) )
490 {
491 c->cr[reg] = old;
492 x86_emul_hw_exception(13 /* #GP */, 0, ctxt);
493 rc = X86EMUL_EXCEPTION;
494 }
495
496 return rc;
497 }
498
499 #define fuzz_read_xcr emul_test_read_xcr
500
501 enum {
502 MSRI_IA32_SYSENTER_CS,
503 MSRI_IA32_SYSENTER_ESP,
504 MSRI_IA32_SYSENTER_EIP,
505 MSRI_EFER,
506 MSRI_STAR,
507 MSRI_LSTAR,
508 MSRI_CSTAR,
509 MSRI_SYSCALL_MASK,
510 MSRI_IA32_DEBUGCTLMSR,
511 };
512
513 static const unsigned int msr_index[MSR_INDEX_MAX] = {
514 [MSRI_IA32_SYSENTER_CS] = MSR_IA32_SYSENTER_CS,
515 [MSRI_IA32_SYSENTER_ESP] = MSR_IA32_SYSENTER_ESP,
516 [MSRI_IA32_SYSENTER_EIP] = MSR_IA32_SYSENTER_EIP,
517 [MSRI_EFER] = MSR_EFER,
518 [MSRI_STAR] = MSR_STAR,
519 [MSRI_LSTAR] = MSR_LSTAR,
520 [MSRI_CSTAR] = MSR_CSTAR,
521 [MSRI_SYSCALL_MASK] = MSR_SYSCALL_MASK,
522 [MSRI_IA32_DEBUGCTLMSR] = MSR_IA32_DEBUGCTLMSR,
523 };
524
fuzz_read_msr(unsigned int reg,uint64_t * val,struct x86_emulate_ctxt * ctxt)525 static int fuzz_read_msr(
526 unsigned int reg,
527 uint64_t *val,
528 struct x86_emulate_ctxt *ctxt)
529 {
530 const struct fuzz_state *s = ctxt->data;
531 const struct fuzz_corpus *c = s->corpus;
532 unsigned int idx;
533
534 switch ( reg )
535 {
536 case MSR_TSC_AUX:
537 case MSR_IA32_TSC:
538 /*
539 * TSC should return monotonically increasing values, TSC_AUX
540 * should preferably return consistent values, but returning
541 * random values is fine in fuzzer.
542 */
543 return data_read(ctxt, x86_seg_none, "read_msr", val, sizeof(*val));
544 case MSR_EFER:
545 *val = c->msr[MSRI_EFER];
546 *val &= ~EFER_LMA;
547 if ( (*val & EFER_LME) && (c->cr[4] & X86_CR4_PAE) &&
548 (c->cr[0] & X86_CR0_PG) )
549 {
550 printf("Setting EFER_LMA\n");
551 *val |= EFER_LMA;
552 }
553 return X86EMUL_OKAY;
554 }
555
556 for ( idx = 0; idx < MSR_INDEX_MAX; idx++ )
557 {
558 if ( msr_index[idx] == reg )
559 {
560 *val = c->msr[idx];
561 return X86EMUL_OKAY;
562 }
563 }
564
565 x86_emul_hw_exception(13, 0, ctxt);
566 return X86EMUL_EXCEPTION;
567 }
568
fuzz_write_msr(unsigned int reg,uint64_t val,struct x86_emulate_ctxt * ctxt)569 static int fuzz_write_msr(
570 unsigned int reg,
571 uint64_t val,
572 struct x86_emulate_ctxt *ctxt)
573 {
574 struct fuzz_state *s = ctxt->data;
575 struct fuzz_corpus *c = s->corpus;
576 unsigned int idx;
577 int rc;
578
579 rc = maybe_fail(ctxt, "write_msr", true);
580 if ( rc != X86EMUL_OKAY )
581 return rc;
582
583 switch ( reg )
584 {
585 case MSR_TSC_AUX:
586 case MSR_IA32_TSC:
587 return X86EMUL_OKAY;
588 }
589
590 for ( idx = 0; idx < MSR_INDEX_MAX; idx++ )
591 {
592 if ( msr_index[idx] == reg )
593 {
594 uint64_t old = c->msr[idx];
595
596 c->msr[idx] = val;
597
598 if ( !check_state(ctxt) )
599 {
600 c->msr[idx] = old;
601 break;
602 }
603
604 return X86EMUL_OKAY;
605 }
606 }
607
608 x86_emul_hw_exception(13, 0, ctxt);
609 return X86EMUL_EXCEPTION;
610 }
611
612 #define SET(h) .h = fuzz_##h
613 static const struct x86_emulate_ops all_fuzzer_ops = {
614 SET(read),
615 SET(insn_fetch),
616 SET(write),
617 SET(cmpxchg),
618 SET(rep_ins),
619 SET(rep_outs),
620 SET(rep_movs),
621 SET(rep_stos),
622 SET(read_segment),
623 SET(write_segment),
624 SET(read_io),
625 SET(write_io),
626 SET(read_cr),
627 SET(write_cr),
628 SET(read_xcr),
629 SET(read_msr),
630 SET(write_msr),
631 SET(cache_op),
632 SET(tlb_op),
633 .get_fpu = emul_test_get_fpu,
634 .put_fpu = emul_test_put_fpu,
635 .cpuid = emul_test_cpuid,
636 };
637 #undef SET
638
setup_fpu_exception_handler(void)639 static void setup_fpu_exception_handler(void)
640 {
641 /* FIXME - just disable exceptions for now */
642 unsigned long a;
643
644 asm volatile ( "fnclex");
645 a = 0x37f; /* FCW_DEFAULT in Xen */
646 asm volatile ( "fldcw %0" :: "m" (a));
647 a = 0x1f80; /* MXCSR_DEFAULT in Xen */
648 asm volatile ( "ldmxcsr %0" :: "m" (a) );
649 }
650
dump_state(struct x86_emulate_ctxt * ctxt)651 static void dump_state(struct x86_emulate_ctxt *ctxt)
652 {
653 struct fuzz_state *s = ctxt->data;
654 const struct fuzz_corpus *c = s->corpus;
655 struct cpu_user_regs *regs = ctxt->regs;
656 uint64_t val = 0;
657
658 printf(" -- State -- \n");
659 printf("addr / sp size: %d / %d\n", ctxt->addr_size, ctxt->sp_size);
660 printf(" cr0: %lx\n", c->cr[0]);
661 printf(" cr3: %lx\n", c->cr[3]);
662 printf(" cr4: %lx\n", c->cr[4]);
663
664 printf(" rip: %"PRIx64"\n", regs->rip);
665
666 fuzz_read_msr(MSR_EFER, &val, ctxt);
667 printf("EFER: %"PRIx64"\n", val);
668 }
669
long_mode_active(struct x86_emulate_ctxt * ctxt)670 static bool long_mode_active(struct x86_emulate_ctxt *ctxt)
671 {
672 uint64_t val;
673
674 if ( fuzz_read_msr(MSR_EFER, &val, ctxt) != X86EMUL_OKAY )
675 return false;
676
677 return val & EFER_LMA;
678 }
679
in_longmode(struct x86_emulate_ctxt * ctxt)680 static bool in_longmode(struct x86_emulate_ctxt *ctxt)
681 {
682 const struct fuzz_state *s = ctxt->data;
683 const struct fuzz_corpus *c = s->corpus;
684
685 return long_mode_active(ctxt) && c->segments[x86_seg_cs].l;
686 }
687
set_sizes(struct x86_emulate_ctxt * ctxt)688 static void set_sizes(struct x86_emulate_ctxt *ctxt)
689 {
690 struct fuzz_state *s = ctxt->data;
691 const struct fuzz_corpus *c = s->corpus;
692
693 ctxt->lma = long_mode_active(ctxt);
694
695 if ( in_longmode(ctxt) )
696 ctxt->addr_size = ctxt->sp_size = 64;
697 else
698 {
699 ctxt->addr_size = c->segments[x86_seg_cs].db ? 32 : 16;
700 ctxt->sp_size = c->segments[x86_seg_ss].db ? 32 : 16;
701 }
702 }
703
704 #define CANONICALIZE(x, bits) \
705 do { \
706 uint64_t _y = (x); \
707 if ( _y & (1ULL << ((bits) - 1)) ) \
708 _y |= (~0ULL) << (bits); \
709 else \
710 _y &= (1ULL << (bits)) - 1; \
711 printf("Canonicalized %" PRIx64 " to %" PRIx64 "\n", x, _y); \
712 (x) = _y; \
713 } while( 0 )
714
715 /* Expects bitmap, regs, and c to be defined */
716 #define CANONICALIZE_MAYBE(reg) \
717 if ( !(bitmap & (1 << CANONICALIZE_##reg)) ) \
718 CANONICALIZE(regs->reg, c->cr[4] & X86_CR4_LA57 ? 57 : 48); \
719
720 enum {
721 HOOK_read,
722 HOOK_insn_fetch,
723 HOOK_write,
724 HOOK_cmpxchg,
725 HOOK_rep_ins,
726 HOOK_rep_outs,
727 HOOK_rep_movs,
728 HOOK_rep_stos,
729 HOOK_read_segment,
730 HOOK_write_segment,
731 HOOK_read_io,
732 HOOK_write_io,
733 HOOK_read_cr,
734 HOOK_write_cr,
735 HOOK_read_dr,
736 HOOK_write_dr,
737 HOOK_read_xcr,
738 HOOK_read_msr,
739 HOOK_write_msr,
740 HOOK_cache_op,
741 HOOK_tlb_op,
742 HOOK_cpuid,
743 HOOK_inject_hw_exception,
744 HOOK_inject_sw_interrupt,
745 HOOK_get_fpu,
746 HOOK_put_fpu,
747 HOOK_vmfunc,
748 CANONICALIZE_rip,
749 CANONICALIZE_rsp,
750 };
751
752 /* Expects bitmap to be defined */
753 #define MAYBE_DISABLE_HOOK(h) \
754 if ( bitmap & (1 << HOOK_##h) ) \
755 { \
756 s->ops.h = NULL; \
757 printf("Disabling hook "#h"\n"); \
758 }
759
disable_hooks(struct x86_emulate_ctxt * ctxt)760 static void disable_hooks(struct x86_emulate_ctxt *ctxt)
761 {
762 struct fuzz_state *s = ctxt->data;
763 const struct fuzz_corpus *c = s->corpus;
764 unsigned long bitmap = c->options;
765
766 /* See also sanitize_input, some hooks can't be disabled. */
767 MAYBE_DISABLE_HOOK(read);
768 MAYBE_DISABLE_HOOK(insn_fetch);
769 MAYBE_DISABLE_HOOK(write);
770 MAYBE_DISABLE_HOOK(cmpxchg);
771 MAYBE_DISABLE_HOOK(rep_ins);
772 MAYBE_DISABLE_HOOK(rep_outs);
773 MAYBE_DISABLE_HOOK(rep_movs);
774 MAYBE_DISABLE_HOOK(rep_stos);
775 MAYBE_DISABLE_HOOK(read_segment);
776 MAYBE_DISABLE_HOOK(write_segment);
777 MAYBE_DISABLE_HOOK(read_io);
778 MAYBE_DISABLE_HOOK(write_io);
779 MAYBE_DISABLE_HOOK(read_cr);
780 MAYBE_DISABLE_HOOK(write_cr);
781 MAYBE_DISABLE_HOOK(read_xcr);
782 MAYBE_DISABLE_HOOK(read_msr);
783 MAYBE_DISABLE_HOOK(write_msr);
784 MAYBE_DISABLE_HOOK(cache_op);
785 MAYBE_DISABLE_HOOK(tlb_op);
786 MAYBE_DISABLE_HOOK(cpuid);
787 MAYBE_DISABLE_HOOK(get_fpu);
788 }
789
790 /*
791 * Constrain input to architecturally-possible states where
792 * the emulator relies on these
793 *
794 * In general we want the emulator to be as absolutely robust as
795 * possible; which means that we want to minimize the number of things
796 * it assumes about the input state. Tesing this means minimizing and
797 * removing as much of the input constraints as possible.
798 *
799 * So we only add constraints that (in general) have been proven to
800 * cause crashes in the emulator.
801 *
802 * For future reference: other constraints which might be necessary at
803 * some point:
804 *
805 * - EFER.LMA => !EFLAGS.NT
806 * - In VM86 mode, force segment...
807 * - ...access rights to 0xf3
808 * - ...limits to 0xffff
809 * - ...bases to below 1Mb, 16-byte aligned
810 * - ...selectors to (base >> 4)
811 */
sanitize_input(struct x86_emulate_ctxt * ctxt)812 static void sanitize_input(struct x86_emulate_ctxt *ctxt)
813 {
814 struct fuzz_state *s = ctxt->data;
815 struct fuzz_corpus *c = s->corpus;
816 struct cpu_user_regs *regs = &c->regs;
817 unsigned long bitmap = c->options;
818
819 /* Some hooks can't be disabled. */
820 c->options &= ~((1<<HOOK_read)|(1<<HOOK_insn_fetch));
821
822 /* Zero 'private' entries */
823 regs->error_code = 0;
824 regs->entry_vector = 0;
825
826 /*
827 * For both RIP and RSP make sure we test with canonical values in at
828 * least a fair number of cases. As all other registers aren't tied to
829 * special addressing purposes, leave everything else alone.
830 */
831 CANONICALIZE_MAYBE(rip);
832 CANONICALIZE_MAYBE(rsp);
833
834 /*
835 * CR0.PG can't be set if CR0.PE isn't set. Set is more interesting, so
836 * set PE if PG is set.
837 */
838 if ( c->cr[0] & X86_CR0_PG )
839 c->cr[0] |= X86_CR0_PE;
840
841 /* EFLAGS.VM not available in long mode */
842 if ( long_mode_active(ctxt) )
843 regs->rflags &= ~X86_EFLAGS_VM;
844
845 /* EFLAGS.VM implies 16-bit mode */
846 if ( regs->rflags & X86_EFLAGS_VM )
847 {
848 c->segments[x86_seg_cs].db = 0;
849 c->segments[x86_seg_ss].db = 0;
850 }
851 }
852
853 /*
854 * Call this function from hooks potentially altering machine state into
855 * something that's not architecturally valid, yet which - as per above -
856 * the emulator relies on.
857 */
check_state(struct x86_emulate_ctxt * ctxt)858 static bool check_state(struct x86_emulate_ctxt *ctxt)
859 {
860 const struct fuzz_state *s = ctxt->data;
861 const struct fuzz_corpus *c = s->corpus;
862 const struct cpu_user_regs *regs = &c->regs;
863
864 if ( long_mode_active(ctxt) && !(c->cr[0] & X86_CR0_PG) )
865 return false;
866
867 if ( (c->cr[0] & X86_CR0_PG) && !(c->cr[0] & X86_CR0_PE) )
868 return false;
869
870 if ( (regs->rflags & X86_EFLAGS_VM) &&
871 (c->segments[x86_seg_cs].db || c->segments[x86_seg_ss].db) )
872 return false;
873
874 return true;
875 }
876
LLVMFuzzerInitialize(int * argc,char *** argv)877 int LLVMFuzzerInitialize(int *argc, char ***argv)
878 {
879 if ( !emul_test_init() )
880 {
881 printf("Warning: Stack could not be made executable (%d).\n", errno);
882 return 1;
883 }
884
885 return 0;
886 }
887
LLVMFuzzerTestOneInput(const uint8_t * data_p,size_t size)888 int LLVMFuzzerTestOneInput(const uint8_t *data_p, size_t size)
889 {
890 struct fuzz_state state = {
891 .ops = all_fuzzer_ops,
892 };
893 struct x86_emulate_ctxt ctxt = {
894 .data = &state,
895 .regs = &input.regs,
896 .addr_size = 8 * sizeof(void *),
897 .sp_size = 8 * sizeof(void *),
898 };
899 int rc;
900
901 /* Not part of the initializer, for old gcc to cope. */
902 ctxt.cpu_policy = &cp;
903
904 /* Reset all global state variables */
905 memset(&input, 0, sizeof(input));
906
907 if ( size <= DATA_OFFSET )
908 {
909 printf("Input too small\n");
910 return 1;
911 }
912
913 if ( size > FUZZ_CORPUS_SIZE )
914 {
915 printf("Input too large\n");
916 return 1;
917 }
918
919 memcpy(&input, data_p, size);
920
921 state.corpus = &input;
922 state.data_num = size - DATA_OFFSET;
923
924 sanitize_input(&ctxt);
925
926 disable_hooks(&ctxt);
927
928 do {
929 /* FIXME: Until we actually implement SIGFPE handling properly */
930 setup_fpu_exception_handler();
931
932 set_sizes(&ctxt);
933 dump_state(&ctxt);
934
935 rc = x86_emulate(&ctxt, &state.ops);
936 printf("Emulation result: %d\n", rc);
937 } while ( rc == X86EMUL_OKAY );
938
939 return 0;
940 }
941
fuzz_minimal_input_size(void)942 unsigned int fuzz_minimal_input_size(void)
943 {
944 return DATA_OFFSET + 1;
945 }
946
947 /*
948 * Local variables:
949 * mode: C
950 * c-file-style: "BSD"
951 * c-basic-offset: 4
952 * indent-tabs-mode: nil
953 * End:
954 */
955