Commit 54587653 authored by Dave Hansen's avatar Dave Hansen Committed by Ingo Molnar

x86/mpx: Introduce new 'directory entry' to 'addr' helper function

Currently, to get from a bounds directory entry to the virtual
address of a bounds table, we simply mask off a few low bits.
However, the set of bits we mask off is different for 32-bit and
64-bit binaries.

This breaks the operation out in to a helper function and also
adds a temporary variable to store the result until we are
sure we are returning one.
Signed-off-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: default avatarThomas Gleixner <tglx@linutronix.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Dave Hansen <dave@sr71.net>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20150607183704.007686CE@viggo.jf.intel.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent a1149fc8
......@@ -45,7 +45,6 @@
#define MPX_BNDSTA_TAIL 2
#define MPX_BNDCFG_TAIL 12
#define MPX_BNDSTA_ADDR_MASK (~((1UL<<MPX_BNDSTA_TAIL)-1))
#define MPX_BT_ADDR_MASK (~((1UL<<MPX_BD_ENTRY_TAIL)-1))
#define MPX_BNDCFG_ADDR_MASK (~((1UL<<MPX_BNDCFG_TAIL)-1))
#define MPX_BNDSTA_ERROR_CODE 0x3
......
......@@ -576,29 +576,55 @@ static int mpx_resolve_fault(long __user *addr, int write)
return 0;
}
static unsigned long mpx_bd_entry_to_bt_addr(struct mm_struct *mm,
unsigned long bd_entry)
{
unsigned long bt_addr = bd_entry;
int align_to_bytes;
/*
* Bit 0 in a bt_entry is always the valid bit.
*/
bt_addr &= ~MPX_BD_ENTRY_VALID_FLAG;
/*
* Tables are naturally aligned at 8-byte boundaries
* on 64-bit and 4-byte boundaries on 32-bit. The
* documentation makes it appear that the low bits
* are ignored by the hardware, so we do the same.
*/
if (is_64bit_mm(mm))
align_to_bytes = 8;
else
align_to_bytes = 4;
bt_addr &= ~(align_to_bytes-1);
return bt_addr;
}
/*
* Get the base of bounds tables pointed by specific bounds
* directory entry.
*/
static int get_bt_addr(struct mm_struct *mm,
long __user *bd_entry, unsigned long *bt_addr)
long __user *bd_entry_ptr,
unsigned long *bt_addr_result)
{
int ret;
int valid_bit;
unsigned long bd_entry;
unsigned long bt_addr;
if (!access_ok(VERIFY_READ, (bd_entry), sizeof(*bd_entry)))
if (!access_ok(VERIFY_READ, (bd_entry_ptr), sizeof(*bd_entry_ptr)))
return -EFAULT;
while (1) {
int need_write = 0;
pagefault_disable();
ret = get_user(*bt_addr, bd_entry);
ret = get_user(bd_entry, bd_entry_ptr);
pagefault_enable();
if (!ret)
break;
if (ret == -EFAULT)
ret = mpx_resolve_fault(bd_entry, need_write);
ret = mpx_resolve_fault(bd_entry_ptr, need_write);
/*
* If we could not resolve the fault, consider it
* userspace's fault and error out.
......@@ -607,8 +633,8 @@ static int get_bt_addr(struct mm_struct *mm,
return ret;
}
valid_bit = *bt_addr & MPX_BD_ENTRY_VALID_FLAG;
*bt_addr &= MPX_BT_ADDR_MASK;
valid_bit = bd_entry & MPX_BD_ENTRY_VALID_FLAG;
bt_addr = mpx_bd_entry_to_bt_addr(mm, bd_entry);
/*
* When the kernel is managing bounds tables, a bounds directory
......@@ -617,7 +643,7 @@ static int get_bt_addr(struct mm_struct *mm,
* data in the address field, we know something is wrong. This
* -EINVAL return will cause a SIGSEGV.
*/
if (!valid_bit && *bt_addr)
if (!valid_bit && bt_addr)
return -EINVAL;
/*
* Do we have an completely zeroed bt entry? That is OK. It
......@@ -628,6 +654,7 @@ static int get_bt_addr(struct mm_struct *mm,
if (!valid_bit)
return -ENOENT;
*bt_addr_result = bt_addr;
return 0;
}
......
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