]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
x86/insn-eval: Add utility function to get segment descriptor
authorRicardo Neri <ricardo.neri-calderon@linux.intel.com>
Fri, 27 Oct 2017 20:25:41 +0000 (13:25 -0700)
committerThomas Gleixner <tglx@linutronix.de>
Wed, 1 Nov 2017 20:50:12 +0000 (21:50 +0100)
The segment descriptor contains information that is relevant to how linear
addresses need to be computed. It contains the default size of addresses
as well as the base address of the segment. Thus, given a segment
selector, we ought to look at segment descriptor to correctly calculate
the linear address.

In protected mode, the segment selector might indicate a segment
descriptor from either the global descriptor table or a local descriptor
table. Both cases are considered in this function.

This function is a prerequisite for functions in subsequent commits that
will obtain the aforementioned attributes of the segment descriptor.

Improvements-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Borislav Petkov <bp@suse.de>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: ricardo.neri@intel.com
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Paul Gortmaker <paul.gortmaker@windriver.com>
Cc: Huang Rui <ray.huang@amd.com>
Cc: Qiaowei Ren <qiaowei.ren@intel.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Kees Cook <keescook@chromium.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: "Ravi V. Shankar" <ravi.v.shankar@intel.com>
Cc: Chris Metcalf <cmetcalf@mellanox.com>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Colin Ian King <colin.king@canonical.com>
Cc: Chen Yucong <slaoub@gmail.com>
Cc: Adam Buchbinder <adam.buchbinder@gmail.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Lorenzo Stoakes <lstoakes@gmail.com>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Thomas Garnier <thgarnie@google.com>
Link: https://lkml.kernel.org/r/1509135945-13762-15-git-send-email-ricardo.neri-calderon@linux.intel.com
arch/x86/lib/insn-eval.c

index 6a902b155f5d6a09e6fd12883d0bda3abfed451b..d85e84091ddc91d219587eb399257336afd181f7 100644 (file)
@@ -6,9 +6,13 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/ratelimit.h>
+#include <linux/mmu_context.h>
+#include <asm/desc_defs.h>
+#include <asm/desc.h>
 #include <asm/inat.h>
 #include <asm/insn.h>
 #include <asm/insn-eval.h>
+#include <asm/ldt.h>
 #include <asm/vm86.h>
 
 #undef pr_fmt
@@ -468,6 +472,59 @@ static int get_reg_offset(struct insn *insn, struct pt_regs *regs,
        return regoff[regno];
 }
 
+/**
+ * get_desc() - Obtain pointer to a segment descriptor
+ * @sel:       Segment selector
+ *
+ * Given a segment selector, obtain a pointer to the segment descriptor.
+ * Both global and local descriptor tables are supported.
+ *
+ * Returns:
+ *
+ * Pointer to segment descriptor on success.
+ *
+ * NULL on error.
+ */
+static struct desc_struct *get_desc(unsigned short sel)
+{
+       struct desc_ptr gdt_desc = {0, 0};
+       unsigned long desc_base;
+
+#ifdef CONFIG_MODIFY_LDT_SYSCALL
+       if ((sel & SEGMENT_TI_MASK) == SEGMENT_LDT) {
+               struct desc_struct *desc = NULL;
+               struct ldt_struct *ldt;
+
+               /* Bits [15:3] contain the index of the desired entry. */
+               sel >>= 3;
+
+               mutex_lock(&current->active_mm->context.lock);
+               ldt = current->active_mm->context.ldt;
+               if (ldt && sel < ldt->nr_entries)
+                       desc = &ldt->entries[sel];
+
+               mutex_unlock(&current->active_mm->context.lock);
+
+               return desc;
+       }
+#endif
+       native_store_gdt(&gdt_desc);
+
+       /*
+        * Segment descriptors have a size of 8 bytes. Thus, the index is
+        * multiplied by 8 to obtain the memory offset of the desired descriptor
+        * from the base of the GDT. As bits [15:3] of the segment selector
+        * contain the index, it can be regarded as multiplied by 8 already.
+        * All that remains is to clear bits [2:0].
+        */
+       desc_base = sel & ~(SEGMENT_RPL_MASK | SEGMENT_TI_MASK);
+
+       if (desc_base > gdt_desc.size)
+               return NULL;
+
+       return (struct desc_struct *)(gdt_desc.address + desc_base);
+}
+
 /**
  * insn_get_modrm_rm_off() - Obtain register in r/m part of the ModRM byte
  * @insn:      Instruction containing the ModRM byte