mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 11:21:26 -04:00
Merge branch 'page-table-check-support' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux into features
Add s390 support for CONFIG_PAGE_TABLE_CHECK. * 'page-table-check-support' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390: Enable page table check for debug_defconfig s390/pgtable: Add s390 support for page table check s390/pgtable: Use set_pmd_bit() to invalidate PMD entry mm/page_table_check: Pass mm_struct to pxx_user_accessible_page() Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
This commit is contained in:
@@ -1263,17 +1263,17 @@ static inline int pmdp_set_access_flags(struct vm_area_struct *vma,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PAGE_TABLE_CHECK
|
||||
static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
|
||||
static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
|
||||
{
|
||||
return pte_valid(pte) && (pte_user(pte) || pte_user_exec(pte));
|
||||
}
|
||||
|
||||
static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
|
||||
static inline bool pmd_user_accessible_page(struct mm_struct *mm, unsigned long addr, pmd_t pmd)
|
||||
{
|
||||
return pmd_valid(pmd) && !pmd_table(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
|
||||
}
|
||||
|
||||
static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
|
||||
static inline bool pud_user_accessible_page(struct mm_struct *mm, unsigned long addr, pud_t pud)
|
||||
{
|
||||
return pud_valid(pud) && !pud_table(pud) && (pud_user(pud) || pud_user_exec(pud));
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
|
||||
static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
|
||||
{
|
||||
return pte_present(pte) && !is_kernel_addr(addr);
|
||||
}
|
||||
|
||||
@@ -549,7 +549,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
|
||||
return arch_pte_access_permitted(pte_val(pte), write, 0);
|
||||
}
|
||||
|
||||
static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
|
||||
static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
|
||||
{
|
||||
return pte_present(pte) && pte_user(pte);
|
||||
}
|
||||
@@ -925,9 +925,9 @@ static inline bool pud_access_permitted(pud_t pud, bool write)
|
||||
}
|
||||
|
||||
#define pud_user_accessible_page pud_user_accessible_page
|
||||
static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
|
||||
static inline bool pud_user_accessible_page(struct mm_struct *mm, unsigned long addr, pud_t pud)
|
||||
{
|
||||
return pud_leaf(pud) && pte_user_accessible_page(pud_pte(pud), addr);
|
||||
return pud_leaf(pud) && pte_user_accessible_page(mm, addr, pud_pte(pud));
|
||||
}
|
||||
|
||||
#define __p4d_raw(x) ((p4d_t) { __pgd_raw(x) })
|
||||
@@ -1096,9 +1096,9 @@ static inline bool pmd_access_permitted(pmd_t pmd, bool write)
|
||||
}
|
||||
|
||||
#define pmd_user_accessible_page pmd_user_accessible_page
|
||||
static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
|
||||
static inline bool pmd_user_accessible_page(struct mm_struct *mm, unsigned long addr, pmd_t pmd)
|
||||
{
|
||||
return pmd_leaf(pmd) && pte_user_accessible_page(pmd_pte(pmd), addr);
|
||||
return pmd_leaf(pmd) && pte_user_accessible_page(mm, addr, pmd_pte(pmd));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
|
||||
@@ -249,7 +249,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
|
||||
static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
|
||||
{
|
||||
return pte_present(pte) && !is_kernel_addr(addr);
|
||||
}
|
||||
|
||||
@@ -205,11 +205,11 @@ static inline bool arch_supports_memmap_on_memory(unsigned long vmemmap_size)
|
||||
#endif /* CONFIG_PPC64 */
|
||||
|
||||
#ifndef pmd_user_accessible_page
|
||||
#define pmd_user_accessible_page(pmd, addr) false
|
||||
#define pmd_user_accessible_page(mm, addr, pmd) false
|
||||
#endif
|
||||
|
||||
#ifndef pud_user_accessible_page
|
||||
#define pud_user_accessible_page(pud, addr) false
|
||||
#define pud_user_accessible_page(mm, addr, pud) false
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
@@ -984,17 +984,17 @@ static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PAGE_TABLE_CHECK
|
||||
static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
|
||||
static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
|
||||
{
|
||||
return pte_present(pte) && pte_user(pte);
|
||||
}
|
||||
|
||||
static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
|
||||
static inline bool pmd_user_accessible_page(struct mm_struct *mm, unsigned long addr, pmd_t pmd)
|
||||
{
|
||||
return pmd_leaf(pmd) && pmd_user(pmd);
|
||||
}
|
||||
|
||||
static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
|
||||
static inline bool pud_user_accessible_page(struct mm_struct *mm, unsigned long addr, pud_t pud)
|
||||
{
|
||||
return pud_leaf(pud) && pud_user(pud);
|
||||
}
|
||||
|
||||
@@ -154,6 +154,7 @@ config S390
|
||||
select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 && CC_IS_CLANG
|
||||
select ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS
|
||||
select ARCH_SUPPORTS_NUMA_BALANCING
|
||||
select ARCH_SUPPORTS_PAGE_TABLE_CHECK
|
||||
select ARCH_SUPPORTS_PER_VMA_LOCK
|
||||
select ARCH_USE_BUILTIN_BSWAP
|
||||
select ARCH_USE_CMPXCHG_LOCKREF
|
||||
|
||||
@@ -929,3 +929,5 @@ CONFIG_PERCPU_TEST=m
|
||||
CONFIG_ATOMIC64_SELFTEST=y
|
||||
CONFIG_TEST_BITOPS=m
|
||||
CONFIG_TEST_BPF=m
|
||||
CONFIG_PAGE_TABLE_CHECK=y
|
||||
CONFIG_PAGE_TABLE_CHECK_ENFORCED=y
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/cpufeature.h>
|
||||
#include <linux/page-flags.h>
|
||||
#include <linux/page_table_check.h>
|
||||
#include <linux/radix-tree.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/mmap_lock.h>
|
||||
#include <asm/ctlreg.h>
|
||||
#include <asm/bug.h>
|
||||
#include <asm/page.h>
|
||||
@@ -1190,6 +1192,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
|
||||
/* At this point the reference through the mapping is still present */
|
||||
if (mm_is_protected(mm) && pte_present(res))
|
||||
WARN_ON_ONCE(uv_convert_from_secure_pte(res));
|
||||
page_table_check_pte_clear(mm, addr, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1208,6 +1211,7 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
|
||||
/* At this point the reference through the mapping is still present */
|
||||
if (mm_is_protected(vma->vm_mm) && pte_present(res))
|
||||
WARN_ON_ONCE(uv_convert_from_secure_pte(res));
|
||||
page_table_check_pte_clear(vma->vm_mm, addr, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1231,6 +1235,9 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
|
||||
} else {
|
||||
res = ptep_xchg_lazy(mm, addr, ptep, __pte(_PAGE_INVALID));
|
||||
}
|
||||
|
||||
page_table_check_pte_clear(mm, addr, res);
|
||||
|
||||
/* Nothing to do */
|
||||
if (!mm_is_protected(mm) || !pte_present(res))
|
||||
return res;
|
||||
@@ -1327,6 +1334,7 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
|
||||
{
|
||||
if (pte_present(entry))
|
||||
entry = clear_pte_bit(entry, __pgprot(_PAGE_UNUSED));
|
||||
page_table_check_ptes_set(mm, addr, ptep, entry, nr);
|
||||
for (;;) {
|
||||
set_pte(ptep, entry);
|
||||
if (--nr == 0)
|
||||
@@ -1703,6 +1711,7 @@ static inline int pmdp_clear_flush_young(struct vm_area_struct *vma,
|
||||
static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
|
||||
pmd_t *pmdp, pmd_t entry)
|
||||
{
|
||||
page_table_check_pmd_set(mm, addr, pmdp, entry);
|
||||
set_pmd(pmdp, entry);
|
||||
}
|
||||
|
||||
@@ -1717,7 +1726,11 @@ static inline pmd_t pmd_mkhuge(pmd_t pmd)
|
||||
static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
|
||||
unsigned long addr, pmd_t *pmdp)
|
||||
{
|
||||
return pmdp_xchg_direct(mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_EMPTY));
|
||||
pmd_t pmd;
|
||||
|
||||
pmd = pmdp_xchg_direct(mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_EMPTY));
|
||||
page_table_check_pmd_clear(mm, addr, pmd);
|
||||
return pmd;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR_FULL
|
||||
@@ -1725,12 +1738,17 @@ static inline pmd_t pmdp_huge_get_and_clear_full(struct vm_area_struct *vma,
|
||||
unsigned long addr,
|
||||
pmd_t *pmdp, int full)
|
||||
{
|
||||
pmd_t pmd;
|
||||
|
||||
if (full) {
|
||||
pmd_t pmd = *pmdp;
|
||||
pmd = *pmdp;
|
||||
set_pmd(pmdp, __pmd(_SEGMENT_ENTRY_EMPTY));
|
||||
page_table_check_pmd_clear(vma->vm_mm, addr, pmd);
|
||||
return pmd;
|
||||
}
|
||||
return pmdp_xchg_lazy(vma->vm_mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_EMPTY));
|
||||
pmd = pmdp_xchg_lazy(vma->vm_mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_EMPTY));
|
||||
page_table_check_pmd_clear(vma->vm_mm, addr, pmd);
|
||||
return pmd;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_PMDP_HUGE_CLEAR_FLUSH
|
||||
@@ -1744,11 +1762,16 @@ static inline pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma,
|
||||
static inline pmd_t pmdp_invalidate(struct vm_area_struct *vma,
|
||||
unsigned long addr, pmd_t *pmdp)
|
||||
{
|
||||
pmd_t pmd;
|
||||
pmd_t pmd = *pmdp;
|
||||
|
||||
VM_WARN_ON_ONCE(!pmd_present(*pmdp));
|
||||
pmd = __pmd(pmd_val(*pmdp) | _SEGMENT_ENTRY_INVALID);
|
||||
return pmdp_xchg_direct(vma->vm_mm, addr, pmdp, pmd);
|
||||
VM_WARN_ON_ONCE(!pmd_present(pmd));
|
||||
pmd = set_pmd_bit(pmd, __pgprot(_SEGMENT_ENTRY_INVALID));
|
||||
#ifdef CONFIG_PAGE_TABLE_CHECK
|
||||
pmd = clear_pmd_bit(pmd, __pgprot(_SEGMENT_ENTRY_READ));
|
||||
#endif
|
||||
page_table_check_pmd_set(vma->vm_mm, addr, pmdp, pmd);
|
||||
pmd = pmdp_xchg_direct(vma->vm_mm, addr, pmdp, pmd);
|
||||
return pmd;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_PMDP_SET_WRPROTECT
|
||||
@@ -1783,6 +1806,29 @@ static inline int has_transparent_hugepage(void)
|
||||
}
|
||||
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
||||
|
||||
#ifdef CONFIG_PAGE_TABLE_CHECK
|
||||
static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
|
||||
{
|
||||
VM_BUG_ON(mm == &init_mm);
|
||||
|
||||
return pte_present(pte);
|
||||
}
|
||||
|
||||
static inline bool pmd_user_accessible_page(struct mm_struct *mm, unsigned long addr, pmd_t pmd)
|
||||
{
|
||||
VM_BUG_ON(mm == &init_mm);
|
||||
|
||||
return pmd_leaf(pmd) && (pmd_val(pmd) & _SEGMENT_ENTRY_READ);
|
||||
}
|
||||
|
||||
static inline bool pud_user_accessible_page(struct mm_struct *mm, unsigned long addr, pud_t pud)
|
||||
{
|
||||
VM_BUG_ON(mm == &init_mm);
|
||||
|
||||
return pud_leaf(pud);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 64 bit swap entry format:
|
||||
* A page-table entry has some bits we have to treat in a special way.
|
||||
|
||||
@@ -1680,17 +1680,17 @@ static inline bool arch_has_hw_nonleaf_pmd_young(void)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PAGE_TABLE_CHECK
|
||||
static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
|
||||
static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
|
||||
{
|
||||
return (pte_val(pte) & _PAGE_PRESENT) && (pte_val(pte) & _PAGE_USER);
|
||||
}
|
||||
|
||||
static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
|
||||
static inline bool pmd_user_accessible_page(struct mm_struct *mm, unsigned long addr, pmd_t pmd)
|
||||
{
|
||||
return pmd_leaf(pmd) && (pmd_val(pmd) & _PAGE_PRESENT) && (pmd_val(pmd) & _PAGE_USER);
|
||||
}
|
||||
|
||||
static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
|
||||
static inline bool pud_user_accessible_page(struct mm_struct *mm, unsigned long addr, pud_t pud)
|
||||
{
|
||||
return pud_leaf(pud) && (pud_val(pud) & _PAGE_PRESENT) && (pud_val(pud) & _PAGE_USER);
|
||||
}
|
||||
|
||||
@@ -151,9 +151,8 @@ void __page_table_check_pte_clear(struct mm_struct *mm, unsigned long addr,
|
||||
if (&init_mm == mm)
|
||||
return;
|
||||
|
||||
if (pte_user_accessible_page(pte, addr)) {
|
||||
if (pte_user_accessible_page(mm, addr, pte))
|
||||
page_table_check_clear(pte_pfn(pte), PAGE_SIZE >> PAGE_SHIFT);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(__page_table_check_pte_clear);
|
||||
|
||||
@@ -163,9 +162,8 @@ void __page_table_check_pmd_clear(struct mm_struct *mm, unsigned long addr,
|
||||
if (&init_mm == mm)
|
||||
return;
|
||||
|
||||
if (pmd_user_accessible_page(pmd, addr)) {
|
||||
if (pmd_user_accessible_page(mm, addr, pmd))
|
||||
page_table_check_clear(pmd_pfn(pmd), PMD_SIZE >> PAGE_SHIFT);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(__page_table_check_pmd_clear);
|
||||
|
||||
@@ -175,9 +173,8 @@ void __page_table_check_pud_clear(struct mm_struct *mm, unsigned long addr,
|
||||
if (&init_mm == mm)
|
||||
return;
|
||||
|
||||
if (pud_user_accessible_page(pud, addr)) {
|
||||
if (pud_user_accessible_page(mm, addr, pud))
|
||||
page_table_check_clear(pud_pfn(pud), PUD_SIZE >> PAGE_SHIFT);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(__page_table_check_pud_clear);
|
||||
|
||||
@@ -211,7 +208,7 @@ void __page_table_check_ptes_set(struct mm_struct *mm, unsigned long addr,
|
||||
|
||||
for (i = 0; i < nr; i++)
|
||||
__page_table_check_pte_clear(mm, addr + PAGE_SIZE * i, ptep_get(ptep + i));
|
||||
if (pte_user_accessible_page(pte, addr))
|
||||
if (pte_user_accessible_page(mm, addr, pte))
|
||||
page_table_check_set(pte_pfn(pte), nr, pte_write(pte));
|
||||
}
|
||||
EXPORT_SYMBOL(__page_table_check_ptes_set);
|
||||
@@ -241,7 +238,7 @@ void __page_table_check_pmds_set(struct mm_struct *mm, unsigned long addr,
|
||||
|
||||
for (i = 0; i < nr; i++)
|
||||
__page_table_check_pmd_clear(mm, addr + PMD_SIZE * i, *(pmdp + i));
|
||||
if (pmd_user_accessible_page(pmd, addr))
|
||||
if (pmd_user_accessible_page(mm, addr, pmd))
|
||||
page_table_check_set(pmd_pfn(pmd), stride * nr, pmd_write(pmd));
|
||||
}
|
||||
EXPORT_SYMBOL(__page_table_check_pmds_set);
|
||||
@@ -257,7 +254,7 @@ void __page_table_check_puds_set(struct mm_struct *mm, unsigned long addr,
|
||||
|
||||
for (i = 0; i < nr; i++)
|
||||
__page_table_check_pud_clear(mm, addr + PUD_SIZE * i, *(pudp + i));
|
||||
if (pud_user_accessible_page(pud, addr))
|
||||
if (pud_user_accessible_page(mm, addr, pud))
|
||||
page_table_check_set(pud_pfn(pud), stride * nr, pud_write(pud));
|
||||
}
|
||||
EXPORT_SYMBOL(__page_table_check_puds_set);
|
||||
|
||||
Reference in New Issue
Block a user