TSS I/O permission bitmap reads are implicit supervisor accesses which
are subject to Linear Address Space Separation (LASS) enforcement.
Though highly unlikely, if a guest configures a TSS base in the
user half, hardware would raise a #GP on access when LASS is enabled.

Currently, the emulator reads the I/O permission bitmap from the TSS by
calling read_std() directly which is inconsistent with other implicit
accesses in the emulator such as IDT reads, GDT/LDT reads and TSS reads
during task switch.

An upcoming change will add a check to linear_read_system() to catch
LASS violations. For consistency as well as to keep LASS enforcement
centralized, switch both I/O bitmap reads to linear_read_system().

Note, emulator_io_port_access_allowed() doesn't propagate faults, so
even though linear_read_system() will set the exception details they
will be ignored.

While at it, fix an off-by-one in the I/O bitmap bounds check to account
for the 2-byte read and ensure both bytes are within the TSS limit. The
SDM mandates a trailing 0xFF byte after the bitmap so any out-of-bounds
access would be all 1s (denying access). Make the change primarily to
ensure hardware fidelity. A correctly configured OS will not run into
this issue.

Signed-off-by: Sohil Mehta <[email protected]>
---
v4:
- New patch

There could be a pre-existing issue here. It is unlikely that any OS
demand-pages the I/O bitmap portion of the TSS. But if it does, the #PF
details could get lost and the guest would get a #GP instead of a
restartable #PF. Propagating the #PF to the callers is a larger change
that is beyond the scope of this series.
---
 arch/x86/kvm/emulate.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 8ff28643b2e3..7f04544cfee5 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2573,12 +2573,12 @@ static bool emulator_io_port_access_allowed(struct 
x86_emulate_ctxt *ctxt,
 #ifdef CONFIG_X86_64
        base |= ((u64)base3) << 32;
 #endif
-       r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL, true);
+       r = linear_read_system(ctxt, base + 102, &io_bitmap_ptr, 2);
        if (r != X86EMUL_CONTINUE)
                return false;
-       if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg))
+       if (io_bitmap_ptr + port/8 + 1 > desc_limit_scaled(&tr_seg))
                return false;
-       r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL, 
true);
+       r = linear_read_system(ctxt, base + io_bitmap_ptr + port/8, &perm, 2);
        if (r != X86EMUL_CONTINUE)
                return false;
        if ((perm >> bit_idx) & mask)
-- 
2.43.0


Reply via email to