Commit 8d68fa0e authored by Eric W. Biederman's avatar Eric W. Biederman

signal/x86: Move mpx siginfo generation into do_bounds

This separates the logic of generating the signal from the logic of
gathering the information about the bounds violation.
Reviewed-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent 8a35eb22
......@@ -57,8 +57,14 @@
#define MPX_BNDCFG_ADDR_MASK (~((1UL<<MPX_BNDCFG_TAIL)-1))
#define MPX_BNDSTA_ERROR_CODE 0x3
struct mpx_fault_info {
void __user *addr;
void __user *lower;
void __user *upper;
};
#ifdef CONFIG_X86_INTEL_MPX
siginfo_t *mpx_generate_siginfo(struct pt_regs *regs);
int mpx_fault_info(struct mpx_fault_info *info, struct pt_regs *regs);
int mpx_handle_bd_fault(void);
static inline int kernel_managing_mpx_tables(struct mm_struct *mm)
{
......@@ -78,9 +84,9 @@ void mpx_notify_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long mpx_unmapped_area_check(unsigned long addr, unsigned long len,
unsigned long flags);
#else
static inline siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
static inline int mpx_fault_info(struct mpx_fault_info *info, struct pt_regs *regs)
{
return NULL;
return -EINVAL;
}
static inline int mpx_handle_bd_fault(void)
{
......
......@@ -455,7 +455,6 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
{
const struct mpx_bndcsr *bndcsr;
siginfo_t *info;
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
if (notify_die(DIE_TRAP, "bounds", regs, error_code,
......@@ -493,8 +492,11 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
goto exit_trap;
break; /* Success, it was handled */
case 1: /* Bound violation. */
info = mpx_generate_siginfo(regs);
if (IS_ERR(info)) {
{
struct mpx_fault_info mpx;
struct siginfo info;
if (mpx_fault_info(&mpx, regs)) {
/*
* We failed to decode the MPX instruction. Act as if
* the exception was not caused by MPX.
......@@ -508,9 +510,16 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
* allows and application to possibly handle the
* #BR exception itself.
*/
do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, info);
kfree(info);
clear_siginfo(&info);
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = SEGV_BNDERR;
info.si_addr = mpx.addr;
info.si_lower = mpx.lower;
info.si_upper = mpx.upper;
do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, &info);
break;
}
case 0: /* No exception caused by Intel MPX operations. */
goto exit_trap;
default:
......
......@@ -118,14 +118,11 @@ static int mpx_insn_decode(struct insn *insn,
* anything it wants in to the instructions. We can not
* trust anything about it. They might not be valid
* instructions or might encode invalid registers, etc...
*
* The caller is expected to kfree() the returned siginfo_t.
*/
siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
int mpx_fault_info(struct mpx_fault_info *info, struct pt_regs *regs)
{
const struct mpx_bndreg_state *bndregs;
const struct mpx_bndreg *bndreg;
siginfo_t *info = NULL;
struct insn insn;
uint8_t bndregno;
int err;
......@@ -153,11 +150,6 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
/* now go select the individual register in the set of 4 */
bndreg = &bndregs->bndreg[bndregno];
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
err = -ENOMEM;
goto err_out;
}
/*
* The registers are always 64-bit, but the upper 32
* bits are ignored in 32-bit mode. Also, note that the
......@@ -168,27 +160,23 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
* complains when casting from integers to different-size
* pointers.
*/
info->si_lower = (void __user *)(unsigned long)bndreg->lower_bound;
info->si_upper = (void __user *)(unsigned long)~bndreg->upper_bound;
info->si_addr_lsb = 0;
info->si_signo = SIGSEGV;
info->si_errno = 0;
info->si_code = SEGV_BNDERR;
info->si_addr = insn_get_addr_ref(&insn, regs);
info->lower = (void __user *)(unsigned long)bndreg->lower_bound;
info->upper = (void __user *)(unsigned long)~bndreg->upper_bound;
info->addr = insn_get_addr_ref(&insn, regs);
/*
* We were not able to extract an address from the instruction,
* probably because there was something invalid in it.
*/
if (info->si_addr == (void __user *)-1) {
if (info->addr == (void __user *)-1) {
err = -EINVAL;
goto err_out;
}
trace_mpx_bounds_register_exception(info->si_addr, bndreg);
return info;
trace_mpx_bounds_register_exception(info->addr, bndreg);
return 0;
err_out:
/* info might be NULL, but kfree() handles that */
kfree(info);
return ERR_PTR(err);
return err;
}
static __user void *mpx_get_bounds_dir(void)
......
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