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.

Cc: Dave Hansen <dave.han...@linux.intel.com>
Cc: Adam Buchbinder <adam.buchbin...@gmail.com>
Cc: Colin Ian King <colin.k...@canonical.com>
Cc: Lorenzo Stoakes <lstoa...@gmail.com>
Cc: Qiaowei Ren <qiaowei....@intel.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Masami Hiramatsu <mhira...@kernel.org>
Cc: Adrian Hunter <adrian.hun...@intel.com>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Thomas Garnier <thgar...@google.com>
Cc: Peter Zijlstra <pet...@infradead.org>
Cc: Borislav Petkov <b...@suse.de>
Cc: Dmitry Vyukov <dvyu...@google.com>
Cc: Ravi V. Shankar <ravi.v.shan...@intel.com>
Cc: x...@kernel.org
Signed-off-by: Ricardo Neri <ricardo.neri-calde...@linux.intel.com>
---
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.
---
 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 1c23ec0..91f08aa 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;
 
-- 
2.7.4

Reply via email to