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