Skip to content

Commit 7dde0df

Browse files
fyin1lijinxia
authored andcommitted
hv: add GVA validation for MOVS
Unlike the other instructions we emulated, MOVS has two operands both are memory. So we need to check whether the operand is valid GVA. With VMX enabled, the src operand is always checked first by VMX. Which means if src operand is not valid GVA, it will trigger fault in guest before trigger EPT. So we don't need to check src operand. Only need to check dst operand here. Signed-off-by: Yin Fengwei <fengwei.yin@intel.com> Acked-by: Anthony Xu <anthony.xu@intel.com>
1 parent b01a812 commit 7dde0df

File tree

1 file changed

+39
-7
lines changed

1 file changed

+39
-7
lines changed

hypervisor/arch/x86/guest/instr_emul.c

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
#define VIE_OP_F_IMM8 (1U << 1) /* 8-bit immediate operand */
5656
#define VIE_OP_F_MOFFSET (1U << 2) /* 16/32/64-bit immediate moffset */
5757
#define VIE_OP_F_NO_MODRM (1U << 3)
58-
#define VIE_OP_F_NO_GLA_VERIFICATION (1U << 4)
58+
#define VIE_OP_F_CHECK_GVA_DI (1U << 4) /* for movs, need to check DI */
5959

6060
static const struct instr_emul_vie_op two_byte_opcodes[256] = {
6161
[0xB6] = {
@@ -108,19 +108,19 @@ static const struct instr_emul_vie_op one_byte_opcodes[256] = {
108108
},
109109
[0xA4] = {
110110
.op_type = VIE_OP_TYPE_MOVS,
111-
.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION
111+
.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_CHECK_GVA_DI
112112
},
113113
[0xA5] = {
114114
.op_type = VIE_OP_TYPE_MOVS,
115-
.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION
115+
.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_CHECK_GVA_DI
116116
},
117117
[0xAA] = {
118118
.op_type = VIE_OP_TYPE_STOS,
119-
.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION
119+
.op_flags = VIE_OP_F_NO_MODRM
120120
},
121121
[0xAB] = {
122122
.op_type = VIE_OP_TYPE_STOS,
123-
.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION
123+
.op_flags = VIE_OP_F_NO_MODRM
124124
},
125125
[0xC6] = {
126126
/* XXX Group 11 extended opcode - not just MOV */
@@ -953,7 +953,7 @@ static int emulate_movs(struct vcpu *vcpu, struct instr_emul_vie *vie)
953953
{
954954
uint64_t dstaddr, srcaddr;
955955
uint64_t rcx, rdi, rsi, rflags;
956-
int error, fault, repeat;
956+
int error, repeat;
957957
uint8_t opsize;
958958
enum cpu_reg_name seg;
959959

@@ -1533,7 +1533,6 @@ static int emulate_bittest(struct vcpu *vcpu, struct instr_emul_vie *vie)
15331533

15341534
static int vmm_emulate_instruction(struct instr_emul_ctxt *ctxt)
15351535
{
1536-
struct vm_guest_paging *paging = &ctxt->paging;
15371536
struct instr_emul_vie *vie = &ctxt->vie;
15381537
struct vcpu *vcpu = ctxt->vcpu;
15391538
int error;
@@ -2123,6 +2122,22 @@ static int local_decode_instruction(enum vm_cpu_mode cpu_mode,
21232122
return 0;
21242123
}
21252124

2125+
/* for instruction MOVS/STO, check the gva gotten from DI/SI. */
2126+
static int instr_check_di(struct vcpu *vcpu, struct instr_emul_ctxt *emul_ctxt)
2127+
{
2128+
int ret;
2129+
struct instr_emul_vie *vie = &emul_ctxt->vie;
2130+
uint64_t gva;
2131+
enum cpu_reg_name seg;
2132+
2133+
ret = get_gva_di_si_check(vcpu, vie->addrsize, PROT_WRITE,
2134+
CPU_REG_ES, CPU_REG_RDI, &gva);
2135+
2136+
if (ret < 0) {
2137+
return -EFAULT;
2138+
}
2139+
}
2140+
21262141
int decode_instruction(struct vcpu *vcpu)
21272142
{
21282143
struct instr_emul_ctxt *emul_ctxt;
@@ -2160,6 +2175,23 @@ int decode_instruction(struct vcpu *vcpu)
21602175
return -EFAULT;
21612176
}
21622177

2178+
/*
2179+
* We do operand check in instruction decode phase and
2180+
* inject exception accordingly. In late instruction
2181+
* emulation, it will always sucess.
2182+
*
2183+
* We only need to do dst check for movs. For other instructions,
2184+
* they always has one register and one mmio which trigger EPT
2185+
* by access mmio. With VMX enabled, the related check is done
2186+
* by VMX itself before hit EPT violation.
2187+
*
2188+
*/
2189+
if (emul_ctxt->vie.op.op_flags & VIE_OP_F_CHECK_GVA_DI) {
2190+
retval = instr_check_di(vcpu, emul_ctxt);
2191+
if (retval < 0)
2192+
return retval;
2193+
}
2194+
21632195
return emul_ctxt->vie.opsize;
21642196
}
21652197

0 commit comments

Comments
 (0)