[PATCH v7 19/26] x86/insn-eval: Add wrapper function for 16-bit and 32-bit address encodings

Ricardo Neri
2017-05-05T18:17:17Z

Convert the function insn_get_add_ref() into a wrapper function that calls
the correct static address-decoding function depending on the address size
In this way, callers do not need to worry about calling the correct
function and decreases the number of functions that need to be exposed.

To this end, the function insn_get_addr_ref() used to obtain linear
addresses from the 32/64-bit encodings is renamed as get_addr_ref_32_64()
to reflect the type of address encodings that it handles.

Documentation is added to the new wrapper function and the documentation
for the 32/64-bit address decoding function is improved.

Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Adam Buchbinder <adam.buchbinder@gmail.com>
Cc: Colin Ian King <colin.king@canonical.com>
Cc: Lorenzo Stoakes <lstoakes@gmail.com>
Cc: Qiaowei Ren <qiaowei.ren@intel.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Thomas Garnier <thgarnie@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@suse.de>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Ravi V. Shankar <ravi.v.shankar@intel.com>
Cc: x86@kernel.org
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
arch/x86/lib/insn-eval.c | 48 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 43 insertions(+), 5 deletions(-)

diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c
index 928a662..8914884 100644
--- a/arch/x86/lib/insn-eval.c
+++ b/arch/x86/lib/insn-eval.c
@@ -899,12 +899,22 @@ long get_mem_offset(struct pt_regs *regs, int reg_offset, int addr_size)
return -1L;
return offset;
}
-/*
- * return the address being referenced be instruction
- * for rm=3 returning the content of the rm reg
- * for rm!=3 calculates the address using SIB and Disp
+
+/**
+ * get_addr_ref_32_64() - Obtain a 32/64-bit linear address
+ * @insn: Instruction struct with ModRM and SiB bytes and displacement
+ * @regs: Structure with register values as seen when entering kernel mode
+ *
+ * This function is to be used with 32-bit and 64-bit address encodings to
+ * obtain the effective memory address referred by the instruction's ModRM,
+ * SIB, and displacement bytes, as applicable. Also, the segment base is used
+ * to compute the linear address. In protected mode, segment limits are
+ * enforced.
+ *
+ * Return: linear address referenced by instruction and registers on success.
+ * -1L on failure.
*/
-void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
+static void __user *get_addr_ref_32_64(struct insn *insn, struct pt_regs *regs)
{
unsigned long linear_addr, seg_base_addr, seg_limit;
long eff_addr, base, indx;
@@ -1026,3 +1036,31 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
out_err:
return (void __user *)-1;
}
+
+/**
+ * insn_get_addr_ref() - Obtain the linear address referred by instruction
+ * @insn: Instruction structure containing ModRM byte and displacement
+ * @regs: Structure with register values as seen when entering kernel mode
+ *
+ * Obtain the memory address referred by the instruction's ModRM bytes and
+ * displacement. Also, the segment used as base is determined by either any
+ * segment override prefixes in insn or the default segment of the registers
+ * involved in the address computation. In protected mode, segment limits
+ * are enforced.
+ *
+ * Return: linear address referenced by instruction and registers on success.
+ * -1L on failure.
+ */
+void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
+{
+ switch (insn->addr_bytes) {
+ case 2:
+ return get_addr_ref_16(insn, regs);
+ case 4:
+ /* fall through */
+ case 8:
+ return get_addr_ref_32_64(insn, regs);
+ default:
+ return (void __user *)-1;
+ }
+}
--
2.9.3