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