ping https://lore.kernel.org/qemu-devel/[email protected]/T/#u
пн, 8 июн. 2026 г., 19:19 Andrey Polivoda <[email protected]>: > Intel and AMD CPUs implement SYSRETQ instruction differently. > One of these differences is whether a canonicality check of the address > that > will be loaded to RIP is performed: Intel CPUs do this check, AMD CPUs > don't. > > Currently, QEMU does not perform this check when emulating Intel CPUs. > This patch corrects this by implementing the canonlicality check on a new > RIP > value from RCX and performing it only when emulating Intel CPUs. > > Flags and segment registers' caches are updated only after checking the > new RIP > value to ensure that CPU state is not modified in case the #GP(0) exception > is raised due to the check failure. > > Cc: [email protected] > Cc: Paolo Bonzini <[email protected]> > Cc: Richard Henderson <[email protected]> > Fixes: 14ce26e75513 ("x86_64 target support") > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3223 > Signed-off-by: Andrey Polivoda <[email protected]> > --- > target/i386/tcg/seg_helper.c | 17 +++++++++++++---- > 1 file changed, 13 insertions(+), 4 deletions(-) > > diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c > index 58aac72011..d5c174b7fd 100644 > --- a/target/i386/tcg/seg_helper.c > +++ b/target/i386/tcg/seg_helper.c > @@ -1096,17 +1096,22 @@ void helper_sysret(CPUX86State *env, int dflag) > selector = (env->star >> 48) & 0xffff; > #ifdef TARGET_X86_64 > if (env->hflags & HF_LMA_MASK) { > - cpu_load_eflags(env, (uint32_t)(env->regs[11]), TF_MASK | AC_MASK > - | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | > RF_MASK | > - NT_MASK); > if (dflag == 2) { > + uint64_t new_rip = env->regs[R_ECX]; > + if (IS_INTEL_CPU(env)) { > + int shift = (get_pg_mode(env) & PG_MODE_LA57) ? 56 : 47; > + int64_t sext = (int64_t)new_rip >> shift; > + if (sext != 0 && sext != -1) { > + raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); > + } > + } > cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, > 0, 0xffffffff, > DESC_G_MASK | DESC_P_MASK | > DESC_S_MASK | (3 << DESC_DPL_SHIFT) | > DESC_CS_MASK | DESC_R_MASK | > DESC_A_MASK | > DESC_L_MASK); > - env->eip = env->regs[R_ECX]; > + env->eip = new_rip; > } else { > cpu_x86_load_seg_cache(env, R_CS, selector | 3, > 0, 0xffffffff, > @@ -1120,6 +1125,10 @@ void helper_sysret(CPUX86State *env, int dflag) > DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | > DESC_S_MASK | (3 << DESC_DPL_SHIFT) | > DESC_W_MASK | DESC_A_MASK); > + > + cpu_load_eflags(env, (uint32_t)(env->regs[11]), TF_MASK | AC_MASK > + | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | > RF_MASK | > + NT_MASK); > } else > #endif > { > -- > 2.53.0 > >
