Bitdefender Hypervisor Memory Introspection
swapgs.c File Reference

This file contains a workaround for the CVE-2019-1125 vulnerability. More...

#include "swapgs.h"
#include "guests.h"
#include "icache.h"
#include "memcloak.h"
#include "slack.h"
#include "winpe.h"

Go to the source code of this file.

Data Structures

struct  _SWAPGS_HANDLER
 
struct  _SWAPGS_GADGET
 

Typedefs

typedef struct _SWAPGS_HANDLER SWAPGS_HANDLER
 
typedef struct _SWAPGS_GADGET SWAPGS_GADGET
 
typedef enum _SWAPGS_SSTATE SWAPGS_SSTATE
 

Enumerations

enum  _SWAPGS_SSTATE {
  swapgsSstateNone = 0, swapgsSstateJcc, swapgsSstatePush, swapgsSstateSwapgs,
  swapgsSstateGsBasedAccess
}
 

Functions

static SWAPGS_HANDLERIntSwapgsInstallHandler (QWORD Section, BYTE Instruction[16], BYTE Length)
 Install a handler for a given instruction. More...
 
INTSTATUS IntSwapgsStartMitigation (void)
 Scan the kernel for vulnerable SWAPGS gadgets, and mitigate CVE-2019-1125, when such gadgets are found. More...
 
void IntSwapgsUninit (void)
 Uninit the SWAPGS mitigation. More...
 
void IntSwapgsDisable (void)
 Disable SWAPGS mitigations. Must be used only for PrepareUninit. More...
 
BOOLEAN IntSwapgsIsPtrInHandler (QWORD Ptr, THS_PTR_TYPE Type, QWORD *Gadget)
 Check if a pointer points inside a SWAPGS handler. More...
 
QWORD IntSwapgsRelocatePtrIfNeeded (QWORD Ptr)
 Relocate a pointer if it points inside a SWAPGS gadget, and make it point inside the installed handler. More...
 

Variables

LIST_HEAD gGadgets = LIST_HEAD_INIT(gGadgets)
 List of all the hooked gadgets. More...
 
LIST_HEAD gHandlers = LIST_HEAD_INIT(gHandlers)
 List of all distinct handlers. More...
 
BOOLEAN gMitigated
 TRUE if we mitigated the SWAPGS issue. More...
 

Detailed Description

This file contains a workaround for the CVE-2019-1125 vulnerability.

Since we have discovered the SWAPGS attack (CVE-2019-1125), we were able to provide a workaround, directly inside the introspection engine, in order to mitigate the vulnerability. The way this works is by simply serializing all the SWAPGS gadgets that are vulnerable. Note that we focus mainly on SWAPGS variant 2, which is the more dangerous form - executing the SWAPGS instruction even if it shouldn't.

IMPORTANT 1: All SWAPGS instructions lie in .text or KVASCODE sections, which are non-paged! IMPORTANT 2: All gadgets are followed by GS based addressing, which simplified hooking! IMPORTANT 3: Gadgets which are located inside the KVASCODE section must be relocated inside the same section. The reason is that under KPTI, only KVASCODE section is mapped in user-mode, and the CR3 switch takes place in that section. If we place the handler in the .text section, the handler would execute before switching the CR3, and it would cause a triple-fault in guest.

Definition in file swapgs.c.

Typedef Documentation

◆ SWAPGS_GADGET

typedef struct _SWAPGS_GADGET SWAPGS_GADGET

Describes one intercepted gadget. Unlike the template, this describes each intercepted vulnerable code sequence. Multiple such gadgets may be handled by a single SWAPGS_HANDLER.

◆ SWAPGS_HANDLER

Describes one SWAPGS handler. A SWAPGS handler may be shared by multiple SWAPGS gadgets.

◆ SWAPGS_SSTATE

SWAPGS gadget state.

Enumeration Type Documentation

◆ _SWAPGS_SSTATE

SWAPGS gadget state.

Enumerator
swapgsSstateNone 

No state, just started scanning.

swapgsSstateJcc 

A conditional jump was found.

swapgsSstatePush 

A PUSH was found.

swapgsSstateSwapgs 

The SWAPGS instruction was found.

swapgsSstateGsBasedAccess 

A GS based addressing instruction was found. This is where we start instrumenting.

Definition at line 178 of file swapgs.c.

Function Documentation

◆ IntSwapgsDisable()

void IntSwapgsDisable ( void  )

Disable SWAPGS mitigations. Must be used only for PrepareUninit.

Definition at line 501 of file swapgs.c.

Referenced by IntGuestPrepareUninit().

◆ IntSwapgsInstallHandler()

static SWAPGS_HANDLER* IntSwapgsInstallHandler ( QWORD  Section,
BYTE  Instruction[16],
BYTE  Length 
)
static

Install a handler for a given instruction.

This function searched for a handler for the specified instruction (which follows SWAPGS). If one is found, it will be installed as a mitigation handler for the identified gadget. Otherwise, a new handler will be allocated. The handler is very simple: LFENCE Instruction PUSHFQ ADD [rsp + 8], Length POPFQ RETN

Parameters
[in]SectionThe section inside NT of the required handler (.text or KVASCODE)
[in]InstructionInstruction bytes of the instruction following the SWAPGS (must be GS based addressing).
[in]LengthLength of the identified instruction.
Return values
Thehandler installed for this instruction.

Definition at line 70 of file swapgs.c.

Referenced by IntSwapgsStartMitigation().

◆ IntSwapgsIsPtrInHandler()

BOOLEAN IntSwapgsIsPtrInHandler ( QWORD  Ptr,
THS_PTR_TYPE  Type,
QWORD Gadget 
)

Check if a pointer points inside a SWAPGS handler.

Parameters
[in]PtrThe pointer to be checked.
[in]TypeLive RIP or stack value.
[out]GadgetThe gadget address, if any is found, or NULL otherwise.
Return values
Trueif the Ptr points inside a gadget, false otherwise.

Definition at line 531 of file swapgs.c.

Referenced by IntThrSafeIsLiveRIPInIntro(), and IntThrSafeIsStackPtrInIntro().

◆ IntSwapgsRelocatePtrIfNeeded()

QWORD IntSwapgsRelocatePtrIfNeeded ( QWORD  Ptr)

Relocate a pointer if it points inside a SWAPGS gadget, and make it point inside the installed handler.

Parameters
[in]PtrThe pointer to be checked.
Return values
Thenew value for the pointer, if it was relocated.

Definition at line 579 of file swapgs.c.

Referenced by IntThrSafeMoveReturn(), and IntThrSafeMoveRip().

◆ IntSwapgsStartMitigation()

INTSTATUS IntSwapgsStartMitigation ( void  )

Scan the kernel for vulnerable SWAPGS gadgets, and mitigate CVE-2019-1125, when such gadgets are found.

This function scans the NT image (.text and KVASCODE sections) for code sequences that are vulnerable to SWAPGS variant 2. When such a sequence is found, it will replace the first GS based access after the SWAPGS with a JMP to a small handler installed inside the NT slack space, which will simply serialize execution using LFENCE. Example: Considering the sequence: TEST [mem], imm JZ skip_swapgs SWAPGS skip_swapgs: MOV r10, gs:[0x188] ... we will replace the "MOV r10, gs:[0x188]" instruction with a "CALL" to a handler installed inside the slack space, which will force a "LFENCE" before actually doing the GS based addressing. NOTE: This scanning & instrumentation is done with the VCPUs paused.

Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_NEEDED_HINTIf KPTI is not active, or if the guest is not x64, or if it is not Windows.
INT_STATUS_INVALID_INTERNAL_STATEIf the NT image headers are corrupt.
INT_STATUS_NOT_SUPPORTEDIf a handler cannot be installed.
INT_STATUS_INSUFFICIENT_RESOURCESIf a memory alloc fails.

Definition at line 190 of file swapgs.c.

Referenced by DbgMitigateSwapgs(), and IntWinGuestFinishInit().

◆ IntSwapgsUninit()

void IntSwapgsUninit ( void  )

Uninit the SWAPGS mitigation.

All gadgets will be restored, making the OS vulnerable again.

Definition at line 446 of file swapgs.c.

Referenced by DbgMitigateSwapgs(), and IntGuestUninit().

Variable Documentation

◆ gGadgets

LIST_HEAD gGadgets = LIST_HEAD_INIT(gGadgets)

List of all the hooked gadgets.

Definition at line 60 of file swapgs.c.

◆ gHandlers

LIST_HEAD gHandlers = LIST_HEAD_INIT(gHandlers)

List of all distinct handlers.

Definition at line 63 of file swapgs.c.

◆ gMitigated

BOOLEAN gMitigated

TRUE if we mitigated the SWAPGS issue.

Definition at line 66 of file swapgs.c.

Referenced by IntSwapgsStartMitigation(), and IntSwapgsUninit().