Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas 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.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Dave Hansen and committed by
Ingo Molnar
54587653 a1149fc8

+34 -8
-1
arch/x86/include/asm/mpx.h
··· 45 45 #define MPX_BNDSTA_TAIL 2 46 46 #define MPX_BNDCFG_TAIL 12 47 47 #define MPX_BNDSTA_ADDR_MASK (~((1UL<<MPX_BNDSTA_TAIL)-1)) 48 - #define MPX_BT_ADDR_MASK (~((1UL<<MPX_BD_ENTRY_TAIL)-1)) 49 48 50 49 #define MPX_BNDCFG_ADDR_MASK (~((1UL<<MPX_BNDCFG_TAIL)-1)) 51 50 #define MPX_BNDSTA_ERROR_CODE 0x3
+34 -7
arch/x86/mm/mpx.c
··· 576 576 return 0; 577 577 } 578 578 579 + static unsigned long mpx_bd_entry_to_bt_addr(struct mm_struct *mm, 580 + unsigned long bd_entry) 581 + { 582 + unsigned long bt_addr = bd_entry; 583 + int align_to_bytes; 584 + /* 585 + * Bit 0 in a bt_entry is always the valid bit. 586 + */ 587 + bt_addr &= ~MPX_BD_ENTRY_VALID_FLAG; 588 + /* 589 + * Tables are naturally aligned at 8-byte boundaries 590 + * on 64-bit and 4-byte boundaries on 32-bit. The 591 + * documentation makes it appear that the low bits 592 + * are ignored by the hardware, so we do the same. 593 + */ 594 + if (is_64bit_mm(mm)) 595 + align_to_bytes = 8; 596 + else 597 + align_to_bytes = 4; 598 + bt_addr &= ~(align_to_bytes-1); 599 + return bt_addr; 600 + } 601 + 579 602 /* 580 603 * Get the base of bounds tables pointed by specific bounds 581 604 * directory entry. 582 605 */ 583 606 static int get_bt_addr(struct mm_struct *mm, 584 - long __user *bd_entry, unsigned long *bt_addr) 607 + long __user *bd_entry_ptr, 608 + unsigned long *bt_addr_result) 585 609 { 586 610 int ret; 587 611 int valid_bit; 612 + unsigned long bd_entry; 613 + unsigned long bt_addr; 588 614 589 - if (!access_ok(VERIFY_READ, (bd_entry), sizeof(*bd_entry))) 615 + if (!access_ok(VERIFY_READ, (bd_entry_ptr), sizeof(*bd_entry_ptr))) 590 616 return -EFAULT; 591 617 592 618 while (1) { 593 619 int need_write = 0; 594 620 595 621 pagefault_disable(); 596 - ret = get_user(*bt_addr, bd_entry); 622 + ret = get_user(bd_entry, bd_entry_ptr); 597 623 pagefault_enable(); 598 624 if (!ret) 599 625 break; 600 626 if (ret == -EFAULT) 601 - ret = mpx_resolve_fault(bd_entry, need_write); 627 + ret = mpx_resolve_fault(bd_entry_ptr, need_write); 602 628 /* 603 629 * If we could not resolve the fault, consider it 604 630 * userspace's fault and error out. ··· 633 607 return ret; 634 608 } 635 609 636 - valid_bit = *bt_addr & MPX_BD_ENTRY_VALID_FLAG; 637 - *bt_addr &= MPX_BT_ADDR_MASK; 610 + valid_bit = bd_entry & MPX_BD_ENTRY_VALID_FLAG; 611 + bt_addr = mpx_bd_entry_to_bt_addr(mm, bd_entry); 638 612 639 613 /* 640 614 * When the kernel is managing bounds tables, a bounds directory ··· 643 617 * data in the address field, we know something is wrong. This 644 618 * -EINVAL return will cause a SIGSEGV. 645 619 */ 646 - if (!valid_bit && *bt_addr) 620 + if (!valid_bit && bt_addr) 647 621 return -EINVAL; 648 622 /* 649 623 * Do we have an completely zeroed bt entry? That is OK. It ··· 654 628 if (!valid_bit) 655 629 return -ENOENT; 656 630 631 + *bt_addr_result = bt_addr; 657 632 return 0; 658 633 } 659 634