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; + } +}