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