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