Skip to content
This repository was archived by the owner on Jan 28, 2023. It is now read-only.

Commit 205d34f

Browse files
authored
Merge pull request #347 from intel/dr-msr
Fix some vulnerability issues of loading DRs and MSRs
2 parents a19ddbd + 42e3498 commit 205d34f

File tree

7 files changed

+175
-81
lines changed

7 files changed

+175
-81
lines changed

core/emulate.c

+24-4
Original file line numberDiff line numberDiff line change
@@ -586,28 +586,48 @@ static void register_add(struct em_context_t *ctxt,
586586

587587
static uint8_t insn_fetch_u8(struct em_context_t *ctxt)
588588
{
589-
uint8_t result = *(uint8_t *)(&ctxt->insn[ctxt->len]);
589+
uint8_t result;
590+
591+
if (ctxt->len >= INSTR_MAX_LEN)
592+
return 0;
593+
594+
result = *(uint8_t *)(&ctxt->insn[ctxt->len]);
590595
ctxt->len += 1;
591596
return result;
592597
}
593598

594599
static uint16_t insn_fetch_u16(struct em_context_t *ctxt)
595600
{
596-
uint16_t result = *(uint16_t *)(&ctxt->insn[ctxt->len]);
601+
uint16_t result;
602+
603+
if (ctxt->len >= INSTR_MAX_LEN)
604+
return 0;
605+
606+
result = *(uint16_t *)(&ctxt->insn[ctxt->len]);
597607
ctxt->len += 2;
598608
return result;
599609
}
600610

601611
static uint32_t insn_fetch_u32(struct em_context_t *ctxt)
602612
{
603-
uint32_t result = *(uint32_t *)(&ctxt->insn[ctxt->len]);
613+
uint32_t result;
614+
615+
if (ctxt->len >= INSTR_MAX_LEN)
616+
return 0;
617+
618+
result = *(uint32_t *)(&ctxt->insn[ctxt->len]);
604619
ctxt->len += 4;
605620
return result;
606621
}
607622

608623
static uint64_t insn_fetch_u64(struct em_context_t *ctxt)
609624
{
610-
uint64_t result = *(uint64_t *)(&ctxt->insn[ctxt->len]);
625+
uint64_t result;
626+
627+
if (ctxt->len >= INSTR_MAX_LEN)
628+
return 0;
629+
630+
result = *(uint64_t *)(&ctxt->insn[ctxt->len]);
611631
ctxt->len += 8;
612632
return result;
613633
}

core/hax.c

+47-38
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,44 @@ static int hax_vmx_enable_check(void)
267267
return 0;
268268
}
269269

270+
/*
271+
* Allows the guest to read from and/or write to the specified MSRs without
272+
* causing a VM exit.
273+
* |start| is the start MSR address, |count| the number of MSRs. Together they
274+
* specify a range of consecutive MSR addresses.
275+
* |read| and |write| determine if each MSR can be read or written freely by the
276+
* guest, respectively.
277+
*/
278+
static void set_msr_access(uint32_t start, uint32_t count, bool read, bool write)
279+
{
280+
uint32_t end = start + count - 1;
281+
uint32_t read_base, write_base, bit;
282+
uint8_t *msr_bitmap = hax_page_va(msr_bitmap_page);
283+
284+
hax_assert(((start ^ (start << 1)) & 0x80000000) == 0);
285+
hax_assert((start & 0x3fffe000) == 0);
286+
hax_assert(((start ^ end) & 0xffffe000) == 0);
287+
hax_assert(msr_bitmap);
288+
289+
// See IA SDM Vol. 3C 24.6.9 for the layout of the MSR bitmaps page
290+
read_base = start & 0x80000000 ? 1024 : 0;
291+
write_base = read_base + 2048;
292+
for (bit = (start & 0x1fff); bit <= (end & 0x1fff); bit++) {
293+
// Bit clear means allowed
294+
if (read) {
295+
btr(msr_bitmap + read_base, bit);
296+
} else {
297+
bts(msr_bitmap + read_base, bit);
298+
}
299+
300+
if (write) {
301+
btr(msr_bitmap + write_base, bit);
302+
} else {
303+
bts(msr_bitmap + write_base, bit);
304+
}
305+
}
306+
}
307+
270308
static int hax_vmx_init(void)
271309
{
272310
int ret = -ENOMEM;
@@ -297,6 +335,15 @@ static int hax_vmx_init(void)
297335
if ((ret = hax_vmx_enable_check()) < 0)
298336
goto out_5;
299337

338+
// Set MSRs loaded on VM entries/exits to pass-through
339+
// See Intel SDM Vol. 3C 24.6.9 (MSR-Bitmap Address)
340+
341+
// 4 consecutive MSRs starting from IA32_STAR:
342+
// IA32_STAR, IA32_LSTAR, IA32_CSTAR and IA32_SF_MASK
343+
set_msr_access(IA32_STAR, 4, true, true);
344+
set_msr_access(IA32_KERNEL_GS_BASE, 1, true, true);
345+
set_msr_access(IA32_TSC_AUX, 1, true, true);
346+
300347
return 0;
301348
out_5:
302349
hax_disable_vmx();
@@ -393,44 +440,6 @@ int hax_get_capability(void *buf, int bufLeng, int *outLength)
393440
return 0;
394441
}
395442

