aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-04-29 16:03:27 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-04 01:56:14 -0400
commit26cf432551d749e7d581db33529507a711c6eaab (patch)
tree2a877a04947ec6ef487a7fe5c60f1c432a67bf94
parent0eef331a3d0ee970dcbebd1bd5fcb57ca33ece01 (diff)
sparc64: Add basic validations to {pud,pmd}_bad().
Instead of returning false we should at least check the most basic things, otherwise page table corruptions will be very difficult to debug. PMD and PTE tables are of size PAGE_SIZE, so none of the sub-PAGE_SIZE bits should be set. We also complement this with a check that the physical address the pud/pmd points to is valid memory. PowerPC was used as a guide while implementating this. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc/include/asm/pgtable_64.h46
1 files changed, 31 insertions, 15 deletions
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 0ad0a1285bd0..baccf35621c0 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -71,6 +71,23 @@
71 71
72#include <linux/sched.h> 72#include <linux/sched.h>
73 73
74extern unsigned long sparc64_valid_addr_bitmap[];
75
76/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
77static inline bool __kern_addr_valid(unsigned long paddr)
78{
79 if ((paddr >> MAX_PHYS_ADDRESS_BITS) != 0UL)
80 return false;
81 return test_bit(paddr >> ILOG2_4MB, sparc64_valid_addr_bitmap);
82}
83
84static inline bool kern_addr_valid(unsigned long addr)
85{
86 unsigned long paddr = __pa(addr);
87
88 return __kern_addr_valid(paddr);
89}
90
74/* Entries per page directory level. */ 91/* Entries per page directory level. */
75#define PTRS_PER_PTE (1UL << (PAGE_SHIFT-3)) 92#define PTRS_PER_PTE (1UL << (PAGE_SHIFT-3))
76#define PTRS_PER_PMD (1UL << PMD_BITS) 93#define PTRS_PER_PMD (1UL << PMD_BITS)
@@ -743,6 +760,20 @@ static inline int pmd_present(pmd_t pmd)
743 760
744#define pmd_none(pmd) (!pmd_val(pmd)) 761#define pmd_none(pmd) (!pmd_val(pmd))
745 762
763/* pmd_bad() is only called on non-trans-huge PMDs. Our encoding is
764 * very simple, it's just the physical address. PTE tables are of
765 * size PAGE_SIZE so make sure the sub-PAGE_SIZE bits are clear and
766 * the top bits outside of the range of any physical address size we
767 * support are clear as well. We also validate the physical itself.
768 */
769#define pmd_bad(pmd) ((pmd_val(pmd) & ~PAGE_MASK) || \
770 !__kern_addr_valid(pmd_val(pmd)))
771
772#define pud_none(pud) (!pud_val(pud))
773
774#define pud_bad(pud) ((pud_val(pud) & ~PAGE_MASK) || \
775 !__kern_addr_valid(pud_val(pud)))
776
746#ifdef CONFIG_TRANSPARENT_HUGEPAGE 777#ifdef CONFIG_TRANSPARENT_HUGEPAGE
747extern void set_pmd_at(struct mm_struct *mm, unsigned long addr, 778extern void set_pmd_at(struct mm_struct *mm, unsigned long addr,
748 pmd_t *pmdp, pmd_t pmd); 779 pmd_t *pmdp, pmd_t pmd);
@@ -776,10 +807,7 @@ static inline unsigned long __pmd_page(pmd_t pmd)
776#define pud_page_vaddr(pud) \ 807#define pud_page_vaddr(pud) \
777 ((unsigned long) __va(pud_val(pud))) 808 ((unsigned long) __va(pud_val(pud)))
778#define pud_page(pud) virt_to_page((void *)pud_page_vaddr(pud)) 809#define pud_page(pud) virt_to_page((void *)pud_page_vaddr(pud))
779#define pmd_bad(pmd) (0)
780#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0UL) 810#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0UL)
781#define pud_none(pud) (!pud_val(pud))
782#define pud_bad(pud) (0)
783#define pud_present(pud) (pud_val(pud) != 0U) 811#define pud_present(pud) (pud_val(pud) != 0U)
784#define pud_clear(pudp) (pud_val(*(pudp)) = 0UL) 812#define pud_clear(pudp) (pud_val(*(pudp)) = 0UL)
785 813
@@ -909,18 +937,6 @@ extern unsigned long pte_file(pte_t);
909extern pte_t pgoff_to_pte(unsigned long); 937extern pte_t pgoff_to_pte(unsigned long);
910#define PTE_FILE_MAX_BITS (64UL - PAGE_SHIFT - 1UL) 938#define PTE_FILE_MAX_BITS (64UL - PAGE_SHIFT - 1UL)
911 939
912extern unsigned long sparc64_valid_addr_bitmap[];
913
914/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
915static inline bool kern_addr_valid(unsigned long addr)
916{
917 unsigned long paddr = __pa(addr);
918
919 if ((paddr >> MAX_PHYS_ADDRESS_BITS) != 0UL)
920 return false;
921 return test_bit(paddr >> ILOG2_4MB, sparc64_valid_addr_bitmap);
922}
923
924extern int page_in_phys_avail(unsigned long paddr); 940extern int page_in_phys_avail(unsigned long paddr);
925 941
926/* 942/*