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