Exemple #1
0
VOID
SetIdtr (
	IN     IDT_BASE_LIMIT *IdtInfo,
	IN OUT AMD_CONFIG_PARAMS *StdHeaderPtr
	)
{
	__lidt (IdtInfo);
}
Exemple #2
0
// VMCALL
_Use_decl_annotations_ static void VmmpHandleVmCall(
    GuestContext *guest_context) {
  // VMCALL for Sushi expects that cx holds a command number, and dx holds an
  // address of a context parameter optionally
  const auto hypercall_number = guest_context->gp_regs->cx;
  const auto context = reinterpret_cast<void *>(guest_context->gp_regs->dx);

  if (hypercall_number == kHyperPlatformVmmBackdoorCode) {
    // Unloading requested
    HYPERPLATFORM_COMMON_DBG_BREAK();

    // The processor sets ffff to limits of IDT and GDT when VM-exit occurred.
    // It is not correct value but fine to ignore since vmresume loads correct
    // values from VMCS. But here, we are going to skip vmresume and simply
    // return to where VMCALL is executed. It results in keeping those broken
    // values and ends up with bug check 109, so we should fix them manually.
    const auto gdt_limit = UtilVmRead(VmcsField::kGuestGdtrLimit);
    const auto gdt_base = UtilVmRead(VmcsField::kGuestGdtrBase);
    const auto idt_limit = UtilVmRead(VmcsField::kGuestIdtrLimit);
    const auto idt_base = UtilVmRead(VmcsField::kGuestIdtrBase);
    Gdtr gdtr = {static_cast<USHORT>(gdt_limit), gdt_base};
    Idtr idtr = {static_cast<USHORT>(idt_limit), idt_base};
    __lgdt(&gdtr);
    __lidt(&idtr);

    // Store an address of the management structure to the context parameter
    const auto result_ptr = reinterpret_cast<ProcessorData **>(context);
    *result_ptr = guest_context->stack->processor_data;
    HYPERPLATFORM_LOG_DEBUG_SAFE("Context at %p %p", context,
                                 guest_context->stack->processor_data);

    // Set rip to the next instruction of VMCALL
    const auto exit_instruction_length =
        UtilVmRead(VmcsField::kVmExitInstructionLen);
    const auto return_address = guest_context->ip + exit_instruction_length;

    // Since rflags is overwritten after VMXOFF, we should manually indicates
    // that VMCALL was successful by clearing those flags.
    guest_context->flag_reg.fields.cf = false;
    guest_context->flag_reg.fields.zf = false;

    // Set registers used after VMXOFF to recover the context. Volatile
    // registers must be used because those changes are reflected to the
    // guest's context after VMXOFF.
    guest_context->gp_regs->cx = return_address;
    guest_context->gp_regs->dx = guest_context->gp_regs->sp;
    guest_context->gp_regs->ax = guest_context->flag_reg.all;
    guest_context->vm_continue = false;

    UtilInveptAll();

  } else {
    // Unsupported hypercall. Handle like other VMX instructions
    VmmpHandleVmx(guest_context);
  }
}
Exemple #3
0
// Modifies IDTL so that PatchGuard fires soon.
_Use_decl_annotations_ NTSTATUS GMonInstallPatchCallback(void *context) {
  UNREFERENCED_PARAMETER(context);

  Idtr idt = {};
  __sidt(&idt);
  const auto old_limit = idt.limit;
  idt.limit = 0xffff;
  __lidt(&idt);
  __sidt(&idt);
  HYPERPLATFORM_LOG_INFO("Patched IDTL %04hx => %04hx", old_limit, idt.limit);
  return STATUS_SUCCESS;
}
Exemple #4
0
DECLSPEC_NORETURN
EXTERN_C
VOID
ShvVmxEntryHandler (
    _In_ PCONTEXT Context
    )
{
    SHV_VP_STATE guestContext;
    PSHV_VP_DATA vpData;

    //
    // Because we run with interrupts disabled during the entire hypervisor's
    // exit handling, raise the IRQL to HIGH_LEVEL which matches the reality of
    // the situation. This will block IPIs and the clock interrupt timer, which
    // means that it's critical to spend as little time here as possible. You
    // can expect CLOCK_WATCHDOG_TIMEOUT bugchecks to happen otherwise. If you
    // chose to enable interrupts note that this will result in further crashes
    // as we are not on a correct OS stack, and you will be hitting crashes if
    // RtlpCheckStackLimits is ever called, or if PatchGuard validates the RSP
    // value.
    //
    KeRaiseIrql(HIGH_LEVEL, &guestContext.GuestIrql);

    //
    // Because we had to use RCX when calling RtlCaptureContext, its true value
    // was actually pushed on the stack right before the call. Go dig into the
    // stack to find it, and overwrite the bogus value that's there now.
    //
    Context->Rcx = *(PULONG64)((ULONG_PTR)Context - sizeof(Context->Rcx));

    //
    // Get the per-VP data for this processor.
    //
    vpData = &ShvGlobalData->VpData[KeGetCurrentProcessorNumberEx(NULL)];

    //
    // Build a little stack context to make it easier to keep track of certain
    // guest state, such as the RIP/RSP/RFLAGS, and the exit reason. The rest
    // of the general purpose registers come from the context structure that we
    // captured on our own with RtlCaptureContext in the assembly entrypoint.
    //
    guestContext.GuestEFlags = ShvVmxRead(GUEST_RFLAGS);
    guestContext.GuestRip = ShvVmxRead(GUEST_RIP);
    guestContext.GuestRsp = ShvVmxRead(GUEST_RSP);
    guestContext.ExitReason = ShvVmxRead(VM_EXIT_REASON) & 0xFFFF;
    guestContext.VpRegs = Context;
    guestContext.ExitVm = FALSE;

    //
    // Call the generic handler
    //
    ShvVmxHandleExit(&guestContext);

    //
    // Did we hit the magic exit sequence, or should we resume back to the VM
    // context?
    //
    if (guestContext.ExitVm)
    {
        //
        // When running in VMX root mode, the processor will set limits of the
        // GDT and IDT to 0xFFFF (notice that there are no Host VMCS fields to
        // set these values). This causes problems with PatchGuard, which will
        // believe that the GDTR and IDTR have been modified by malware, and
        // eventually crash the system. Since we know what the original state
        // of the GDTR and IDTR was, simply restore it now.
        //
        __lgdt(&vpData->HostState.SpecialRegisters.Gdtr.Limit);
        __lidt(&vpData->HostState.SpecialRegisters.Idtr.Limit);

        //
        // Our DPC routine may have interrupted an arbitrary user process, and
        // not an idle or system thread as usually happens on an idle system.
        // Therefore if we return back to the original caller after turning off
        // VMX, it will keep our current "host" CR3 value which we set on entry
        // to the PML4 of the SYSTEM process. We want to return back with the
        // correct value of the "guest" CR3, so that the currently executing
        // process continues to run with its expected address space mappings.
        //
        __writecr3(ShvVmxRead(GUEST_CR3));

        //
        // Finally, set the stack and instruction pointer to whatever location
        // had the instruction causing our VM-Exit, such as ShvVpUninitialize.
        // This will effectively act as a longjmp back to that location.
        //
        Context->Rsp = guestContext.GuestRsp;
        Context->Rip = (ULONG64)guestContext.GuestRip;

        //
        // Turn off VMX root mode on this logical processor. We're done here.
        //
        __vmx_off();
    }
    else
    {
        //
        // Because we won't be returning back into assembly code, nothing will
        // ever know about the "pop rcx" that must technically be done (or more
        // accurately "add rsp, 4" as rcx will already be correct thanks to the
        // fixup earlier. In order to keep the stack sane, do that adjustment
        // here.
        //
        Context->Rsp += sizeof(Context->Rcx);

        //
        // Return into a VMXRESUME intrinsic, which we broke out as its own
        // function, in order to allow this to work. No assembly code will be
        // needed as RtlRestoreContext will fix all the GPRs, and what we just
        // did to RSP will take care of the rest.
        //
        Context->Rip = (ULONG64)ShvVmxResume;
    }

    //
    // Restore the IRQL back to the original level
    //
    KeLowerIrql(guestContext.GuestIrql);

    //
    // Restore the context to either ShvVmxResume, in which case the CPU's VMX
    // facility will do the "true" return back to the VM (but without restoring
    // GPRs, which is why we must do it here), or to the original guest's RIP,
    // which we use in case an exit was requested. In this case VMX must now be
    // off, and this will look like a longjmp to the original stack and RIP.
    //
    RtlRestoreContext(Context, NULL);
}