x86/pv: Rework guest_io_okay() to return X86EMUL_*

In order to fix a bug with guest_io_okay() (subsequent patch), rework
guest_io_okay() to take in an emulation context, and return X86EMUL_* rather
than a boolean.

For the failing case, take the opportunity to inject #GP explicitly, rather
than returning X86EMUL_UNHANDLEABLE.  There is a logical difference between
"we know what this is, and it's #GP", vs "we don't know what this is".

There is no change in practice as emulation is the final step on general #GP
resolution, but returning X86EMUL_UNHANDLEABLE would be a latent bug if a
subsequent action were to appear.

No practical change.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: 7429e1cc07
master date: 2024-10-01 14:58:18 +0100
This commit is contained in:
Andrew Cooper authored and Jan Beulich committed 2024-10-29 16:27:29 +01:00
1 parent 8f9dad658a
commit f879df5eb4
1 file changed
+23 -13
+23 -13
View File
@@ -156,14 +156,16 @@ static bool iopl_ok(const struct vcpu *v, const struct cpu_user_regs *regs)
}
/* Has the guest requested sufficient permission for this I/O access? */
static bool guest_io_okay(unsigned int port, unsigned int bytes,
struct vcpu *v, struct cpu_user_regs *regs)
static int guest_io_okay(unsigned int port, unsigned int bytes,
struct x86_emulate_ctxt *ctxt)
{
const struct cpu_user_regs *regs = ctxt->regs;
struct vcpu *v = current;
/* If in user mode, switch to kernel mode just to read I/O bitmap. */
const bool user_mode = !(v->arch.flags & TF_kernel_mode);
if ( iopl_ok(v, regs) )
return true;
return X86EMUL_OKAY;
if ( (port + bytes) <= v->arch.pv.iobmp_limit )
{
@@ -190,10 +192,12 @@ static bool guest_io_okay(unsigned int port, unsigned int bytes,
toggle_guest_pt(v);
if ( (x.mask & (((1 << bytes) - 1) << (port & 7))) == 0 )
return true;
return X86EMUL_OKAY;
}
return false;
x86_emul_hw_exception(X86_EXC_GP, 0, ctxt);
return X86EMUL_EXCEPTION;
}
/* Has the administrator granted sufficient permission for this I/O access? */
@@ -353,12 +357,14 @@ static int cf_check read_io(
struct priv_op_ctxt *poc = container_of(ctxt, struct priv_op_ctxt, ctxt);
struct vcpu *curr = current;
struct domain *currd = current->domain;
int rc;
/* INS must not come here. */
ASSERT((ctxt->opcode & ~9) == 0xe4);
if ( !guest_io_okay(port, bytes, curr, ctxt->regs) )
return X86EMUL_UNHANDLEABLE;
rc = guest_io_okay(port, bytes, ctxt);
if ( rc != X86EMUL_OKAY )
return rc;
poc->bpmatch = check_guest_io_breakpoint(curr, port, bytes);
@@ -458,12 +464,14 @@ static int cf_check write_io(
struct priv_op_ctxt *poc = container_of(ctxt, struct priv_op_ctxt, ctxt);
struct vcpu *curr = current;
struct domain *currd = current->domain;
int rc;
/* OUTS must not come here. */
ASSERT((ctxt->opcode & ~9) == 0xe6);
if ( !guest_io_okay(port, bytes, curr, ctxt->regs) )
return X86EMUL_UNHANDLEABLE;
rc = guest_io_okay(port, bytes, ctxt);
if ( rc != X86EMUL_OKAY )
return rc;
poc->bpmatch = check_guest_io_breakpoint(curr, port, bytes);
@@ -612,8 +620,9 @@ static int cf_check rep_ins(
*reps = 0;
if ( !guest_io_okay(port, bytes_per_rep, curr, ctxt->regs) )
return X86EMUL_UNHANDLEABLE;
rc = guest_io_okay(port, bytes_per_rep, ctxt);
if ( rc != X86EMUL_OKAY )
return rc;
rc = read_segment(x86_seg_es, &sreg, ctxt);
if ( rc != X86EMUL_OKAY )
@@ -678,8 +687,9 @@ static int cf_check rep_outs(
*reps = 0;
if ( !guest_io_okay(port, bytes_per_rep, curr, ctxt->regs) )
return X86EMUL_UNHANDLEABLE;
rc = guest_io_okay(port, bytes_per_rep, ctxt);
if ( rc != X86EMUL_OKAY )
return rc;
rc = read_segment(seg, &sreg, ctxt);
if ( rc != X86EMUL_OKAY )
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.