[PATCH] target/i386/tcg: raise #GP(0) on null SS load with RPL != CPL
Jakub Lipový <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu,gmane.comp.emulators.qemu.stable |
|---|---|
| Message-ID | <[email protected]> |
In 64-bit mode, loading a null selector into SS raises #GP(0) if CPL = 3, or if CPL < 3 and CPL != RPL. helper_load_seg() only implemented the first case: the null-selector path never examined the selector's RPL, so a null selector with non-zero RPL (such as 0x0003) loaded successfully at CPL < 3. This was caught by test_sreg() in kvm-unit-tests x86/emulator64.c, which additionally fails its subsequent non-null check because the wrongly succeeded load leaves 3 in SS. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4204 Cc: [email protected] Signed-off-by: Jakub Lipový <[email protected]> --- All three SS related checks in x86/emulator64.c's test_sreg() now pass under TCG. I have not added an in-tree test case to verify this, as this case requires CPL manipulations that tests/tcg doesn't seem to be able to easily do. The behavior is covered by test_sreg() in kvm-unit-tests. Happy to add one if preferred. target/i386/tcg/seg_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index d5c174b7fd..36e3ae3b55 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -1411,11 +1411,12 @@ void helper_load_seg(CPUX86State *env, int seg_reg, int selector) selector &= 0xffff; cpl = env->hflags & HF_CPL_MASK; + rpl = selector & 3; if ((selector & 0xfffc) == 0) { /* null selector case */ if (seg_reg == R_SS #ifdef TARGET_X86_64 - && (!(env->hflags & HF_CS64_MASK) || cpl == 3) + && (!(env->hflags & HF_CS64_MASK) || cpl == 3 || cpl != rpl) #endif ) { raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); @@ -1439,7 +1440,6 @@ void helper_load_seg(CPUX86State *env, int seg_reg, int selector) if (!(e2 & DESC_S_MASK)) { raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC()); } - rpl = selector & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3; if (seg_reg == R_SS) { /* must be writable segment */ -- 2.55.0