|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v2 10/12] fuzz/x86emul: update fuzzer
On Tue, Jan 31, 2017 at 06:33:11AM -0700, Jan Beulich wrote:
> >>> On 31.01.17 at 12:08, <wei.liu2@xxxxxxxxxx> wrote:
> > @@ -16,26 +17,79 @@
> >
> > #include "x86_emulate.h"
> >
> > -static unsigned char data[4096];
> > +#include "../../../xen/include/asm-x86/msr-index.h"
> > +
> > +#define MSR_INDEX_MAX 16
> > +
> > +#define SEG_NUM x86_seg_none
> > +
> > +struct input_struct {
> > + unsigned long cr[5];
> > + uint64_t msr[MSR_INDEX_MAX];
> > + struct cpu_user_regs regs;
> > + struct segment_register segments[SEG_NUM];
> > + unsigned long options;
> > + unsigned char data[4096];
> > +} input;
> > +#define DATA_OFFSET offsetof(struct input_struct, data)
> > static unsigned int data_index;
> > -static unsigned int data_max;
> > +static unsigned int data_num;
> > +
> > +/* Randomly return success or failure when processing data. If
> > + * `exception` is false, this function turns _EXCEPTION to _OKAY.
> > + */
>
> I'm not sure what coding style is to apply here, but if I consider this
> an extension to the insn emulator harness, which in turn is covered
> by hypervisor style, then the comment here needs /* to go on a
> separate line.
>
Fixed.
> > +int maybe_fail(const char *why, bool exception)
> > +{
> > + int rc;
> > +
> > + if ( data_index + 1 > data_num )
>
> "data_index >= data_num" would be the more conventional way
> to express this.
>
Fixed.
> > +static int _fuzz_rep_read(const char *why, unsigned long *reps)
> > +{
> > + int rc;
> > + unsigned long bytes_read = 0;
> > +
> > + rc = data_read(why, &bytes_read, sizeof(bytes_read));
> > +
> > + if ( bytes_read < *reps )
> > + *reps -= bytes_read;
>
> I don't understand this: In the success case, *reps upon return
> indicates the number of iterations done, not the number of
> iterations left. So at least the variable naming deserves
> improvement.
>
OK, so this should be *reps = bytes_read.
> > + /* Indicate we haven't done any work if emulation has failed */
> > + if ( rc != X86EMUL_OKAY )
> > + *reps = 0;
>
> That'll result in some code paths never taken. I'd suggest clearing
> to zero only in the UNHANDLEABLE case, and simply halving the
> amount for EXCEPTION or RETRY (granted the latter can't occur
> right now), or even using input data too for determining the new
> value.
>
No problem. This function is now like:
static int _fuzz_rep_read(const char *why, unsigned long *reps)
{
int rc;
unsigned long bytes_read = 0;
rc = data_read(why, &bytes_read, sizeof(bytes_read));
if ( bytes_read < *reps )
*reps = bytes_read;
switch ( rc )
{
case X86EMUL_UNHANDLEABLE:
*reps = 0;
break;
case X86EMUL_EXCEPTION:
case X86EMUL_RETRY:
*reps /= 2;
}
return rc;
}
And I will do the same to rep_write.
> > +static int 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)
> > +{
> > + return _fuzz_rep_read("rep_in", reps);
>
> "rep_ins"
>
Fixed.
> > +static int fuzz_cpuid(
> > + uint32_t leaf,
> > + uint32_t subleaf,
> > + struct cpuid_leaf *res,
> > + struct x86_emulate_ctxt *ctxt)
> > +{
> > + return emul_test_cpuid(leaf, subleaf, res, ctxt);
> > +}
>
> I don't think you need this wrapper anymore. For the purpose of
> SET() below a simple #define will do.
>
Fixed.
> > +static int fuzz_read_segment(
> > + enum x86_segment seg,
> > + struct segment_register *reg,
> > + struct x86_emulate_ctxt *ctxt)
> > +{
> > + int rc;
> > +
> > + if ( seg > SEG_NUM )
> > + return X86EMUL_UNHANDLEABLE;
>
> As said before - this wants to be >= (even more so with
> input.segments only having SEG_NUM elements).
>
Done, and fixed write_segment too.
> > + rc = maybe_fail("read_segment", true);
> > +
> > + if ( rc == X86EMUL_OKAY )
> > + memcpy(reg, input.segments+seg, sizeof(struct segment_register));
>
> Please prefer (type safe) structure assignment.
>
> > +static int fuzz_read_cr(
> > + unsigned int reg,
> > + unsigned long *val,
> > + struct x86_emulate_ctxt *ctxt)
> > +{
> > + int rc;
> > +
> > + if ( reg > ARRAY_SIZE(input.cr) )
> > + return X86EMUL_UNHANDLEABLE;
>
> >= again.
>
Done, and fixed write_cr.
> > +enum {
> > + MSRI_IA32_SYSENTER_CS,
> > + MSRI_IA32_SYSENTER_ESP,
> > + MSRI_IA32_SYSENTER_EIP,
> > + MSRI_EFER,
> > + MSRI_STAR,
> > + MSRI_LSTAR,
> > + MSRI_CSTAR,
> > + MSRI_SYSCALL_MASK
> > +};
> > +
> > +const static unsigned int msr_index[MSR_INDEX_MAX] = {
>
> Conventionally static comes first (as not being part of the type).
>
Done.
> > +static int fuzz_read_msr(
> > + unsigned int reg,
> > + uint64_t *val,
> > + struct x86_emulate_ctxt *ctxt) {
> > + int rc;
> > +
> > + rc = maybe_fail("read_msr", true);
> > + if ( rc != X86EMUL_OKAY )
> > + return rc;
> > + else
>
> No need for "else".
>
Done.
> > +static void setup_fpu_exception_handler(void)
> > +{
> > + /* FIXME - just disable exceptions for now */
> > + unsigned long a;
> > +
> > + asm volatile ( "fnclex");
> > + a=0x37f; /* FCW_DEFAULT in Xen */
> > + asm volatile ( "fldcw %0" :: "m" (a));
> > + a=0x1f80; /* MXCSR_DEFAULT in Xen */
> > + asm volatile ( "ldmxcsr %0" :: "m" (a) );
> > +}
>
> While I see that the FCW value has changed, the strange local
> variable is still there. If you really want to keep it, please at least
> add the missing spaces around the = signs. But I'd prefer
>
> asm volatile ( "fldcw %0" :: "m" (0x37f /* FCW_DEFAULT in Xen */));
> asm volatile ( "ldmxcsr %0" :: "m" (0x1f80 /* MXCSR_DEFAULT in Xen */) );
>
This doesn't work.
x86-insn-emulator-fuzzer.c:445:5: error: memory input 0 is not directly
addressable
That's why I kept the local variable. But I will add spaces around =.
> And then - doesn't the ABI require these settings to be in effect
> upon program startup anyway?
>
I'm not sure about this -- reading AMD64 ABI Draft 0.99.8 doesn't reveal
much for me. But having the code arranged like this hasn't caused any
SIGFPE so far.
What do you suggest I do here?
> > +/*
> > + * Constrain input to architecturally-possible states where
> > + * the emulator relies on these
> > + *
> > + * In general we want the emulator to be as absolutely robust as
> > + * possible; which means that we want to minimize the number of things
> > + * it assumes about the input state. Tesing this means minimizing and
> > + * removing as much of the input constraints as possible.
> > + *
> > + * So we only add constraints that (in general) have been proven to
> > + * cause crashes in the emulator.
> > + *
> > + * For future reference: other constraints which might be necessary at
> > + * some point:
> > + *
> > + * - EFER.LMA => !EFLAGS.NT
> > + * - In VM86 mode (and real mode?), force segment...
>
> As asked for before - please drop the mentioning of real mode here.
Done.
>
> > +void sanitize_input(struct x86_emulate_ctxt *ctxt) {
> > + struct cpu_user_regs *regs = &input.regs;
> > + unsigned long bitmap = input.options;
> > +
> > + /* Some hooks can't be disabled. */
> > + input.options &= ~((1<<HOOK_read)|(1<<HOOK_insn_fetch));
> > +
> > + /* Zero 'private' entries */
> > + regs->error_code = 0;
> > + regs->entry_vector = 0;
> > +
> > + CANONICALIZE_MAYBE(rip);
> > + CANONICALIZE_MAYBE(rsp);
> > + CANONICALIZE_MAYBE(rbp);
> > +
> > + /*
> > + * CR0.PG can't be set if CR0.PE isn't set. Set is more interesting,
> > so
> > + * set PE if PG is set.
> > + */
> > + if ( input.cr[0] & X86_CR0_PG )
> > + input.cr[0] |= X86_CR0_PE;
> > +
> > + /*
> > + * EFLAGS.VM not available in long mode
> > + */
> > + if ( long_mode_active(ctxt) )
> > + regs->rflags &= ~X86_EFLAGS_VM;
> > +
> > + /*
> > + * EFLAGS.VM implies 16-bit mode
> > + */
>
> Both of these are single line comments.
Done.
>
> > do {
> > + /* FIXME: Until we actually implement SIGFPE handling properly */
> > + setup_fpu_exception_handler();
>
> I don't think the comment is appropriate here - all that needs fixing is
> the body of that function (which iirc already has a respective comment).
>
Deleted this comment.
> Jan
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |