lkml.org 
[lkml]   [2020]   [Apr]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v3 07/75] x86/umip: Factor out instruction fetch
    Date
    From: Joerg Roedel <jroedel@suse.de>

    Factor out the code to fetch the instruction from user-space to a helper
    function.

    No functional changes.

    Signed-off-by: Joerg Roedel <jroedel@suse.de>
    ---
    arch/x86/include/asm/insn-eval.h | 2 ++
    arch/x86/kernel/umip.c | 26 +++++-----------------
    arch/x86/lib/insn-eval.c | 38 ++++++++++++++++++++++++++++++++
    3 files changed, 46 insertions(+), 20 deletions(-)

    diff --git a/arch/x86/include/asm/insn-eval.h b/arch/x86/include/asm/insn-eval.h
    index 2b6ccf2c49f1..b8b9ef1bbd06 100644
    --- a/arch/x86/include/asm/insn-eval.h
    +++ b/arch/x86/include/asm/insn-eval.h
    @@ -19,5 +19,7 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs);
    int insn_get_modrm_rm_off(struct insn *insn, struct pt_regs *regs);
    unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx);
    int insn_get_code_seg_params(struct pt_regs *regs);
    +int insn_fetch_from_user(struct pt_regs *regs,
    + unsigned char buf[MAX_INSN_SIZE]);

    #endif /* _ASM_X86_INSN_EVAL_H */
    diff --git a/arch/x86/kernel/umip.c b/arch/x86/kernel/umip.c
    index 8d5cbe1bbb3b..c9e5345da793 100644
    --- a/arch/x86/kernel/umip.c
    +++ b/arch/x86/kernel/umip.c
    @@ -317,11 +317,11 @@ static void force_sig_info_umip_fault(void __user *addr, struct pt_regs *regs)
    */
    bool fixup_umip_exception(struct pt_regs *regs)
    {
    - int not_copied, nr_copied, reg_offset, dummy_data_size, umip_inst;
    - unsigned long seg_base = 0, *reg_addr;
    + int nr_copied, reg_offset, dummy_data_size, umip_inst;
    /* 10 bytes is the maximum size of the result of UMIP instructions */
    unsigned char dummy_data[10] = { 0 };
    unsigned char buf[MAX_INSN_SIZE];
    + unsigned long *reg_addr;
    void __user *uaddr;
    struct insn insn;
    int seg_defs;
    @@ -329,26 +329,12 @@ bool fixup_umip_exception(struct pt_regs *regs)
    if (!regs)
    return false;

    - /*
    - * If not in user-space long mode, a custom code segment could be in
    - * use. This is true in protected mode (if the process defined a local
    - * descriptor table), or virtual-8086 mode. In most of the cases
    - * seg_base will be zero as in USER_CS.
    - */
    - if (!user_64bit_mode(regs))
    - seg_base = insn_get_seg_base(regs, INAT_SEG_REG_CS);
    -
    - if (seg_base == -1L)
    - return false;
    -
    - not_copied = copy_from_user(buf, (void __user *)(seg_base + regs->ip),
    - sizeof(buf));
    - nr_copied = sizeof(buf) - not_copied;
    + nr_copied = insn_fetch_from_user(regs, buf);

    /*
    - * The copy_from_user above could have failed if user code is protected
    - * by a memory protection key. Give up on emulation in such a case.
    - * Should we issue a page fault?
    + * The insn_fetch_from_user above could have failed if user code
    + * is protected by a memory protection key. Give up on emulation
    + * in such a case. Should we issue a page fault?
    */
    if (!nr_copied)
    return false;
    diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c
    index 31600d851fd8..0c4f7ebc261b 100644
    --- a/arch/x86/lib/insn-eval.c
    +++ b/arch/x86/lib/insn-eval.c
    @@ -1369,3 +1369,41 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
    return (void __user *)-1L;
    }
    }
    +
    +/**
    + * insn_fetch_from_user() - Copy instruction bytes from user-space memory
    + * @regs: Structure with register values as seen when entering kernel mode
    + * @buf: Array to store the fetched instruction
    + *
    + * Gets the linear address of the instruction and copies the instruction bytes
    + * to the buf.
    + *
    + * Returns:
    + *
    + * Number of instruction bytes copied.
    + *
    + * 0 if nothing was copied.
    + */
    +int insn_fetch_from_user(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE])
    +{
    + unsigned long seg_base = 0;
    + int not_copied;
    +
    + /*
    + * If not in user-space long mode, a custom code segment could be in
    + * use. This is true in protected mode (if the process defined a local
    + * descriptor table), or virtual-8086 mode. In most of the cases
    + * seg_base will be zero as in USER_CS.
    + */
    + if (!user_64bit_mode(regs)) {
    + seg_base = insn_get_seg_base(regs, INAT_SEG_REG_CS);
    + if (seg_base == -1L)
    + return 0;
    + }
    +
    +
    + not_copied = copy_from_user(buf, (void __user *)(seg_base + regs->ip),
    + MAX_INSN_SIZE);
    +
    + return MAX_INSN_SIZE - not_copied;
    +}
    --
    2.17.1
    \
     
     \ /
      Last update: 2020-04-28 17:26    [W:3.136 / U:0.808 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site