diff options
author | Ricardo Neri <[email protected]> | 2017-10-27 13:25:41 -0700 |
---|---|---|
committer | Thomas Gleixner <[email protected]> | 2017-11-01 21:50:12 +0100 |
commit | 670f928ba09b06712da34a3c44be6c8fa561fb19 (patch) | |
tree | c76f11a6cc413112bdcc0f4cc33675203368fcbf | |
parent | 32d0b95300db03c2b23b2ea2c94769a4a138e79d (diff) |
x86/insn-eval: Add utility function to get segment descriptor
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 <[email protected]>
Signed-off-by: Ricardo Neri <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Reviewed-by: Borislav Petkov <[email protected]>
Cc: "Michael S. Tsirkin" <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: [email protected]
Cc: Adrian Hunter <[email protected]>
Cc: Paul Gortmaker <[email protected]>
Cc: Huang Rui <[email protected]>
Cc: Qiaowei Ren <[email protected]>
Cc: Shuah Khan <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Jonathan Corbet <[email protected]>
Cc: Jiri Slaby <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: "Ravi V. Shankar" <[email protected]>
Cc: Chris Metcalf <[email protected]>
Cc: Brian Gerst <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Colin Ian King <[email protected]>
Cc: Chen Yucong <[email protected]>
Cc: Adam Buchbinder <[email protected]>
Cc: Vlastimil Babka <[email protected]>
Cc: Lorenzo Stoakes <[email protected]>
Cc: Masami Hiramatsu <[email protected]>
Cc: Paolo Bonzini <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Thomas Garnier <[email protected]>
Link: https://lkml.kernel.org/r/1509135945-13762-15-git-send-email-ricardo.neri-calderon@linux.intel.com
-rw-r--r-- | arch/x86/lib/insn-eval.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c index 6a902b155f5d..d85e84091ddc 100644 --- a/arch/x86/lib/insn-eval.c +++ b/arch/x86/lib/insn-eval.c @@ -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 @@ -469,6 +473,59 @@ static int get_reg_offset(struct insn *insn, struct pt_regs *regs, } /** + * 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(¤t->active_mm->context.lock); + ldt = current->active_mm->context.ldt; + if (ldt && sel < ldt->nr_entries) + desc = &ldt->entries[sel]; + + mutex_unlock(¤t->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 * @regs: Register values as seen when entering kernel mode |