aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2011-04-03 05:32:09 -0400
committerAvi Kivity <avi@redhat.com>2011-05-11 07:57:08 -0400
commit618ff15de19109af126b33d90d7eaec27e61c691 (patch)
treec4c37731a89703a0684e8ddbb859d2ba30c4179e /arch/x86/kvm
parent56697687da592d0429c0c3ab80ee7e9d20a3b6e5 (diff)
KVM: x86 emulator: implement segment permission checks
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/emulate.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 793aff52a4b8..2ec69bc85846 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -515,6 +515,11 @@ static int emulate_gp(struct x86_emulate_ctxt *ctxt, int err)
515 return emulate_exception(ctxt, GP_VECTOR, err, true); 515 return emulate_exception(ctxt, GP_VECTOR, err, true);
516} 516}
517 517
518static int emulate_ss(struct x86_emulate_ctxt *ctxt, int err)
519{
520 return emulate_exception(ctxt, SS_VECTOR, err, true);
521}
522
518static int emulate_ud(struct x86_emulate_ctxt *ctxt) 523static int emulate_ud(struct x86_emulate_ctxt *ctxt)
519{ 524{
520 return emulate_exception(ctxt, UD_VECTOR, 0, false); 525 return emulate_exception(ctxt, UD_VECTOR, 0, false);
@@ -541,13 +546,71 @@ static int linearize(struct x86_emulate_ctxt *ctxt,
541 ulong *linear) 546 ulong *linear)
542{ 547{
543 struct decode_cache *c = &ctxt->decode; 548 struct decode_cache *c = &ctxt->decode;
549 struct desc_struct desc;
550 bool usable;
544 ulong la; 551 ulong la;
552 u32 lim;
553 unsigned cpl, rpl;
545 554
546 la = seg_base(ctxt, ctxt->ops, addr.seg) + addr.ea; 555 la = seg_base(ctxt, ctxt->ops, addr.seg) + addr.ea;
556 switch (ctxt->mode) {
557 case X86EMUL_MODE_REAL:
558 break;
559 case X86EMUL_MODE_PROT64:
560 if (((signed long)la << 16) >> 16 != la)
561 return emulate_gp(ctxt, 0);
562 break;
563 default:
564 usable = ctxt->ops->get_cached_descriptor(&desc, NULL, addr.seg,
565 ctxt->vcpu);
566 if (!usable)
567 goto bad;
568 /* code segment or read-only data segment */
569 if (((desc.type & 8) || !(desc.type & 2)) && write)
570 goto bad;
571 /* unreadable code segment */
572 if ((desc.type & 8) && !(desc.type & 2))
573 goto bad;
574 lim = desc_limit_scaled(&desc);
575 if ((desc.type & 8) || !(desc.type & 4)) {
576 /* expand-up segment */
577 if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim)
578 goto bad;
579 } else {
580 /* exapand-down segment */
581 if (addr.ea <= lim || (u32)(addr.ea + size - 1) <= lim)
582 goto bad;
583 lim = desc.d ? 0xffffffff : 0xffff;
584 if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim)
585 goto bad;
586 }
587 cpl = ctxt->ops->cpl(ctxt->vcpu);
588 rpl = ctxt->ops->get_segment_selector(addr.seg, ctxt->vcpu) & 3;
589 cpl = max(cpl, rpl);
590 if (!(desc.type & 8)) {
591 /* data segment */
592 if (cpl > desc.dpl)
593 goto bad;
594 } else if ((desc.type & 8) && !(desc.type & 4)) {
595 /* nonconforming code segment */
596 if (cpl != desc.dpl)
597 goto bad;
598 } else if ((desc.type & 8) && (desc.type & 4)) {
599 /* conforming code segment */
600 if (cpl < desc.dpl)
601 goto bad;
602 }
603 break;
604 }
547 if (c->ad_bytes != 8) 605 if (c->ad_bytes != 8)
548 la &= (u32)-1; 606 la &= (u32)-1;
549 *linear = la; 607 *linear = la;
550 return X86EMUL_CONTINUE; 608 return X86EMUL_CONTINUE;
609bad:
610 if (addr.seg == VCPU_SREG_SS)
611 return emulate_ss(ctxt, addr.seg);
612 else
613 return emulate_gp(ctxt, addr.seg);
551} 614}
552 615
553static int segmented_read_std(struct x86_emulate_ctxt *ctxt, 616static int segmented_read_std(struct x86_emulate_ctxt *ctxt,