target/i386: Assert CPL is 3 for user-only

A user-mode executable always runs in ring 3.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20210514151342.384376-8-richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2021-05-14 10:12:59 -05:00
parent d75f912927
commit 01b9d8c1b2

View file

@ -94,6 +94,11 @@ typedef struct DisasContext {
target_ulong pc; /* pc = eip + cs_base */ target_ulong pc; /* pc = eip + cs_base */
/* current block context */ /* current block context */
target_ulong cs_base; /* base of CS segment */ target_ulong cs_base; /* base of CS segment */
#ifndef CONFIG_USER_ONLY
uint8_t cpl; /* code priv level */
#endif
int code32; /* 32 bit code segment */ int code32; /* 32 bit code segment */
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
int lma; /* long mode active */ int lma; /* long mode active */
@ -111,7 +116,6 @@ typedef struct DisasContext {
int addseg; /* non zero if either DS/ES/SS have a non zero base */ int addseg; /* non zero if either DS/ES/SS have a non zero base */
int f_st; /* currently unused */ int f_st; /* currently unused */
int vm86; /* vm86 mode */ int vm86; /* vm86 mode */
int cpl;
int iopl; int iopl;
int tf; /* TF cpu flag */ int tf; /* TF cpu flag */
int jmp_opt; /* use direct block chaining for direct jumps */ int jmp_opt; /* use direct block chaining for direct jumps */
@ -148,8 +152,10 @@ typedef struct DisasContext {
/* The environment in which user-only runs is constrained. */ /* The environment in which user-only runs is constrained. */
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
#define PE(S) true #define PE(S) true
#define CPL(S) 3
#else #else
#define PE(S) (((S)->flags & HF_PE_MASK) != 0) #define PE(S) (((S)->flags & HF_PE_MASK) != 0)
#define CPL(S) ((S)->cpl)
#endif #endif
static void gen_eob(DisasContext *s); static void gen_eob(DisasContext *s);
@ -623,7 +629,7 @@ static void gen_check_io(DisasContext *s, MemOp ot, target_ulong cur_eip,
{ {
target_ulong next_eip; target_ulong next_eip;
if (PE(s) && (s->cpl > s->iopl || s->vm86)) { if (PE(s) && (CPL(s) > s->iopl || s->vm86)) {
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
switch (ot) { switch (ot) {
case MO_8: case MO_8:
@ -1291,7 +1297,7 @@ static void gen_exception_gpf(DisasContext *s)
/* Check for cpl == 0; if not, raise #GP and return false. */ /* Check for cpl == 0; if not, raise #GP and return false. */
static bool check_cpl0(DisasContext *s) static bool check_cpl0(DisasContext *s)
{ {
if (s->cpl == 0) { if (CPL(s) == 0) {
return true; return true;
} }
gen_exception_gpf(s); gen_exception_gpf(s);
@ -1311,7 +1317,7 @@ static bool check_vm86_iopl(DisasContext *s)
/* Check for iopl allowing access; if not, raise #GP and return false. */ /* Check for iopl allowing access; if not, raise #GP and return false. */
static bool check_iopl(DisasContext *s) static bool check_iopl(DisasContext *s)
{ {
if (s->vm86 ? s->iopl == 3 : s->cpl <= s->iopl) { if (s->vm86 ? s->iopl == 3 : CPL(s) <= s->iopl) {
return true; return true;
} }
gen_exception_gpf(s); gen_exception_gpf(s);
@ -6735,7 +6741,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF); gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF);
if (check_vm86_iopl(s)) { if (check_vm86_iopl(s)) {
ot = gen_pop_T0(s); ot = gen_pop_T0(s);
if (s->cpl == 0) { if (CPL(s) == 0) {
if (dflag != MO_16) { if (dflag != MO_16) {
gen_helper_write_eflags(cpu_env, s->T0, gen_helper_write_eflags(cpu_env, s->T0,
tcg_const_i32((TF_MASK | AC_MASK | tcg_const_i32((TF_MASK | AC_MASK |
@ -6750,7 +6756,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
& 0xffff)); & 0xffff));
} }
} else { } else {
if (s->cpl <= s->iopl) { if (CPL(s) <= s->iopl) {
if (dflag != MO_16) { if (dflag != MO_16) {
gen_helper_write_eflags(cpu_env, s->T0, gen_helper_write_eflags(cpu_env, s->T0,
tcg_const_i32((TF_MASK | tcg_const_i32((TF_MASK |
@ -7380,7 +7386,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break; break;
case 0xc8: /* monitor */ case 0xc8: /* monitor */
if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) { if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || CPL(s) != 0) {
goto illegal_op; goto illegal_op;
} }
gen_update_cc_op(s); gen_update_cc_op(s);
@ -7392,7 +7398,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break; break;
case 0xc9: /* mwait */ case 0xc9: /* mwait */
if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) { if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || CPL(s) != 0) {
goto illegal_op; goto illegal_op;
} }
gen_update_cc_op(s); gen_update_cc_op(s);
@ -7403,7 +7409,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0xca: /* clac */ case 0xca: /* clac */
if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP) if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)
|| s->cpl != 0) { || CPL(s) != 0) {
goto illegal_op; goto illegal_op;
} }
gen_helper_clac(cpu_env); gen_helper_clac(cpu_env);
@ -7413,7 +7419,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0xcb: /* stac */ case 0xcb: /* stac */
if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP) if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)
|| s->cpl != 0) { || CPL(s) != 0) {
goto illegal_op; goto illegal_op;
} }
gen_helper_stac(cpu_env); gen_helper_stac(cpu_env);
@ -8467,19 +8473,23 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
DisasContext *dc = container_of(dcbase, DisasContext, base); DisasContext *dc = container_of(dcbase, DisasContext, base);
CPUX86State *env = cpu->env_ptr; CPUX86State *env = cpu->env_ptr;
uint32_t flags = dc->base.tb->flags; uint32_t flags = dc->base.tb->flags;
int cpl = (flags >> HF_CPL_SHIFT) & 3;
dc->cs_base = dc->base.tb->cs_base; dc->cs_base = dc->base.tb->cs_base;
dc->flags = flags; dc->flags = flags;
#ifndef CONFIG_USER_ONLY
dc->cpl = cpl;
#endif
/* We make some simplifying assumptions; validate they're correct. */ /* We make some simplifying assumptions; validate they're correct. */
g_assert(PE(dc) == ((flags & HF_PE_MASK) != 0)); g_assert(PE(dc) == ((flags & HF_PE_MASK) != 0));
g_assert(CPL(dc) == cpl);
dc->code32 = (flags >> HF_CS32_SHIFT) & 1; dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
dc->ss32 = (flags >> HF_SS32_SHIFT) & 1; dc->ss32 = (flags >> HF_SS32_SHIFT) & 1;
dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1; dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1;
dc->f_st = 0; dc->f_st = 0;
dc->vm86 = (flags >> VM_SHIFT) & 1; dc->vm86 = (flags >> VM_SHIFT) & 1;
dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
dc->iopl = (flags >> IOPL_SHIFT) & 3; dc->iopl = (flags >> IOPL_SHIFT) & 3;
dc->tf = (flags >> TF_SHIFT) & 1; dc->tf = (flags >> TF_SHIFT) & 1;
dc->cc_op = CC_OP_DYNAMIC; dc->cc_op = CC_OP_DYNAMIC;