LCOV - code coverage report
Current view: top level - x86_instruction_emulator - fuzz-emul.c (source / functions) Hit Total Coverage
Test: trace.lcov_info_final Lines: 256 263 97.3 %
Date: 2017-04-07 10:24:39 Functions: 31 32 96.9 %

          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 = &regs,
     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             :  */

Generated by: LCOV version 1.11