insn_get_addr_ref returns the effective address as defined by the
section 3.7.5.1 Vol 1 of the Intel 64 and IA-32 Architectures Software
Developer's Manual. In order to truly give the linear address, we must
add the effective address to the segment base as described by the segment
descriptor.

In most cases, the base will be 0 if the USER_DS segment is used or if
segmentation is not used. However, the base address is not necessarily
zero if a user programs defines its own segments. This is possible by
using a local descriptor table.

Cc: Dave Hansen <[email protected]>
Cc: Adam Buchbinder <[email protected]>
Cc: Colin Ian King <[email protected]>
Cc: Lorenzo Stoakes <[email protected]>
Cc: Qiaowei Ren <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Masami Hiramatsu <[email protected]>
Cc: Adrian Hunter <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Thomas Garnier <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: Ravi V. Shankar <[email protected]>
Cc: [email protected]
Signed-off-by: Ricardo Neri <[email protected]>
---
 arch/x86/lib/insn-eval.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c
index d6525c2..b3a2fe8 100644
--- a/arch/x86/lib/insn-eval.c
+++ b/arch/x86/lib/insn-eval.c
@@ -523,6 +523,7 @@ static void __user *insn_get_addr_ref(struct insn *insn, 
struct pt_regs *regs)
                if (addr_offset < 0)
                        goto out_err;
                addr = regs_get_register(regs, addr_offset);
+               addr += insn_get_seg_base(regs, insn, addr_offset);
        } else {
                if (insn->sib.nbytes) {
                        /*
@@ -551,6 +552,7 @@ static void __user *insn_get_addr_ref(struct insn *insn, 
struct pt_regs *regs)
                                indx = regs_get_register(regs, indx_offset);
 
                        addr = base + indx * (1 << X86_SIB_SCALE(sib));
+                       addr += insn_get_seg_base(regs, insn, base_offset);
                } else {
                        unsigned char addr_bytes;
 
@@ -575,8 +577,10 @@ static void __user *insn_get_addr_ref(struct insn *insn, 
struct pt_regs *regs)
                        } else {
                                addr = regs_get_register(regs, addr_offset);
                        }
+                       addr += insn_get_seg_base(regs, insn, addr_offset);
                }
                addr += insn->displacement.value;
+
        }
        return (void __user *)addr;
 out_err:
-- 
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-msdos" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to