396-
/*
397-
* Allows the guest to read from and/or write to the specified MSRs without
398-
* causing a VM exit.
399-
* |start| is the start MSR address, |count| the number of MSRs. Together they
400-
* specify a range of consecutive MSR addresses.
401-
* |read| and |write| determine if each MSR can be read or written freely by the
402-
* guest, respectively.
403-
*/
404-
static void set_msr_access(uint32_t start, uint32_t count, bool read, bool write)
405-
{
406-
uint32_t end = start + count - 1;
407-
uint32_t read_base, write_base, bit;
408-
uint8_t *msr_bitmap = hax_page_va(msr_bitmap_page);
409-
410-
hax_assert(((start ^ (start << 1)) & 0x80000000) == 0);
411-
hax_assert((start & 0x3fffe000) == 0);
412-
hax_assert(((start ^ end) & 0xffffe000) == 0);
413-
hax_assert(msr_bitmap);
414-
415-
// See IA SDM Vol. 3C 24.6.9 for the layout of the MSR bitmaps page
416-
read_base = start & 0x80000000 ? 1024 : 0;
417-
write_base = read_base + 2048;
418-
for (bit = (start & 0x1fff); bit <= (end & 0x1fff); bit++) {
419-
// Bit clear means allowed
420-
if (read) {
421-
btr(msr_bitmap + read_base, bit);
422-
} else {
423-
bts(msr_bitmap + read_base, bit);
424-
}
425-
426-
if (write) {
427-
btr(msr_bitmap + write_base, bit);
428-
} else {
429-
bts(msr_bitmap + write_base, bit);
430-
}
431-
}
432-
}
433-
434443
/*
435444
* Probes the host CPU to determine its performance monitoring capabilities.
436445
*/

core/include/cpu.h

+7
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ struct vcpu_t;
4545
struct vcpu_state_t;
4646

4747
#define NR_HMSR 6
48+
// The number of MSRs to be loaded on VM exits
49+
// Currently the MSRs list only supports automatic loading of below MSRs, the
50+
// total count of which is 8.
51+
// * IA32_PMCx
52+
// * IA32_PERFEVTSELx
53+
#define NR_HMSR_AUTOLOAD 8
4854

4955
struct hstate {
5056
/* ldt is not covered by host vmcs area */
@@ -65,6 +71,7 @@ struct hstate {
6571
uint64_t fs_base;
6672
uint64_t hcr2;
6773
struct vmx_msr hmsr[NR_HMSR];
74+
vmx_msr_entry hmsr_autoload[NR_HMSR_AUTOLOAD];
6875
// IA32_PMCx, since APM v1
6976
uint64_t apm_pmc_msrs[APM_MAX_GENERAL_COUNT];
7077
// IA32_PERFEVTSELx, since APM v1

core/include/emulate.h

+4
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ struct em_operand_t;
9999
/* Emulator interface flags */
100100
#define EM_OPS_NO_TRANSLATION (1 << 0)
101101

102+
// Instructions are never longer than 15 bytes:
103+
// http://wiki.osdev.org/X86-64_Instruction_Encoding
104+
#define INSTR_MAX_LEN 15
105+
102106
typedef struct em_vcpu_ops_t {
103107
uint64_t (*read_gpr)(void *vcpu, uint32_t reg_index);
104108
void (*write_gpr)(void *vcpu, uint32_t reg_index, uint64_t value);

core/include/vcpu.h

+9
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,18 @@
4242

4343
#define NR_GMSR 5
4444
#define NR_EMT64MSR 6
45+
// The number of MSRs to be loaded on VM entries
46+
// Currently the MSRs list only supports automatic loading of below MSRs, the
47+
// total count of which is 14.
48+
// * IA32_PMCx
49+
// * IA32_PERFEVTSELx
50+
// * IA32_TSC_AUX
51+
// * all MSRs defined in gmsr_list[]
52+
#define NR_GMSR_AUTOLOAD 14
4553

4654
struct gstate {
4755
struct vmx_msr gmsr[NR_GMSR];
56+
vmx_msr_entry gmsr_autoload[NR_GMSR_AUTOLOAD];
4857
// IA32_PMCx, since APM v1
4958
uint64_t apm_pmc_msrs[APM_MAX_GENERAL_COUNT];
5059
// IA32_PERFEVTSELx, since APM v1

core/include/vmx.h

+6
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,12 @@ struct invept_desc {
639639
uint64_t rsvd;
640640
};
641641

642+
// Intel SDM Vol. 3C: Table 24-12. Format of an MSR Entry
643+
typedef struct ALIGNED(16) vmx_msr_entry {
644+
uint64_t index;
645+
uint64_t data;
646+
} vmx_msr_entry;
647+
642648
struct vcpu_state_t;
643649
struct vcpu_t;
644650

0 commit comments

Comments
 (0)