diff options
author | Avi Kivity <avi@redhat.com> | 2011-04-03 05:32:09 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-05-11 07:57:08 -0400 |
commit | 618ff15de19109af126b33d90d7eaec27e61c691 (patch) | |
tree | c4c37731a89703a0684e8ddbb859d2ba30c4179e /arch/x86/kvm | |
parent | 56697687da592d0429c0c3ab80ee7e9d20a3b6e5 (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.c | 63 |
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 | ||
518 | static int emulate_ss(struct x86_emulate_ctxt *ctxt, int err) | ||
519 | { | ||
520 | return emulate_exception(ctxt, SS_VECTOR, err, true); | ||
521 | } | ||
522 | |||
518 | static int emulate_ud(struct x86_emulate_ctxt *ctxt) | 523 | static 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; |
609 | bad: | ||
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 | ||
553 | static int segmented_read_std(struct x86_emulate_ctxt *ctxt, | 616 | static int segmented_read_std(struct x86_emulate_ctxt *ctxt, |