From 71271269ef9a997fb4416b2f8ef3558dd846c7cb Mon Sep 17 00:00:00 2001 From: Ricardo Neri Date: Fri, 27 Oct 2017 16:51:38 -0700 Subject: x86/insn-eval: Extend get_seg_base_addr() to also obtain segment limit In protected mode, it is common to want to obtain the limit of a segment along with its base address. This is useful, for instance, to verify that an effective address lies within a segment before computing a linear address. Up to this point, this library only computes linear addresses in long mode. Subsequent patches will include support for protected mode. Support to verify the segment limit will be needed. Signed-off-by: Ricardo Neri Cc: Adam Buchbinder Cc: Adrian Hunter Cc: Andrew Morton Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Brian Gerst Cc: Chen Yucong Cc: Chris Metcalf Cc: Colin Ian King Cc: Dave Hansen Cc: Dmitry Vyukov Cc: Huang Rui Cc: Jiri Slaby Cc: Jonathan Corbet Cc: Kees Cook Cc: Linus Torvalds Cc: Lorenzo Stoakes Cc: Masami Hiramatsu Cc: Michael S. Tsirkin Cc: Paolo Bonzini Cc: Paul Gortmaker Cc: Peter Zijlstra Cc: Qiaowei Ren Cc: Ravi V. Shankar Cc: Shuah Khan Cc: Thomas Garnier Cc: Thomas Gleixner Cc: Vlastimil Babka Cc: ricardo.neri@intel.com Link: http://lkml.kernel.org/r/1509148310-30862-2-git-send-email-ricardo.neri-calderon@linux.intel.com Signed-off-by: Ingo Molnar --- arch/x86/lib/insn-eval.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c index 1c23ec03c568..91f08aafb65e 100644 --- a/arch/x86/lib/insn-eval.c +++ b/arch/x86/lib/insn-eval.c @@ -729,25 +729,29 @@ int insn_get_modrm_rm_off(struct insn *insn, struct pt_regs *regs) } /** - * get_seg_base_addr() - obtain base address of a segment + * get_seg_base_limit() - obtain base address and limit of a segment * @insn: Instruction. Must be valid. * @regs: Register values as seen when entering kernel mode * @regoff: Operand offset, in pt_regs, used to resolve segment descriptor * @base: Obtained segment base + * @limit: Obtained segment limit * - * Obtain the base address of the segment associated with the operand @regoff - * and, if any or allowed, override prefixes in @insn. This function is + * Obtain the base address and limit of the segment associated with the operand + * @regoff and, if any or allowed, override prefixes in @insn. This function is * different from insn_get_seg_base() as the latter does not resolve the segment - * associated with the instruction operand. + * associated with the instruction operand. If a limit is not needed (e.g., + * when running in long mode), @limit can be NULL. * * Returns: * - * 0 on success. @base will contain the base address of the resolved segment. + * 0 on success. @base and @limit will contain the base address and of the + * resolved segment, respectively. * * -EINVAL on error. */ -static int get_seg_base_addr(struct insn *insn, struct pt_regs *regs, - int regoff, unsigned long *base) +static int get_seg_base_limit(struct insn *insn, struct pt_regs *regs, + int regoff, unsigned long *base, + unsigned long *limit) { int seg_reg_idx; @@ -762,6 +766,13 @@ static int get_seg_base_addr(struct insn *insn, struct pt_regs *regs, if (*base == -1L) return -EINVAL; + if (!limit) + return 0; + + *limit = get_seg_limit(regs, seg_reg_idx); + if (!(*limit)) + return -EINVAL; + return 0; } @@ -843,7 +854,7 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) eff_addr += insn->displacement.value; } - ret = get_seg_base_addr(insn, regs, addr_offset, &seg_base); + ret = get_seg_base_limit(insn, regs, addr_offset, &seg_base, NULL); if (ret) goto out; -- cgit