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

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
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -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)
{
+14 −5
Original line number Diff line number Diff line
@@ -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:
+9 −21
Original line number Diff line number Diff line
@@ -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)