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

