Commit 172b75e5 authored by Joerg Roedel's avatar Joerg Roedel Committed by Borislav Petkov

x86/umip: Factor out instruction fetch

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

No functional changes.
Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20200907131613.12703-9-joro@8bytes.org
parent 05a2ae7c
...@@ -19,5 +19,7 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs); ...@@ -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); 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); 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_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 */ #endif /* _ASM_X86_INSN_EVAL_H */
...@@ -335,11 +335,11 @@ static void force_sig_info_umip_fault(void __user *addr, struct pt_regs *regs) ...@@ -335,11 +335,11 @@ static void force_sig_info_umip_fault(void __user *addr, struct pt_regs *regs)
*/ */
bool fixup_umip_exception(struct pt_regs *regs) bool fixup_umip_exception(struct pt_regs *regs)
{ {
int not_copied, nr_copied, reg_offset, dummy_data_size, umip_inst; int nr_copied, reg_offset, dummy_data_size, umip_inst;
unsigned long seg_base = 0, *reg_addr;
/* 10 bytes is the maximum size of the result of UMIP instructions */ /* 10 bytes is the maximum size of the result of UMIP instructions */
unsigned char dummy_data[10] = { 0 }; unsigned char dummy_data[10] = { 0 };
unsigned char buf[MAX_INSN_SIZE]; unsigned char buf[MAX_INSN_SIZE];
unsigned long *reg_addr;
void __user *uaddr; void __user *uaddr;
struct insn insn; struct insn insn;
int seg_defs; int seg_defs;
...@@ -347,26 +347,12 @@ bool fixup_umip_exception(struct pt_regs *regs) ...@@ -347,26 +347,12 @@ bool fixup_umip_exception(struct pt_regs *regs)
if (!regs) if (!regs)
return false; return false;
/* nr_copied = insn_fetch_from_user(regs, buf);
* 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;
/* /*
* The copy_from_user above could have failed if user code is protected * The insn_fetch_from_user above could have failed if user code
* by a memory protection key. Give up on emulation in such a case. * is protected by a memory protection key. Give up on emulation
* Should we issue a page fault? * in such a case. Should we issue a page fault?
*/ */
if (!nr_copied) if (!nr_copied)
return false; return false;
......
...@@ -1367,3 +1367,41 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) ...@@ -1367,3 +1367,41 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
return (void __user *)-1L; 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment