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