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: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
This commit is contained in:
Eric W. Biederman 2018-01-03 19:22:04 -06:00
parent 8a35eb22c0
commit 8d68fa0e08
3 changed files with 32 additions and 29 deletions

View File

@ -57,8 +57,14 @@
#define MPX_BNDCFG_ADDR_MASK (~((1UL<<MPX_BNDCFG_TAIL)-1)) #define MPX_BNDCFG_ADDR_MASK (~((1UL<<MPX_BNDCFG_TAIL)-1))
#define MPX_BNDSTA_ERROR_CODE 0x3 #define MPX_BNDSTA_ERROR_CODE 0x3
struct mpx_fault_info {
void __user *addr;
void __user *lower;
void __user *upper;
};
#ifdef CONFIG_X86_INTEL_MPX #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); int mpx_handle_bd_fault(void);
static inline int kernel_managing_mpx_tables(struct mm_struct *mm) 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 mpx_unmapped_area_check(unsigned long addr, unsigned long len,
unsigned long flags); unsigned long flags);
#else #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) static inline int mpx_handle_bd_fault(void)
{ {

View File

@ -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) dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
{ {
const struct mpx_bndcsr *bndcsr; const struct mpx_bndcsr *bndcsr;
siginfo_t *info;
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU"); RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
if (notify_die(DIE_TRAP, "bounds", regs, error_code, 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; goto exit_trap;
break; /* Success, it was handled */ break; /* Success, it was handled */
case 1: /* Bound violation. */ 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 * We failed to decode the MPX instruction. Act as if
* the exception was not caused by MPX. * 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 * allows and application to possibly handle the
* #BR exception itself. * #BR exception itself.
*/ */
do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, info); clear_siginfo(&info);
kfree(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; break;
}
case 0: /* No exception caused by Intel MPX operations. */ case 0: /* No exception caused by Intel MPX operations. */
goto exit_trap; goto exit_trap;
default: default:

View File

@ -118,14 +118,11 @@ bad_opcode:
* anything it wants in to the instructions. We can not * anything it wants in to the instructions. We can not
* trust anything about it. They might not be valid * trust anything about it. They might not be valid
* instructions or might encode invalid registers, etc... * 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_state *bndregs;
const struct mpx_bndreg *bndreg; const struct mpx_bndreg *bndreg;
siginfo_t *info = NULL;
struct insn insn; struct insn insn;
uint8_t bndregno; uint8_t bndregno;
int err; 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 */ /* now go select the individual register in the set of 4 */
bndreg = &bndregs->bndreg[bndregno]; 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 * The registers are always 64-bit, but the upper 32
* bits are ignored in 32-bit mode. Also, note that the * 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 * complains when casting from integers to different-size
* pointers. * pointers.
*/ */
info->si_lower = (void __user *)(unsigned long)bndreg->lower_bound; info->lower = (void __user *)(unsigned long)bndreg->lower_bound;
info->si_upper = (void __user *)(unsigned long)~bndreg->upper_bound; info->upper = (void __user *)(unsigned long)~bndreg->upper_bound;
info->si_addr_lsb = 0; info->addr = insn_get_addr_ref(&insn, regs);
info->si_signo = SIGSEGV;
info->si_errno = 0;
info->si_code = SEGV_BNDERR;
info->si_addr = insn_get_addr_ref(&insn, regs);
/* /*
* We were not able to extract an address from the instruction, * We were not able to extract an address from the instruction,
* probably because there was something invalid in it. * probably because there was something invalid in it.
*/ */
if (info->si_addr == (void __user *)-1) { if (info->addr == (void __user *)-1) {
err = -EINVAL; err = -EINVAL;
goto err_out; goto err_out;
} }
trace_mpx_bounds_register_exception(info->si_addr, bndreg); trace_mpx_bounds_register_exception(info->addr, bndreg);
return info; return 0;
err_out: err_out:
/* info might be NULL, but kfree() handles that */ /* info might be NULL, but kfree() handles that */
kfree(info); return err;
return ERR_PTR(err);
} }
static __user void *mpx_get_bounds_dir(void) static __user void *mpx_get_bounds_dir(void)