diff options
Diffstat (limited to 'arch/x86/mm/mpx.c')
-rw-r--r-- | arch/x86/mm/mpx.c | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c index b0ae85f90f10..1202d5ca2fb5 100644 --- a/arch/x86/mm/mpx.c +++ b/arch/x86/mm/mpx.c | |||
@@ -586,6 +586,29 @@ static unsigned long mpx_bd_entry_to_bt_addr(struct mm_struct *mm, | |||
586 | } | 586 | } |
587 | 587 | ||
588 | /* | 588 | /* |
589 | * We only want to do a 4-byte get_user() on 32-bit. Otherwise, | ||
590 | * we might run off the end of the bounds table if we are on | ||
591 | * a 64-bit kernel and try to get 8 bytes. | ||
592 | */ | ||
593 | int get_user_bd_entry(struct mm_struct *mm, unsigned long *bd_entry_ret, | ||
594 | long __user *bd_entry_ptr) | ||
595 | { | ||
596 | u32 bd_entry_32; | ||
597 | int ret; | ||
598 | |||
599 | if (is_64bit_mm(mm)) | ||
600 | return get_user(*bd_entry_ret, bd_entry_ptr); | ||
601 | |||
602 | /* | ||
603 | * Note that get_user() uses the type of the *pointer* to | ||
604 | * establish the size of the get, not the destination. | ||
605 | */ | ||
606 | ret = get_user(bd_entry_32, (u32 __user *)bd_entry_ptr); | ||
607 | *bd_entry_ret = bd_entry_32; | ||
608 | return ret; | ||
609 | } | ||
610 | |||
611 | /* | ||
589 | * Get the base of bounds tables pointed by specific bounds | 612 | * Get the base of bounds tables pointed by specific bounds |
590 | * directory entry. | 613 | * directory entry. |
591 | */ | 614 | */ |
@@ -605,7 +628,7 @@ static int get_bt_addr(struct mm_struct *mm, | |||
605 | int need_write = 0; | 628 | int need_write = 0; |
606 | 629 | ||
607 | pagefault_disable(); | 630 | pagefault_disable(); |
608 | ret = get_user(bd_entry, bd_entry_ptr); | 631 | ret = get_user_bd_entry(mm, &bd_entry, bd_entry_ptr); |
609 | pagefault_enable(); | 632 | pagefault_enable(); |
610 | if (!ret) | 633 | if (!ret) |
611 | break; | 634 | break; |
@@ -700,11 +723,23 @@ static unsigned long mpx_get_bt_entry_offset_bytes(struct mm_struct *mm, | |||
700 | */ | 723 | */ |
701 | static inline unsigned long bd_entry_virt_space(struct mm_struct *mm) | 724 | static inline unsigned long bd_entry_virt_space(struct mm_struct *mm) |
702 | { | 725 | { |
703 | unsigned long long virt_space = (1ULL << boot_cpu_data.x86_virt_bits); | 726 | unsigned long long virt_space; |
704 | if (is_64bit_mm(mm)) | 727 | unsigned long long GB = (1ULL << 30); |
705 | return virt_space / MPX_BD_NR_ENTRIES_64; | 728 | |
706 | else | 729 | /* |
707 | return virt_space / MPX_BD_NR_ENTRIES_32; | 730 | * This covers 32-bit emulation as well as 32-bit kernels |
731 | * running on 64-bit harware. | ||
732 | */ | ||
733 | if (!is_64bit_mm(mm)) | ||
734 | return (4ULL * GB) / MPX_BD_NR_ENTRIES_32; | ||
735 | |||
736 | /* | ||
737 | * 'x86_virt_bits' returns what the hardware is capable | ||
738 | * of, and returns the full >32-bit adddress space when | ||
739 | * running 32-bit kernels on 64-bit hardware. | ||
740 | */ | ||
741 | virt_space = (1ULL << boot_cpu_data.x86_virt_bits); | ||
742 | return virt_space / MPX_BD_NR_ENTRIES_64; | ||
708 | } | 743 | } |
709 | 744 | ||
710 | /* | 745 | /* |