Re: [PATCH 1/3] KVM: x86/emulator: Fix segment load privilege level validation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 1/26/23 02:34, Michal Luczaj wrote:
Intel SDM describes what steps are taken by the CPU to verify if a
memory segment can actually be used at a given privilege level. Loading
DS/ES/FS/GS involves checking segment's type as well as making sure that
neither selector's RPL nor caller's CPL are greater than segment's DPL.

Emulator implements Intel's pseudocode in __load_segment_descriptor(),
even quoting the pseudocode in the comments. Although the pseudocode is
correctly translated, the implementation is incorrect. This is most
likely due to SDM, at the time, being wrong.

Patch fixes emulator's logic and updates the pseudocode in the comment.
Below are historical notes.

Emulator code for handling segment descriptors appears to have been
introduced in March 2010 in commit 38ba30ba51a0 ("KVM: x86 emulator:
Emulate task switch in emulator.c"). Intel SDM Vol 2A: Instruction Set
Reference, A-M (Order Number: 253666-034US, _March 2010_) lists the
steps for loading segment registers in section related to MOV
instruction:

   IF DS, ES, FS, or GS is loaded with non-NULL selector
   THEN
     IF segment selector index is outside descriptor table limits
     or segment is not a data or readable code segment
     or ((segment is a data or nonconforming code segment)
     and (both RPL and CPL > DPL))   <---
       THEN #GP(selector); FI;

This is precisely what __load_segment_descriptor() quotes and
implements. But there's a twist; a few SDM revisions later
(253667-044US), in August 2012, the snippet above becomes:

   IF DS, ES, FS, or GS is loaded with non-NULL selector
   THEN
     IF segment selector index is outside descriptor table limits
     or segment is not a data or readable code segment
     or ((segment is a data or nonconforming code segment)
       [note: missing or superfluous parenthesis?]
     or ((RPL > DPL) and (CPL > DPL))   <---
       THEN #GP(selector); FI;

Many SDMs later (253667-065US), in December 2017, pseudocode reaches
what seems to be its final form:

   IF DS, ES, FS, or GS is loaded with non-NULL selector
   THEN
     IF segment selector index is outside descriptor table limits
     OR segment is not a data or readable code segment
     OR ((segment is a data or nonconforming code segment)
         AND ((RPL > DPL) or (CPL > DPL)))   <---
       THEN #GP(selector); FI;

Signed-off-by: Michal Luczaj <mhal@xxxxxxx>
---
  arch/x86/kvm/emulate.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 5cc3efa0e21c..81b8f5dcfa44 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1695,11 +1695,11 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
  		/*
  		 * segment is not a data or readable code segment or
  		 * ((segment is a data or nonconforming code segment)
-		 * and (both RPL and CPL > DPL))
+		 * and ((RPL > DPL) or (CPL > DPL)))
  		 */
  		if ((seg_desc.type & 0xa) == 0x8 ||
  		    (((seg_desc.type & 0xc) != 0xc) &&
-		     (rpl > dpl && cpl > dpl)))
+		     (rpl > dpl || cpl > dpl)))
  			goto exception;
  		break;
  	}

Reviewed-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux