powerpc: Add set_memory_{p/np}() and remove set_memory_attr()
commit f222ab83df92acf72691a2021e1f0d99880dcdf1 upstream. set_memory_attr() was implemented by commit4d1755b6a7("powerpc/mm: implement set_memory_attr()") because the set_memory_xx() couldn't be used at that time to modify memory "on the fly" as explained it the commit. But set_memory_attr() uses set_pte_at() which leads to warnings when CONFIG_DEBUG_VM is selected, because set_pte_at() is unexpected for updating existing page table entries. The check could be bypassed by using __set_pte_at() instead, as it was the case before commitc988cfd38e("powerpc/32: use set_memory_attr()") but since commit9f7853d760("powerpc/mm: Fix set_memory_*() against concurrent accesses") it is now possible to use set_memory_xx() functions to update page table entries "on the fly" because the update is now atomic. For DEBUG_PAGEALLOC we need to clear and set back _PAGE_PRESENT. Add set_memory_np() and set_memory_p() for that. Replace all uses of set_memory_attr() by the relevant set_memory_xx() and remove set_memory_attr(). Fixes:c988cfd38e("powerpc/32: use set_memory_attr()") Cc: stable@vger.kernel.org Reported-by: Maxime Bizon <mbizon@freebox.fr> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu> Tested-by: Maxime Bizon <mbizon@freebox.fr> Reviewed-by: Russell Currey <ruscur@russell.cc> Depends-on:9f7853d760("powerpc/mm: Fix set_memory_*() against concurrent accesses") Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/cda2b44b55c96f9ac69fa92e68c01084ec9495c5.1640344012.git.christophe.leroy@csgroup.eu Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
a29341e486
commit
f4b0b5a0f3
@@ -6,6 +6,8 @@
|
|||||||
#define SET_MEMORY_RW 1
|
#define SET_MEMORY_RW 1
|
||||||
#define SET_MEMORY_NX 2
|
#define SET_MEMORY_NX 2
|
||||||
#define SET_MEMORY_X 3
|
#define SET_MEMORY_X 3
|
||||||
|
#define SET_MEMORY_NP 4 /* Set memory non present */
|
||||||
|
#define SET_MEMORY_P 5 /* Set memory present */
|
||||||
|
|
||||||
int change_memory_attr(unsigned long addr, int numpages, long action);
|
int change_memory_attr(unsigned long addr, int numpages, long action);
|
||||||
|
|
||||||
@@ -29,6 +31,14 @@ static inline int set_memory_x(unsigned long addr, int numpages)
|
|||||||
return change_memory_attr(addr, numpages, SET_MEMORY_X);
|
return change_memory_attr(addr, numpages, SET_MEMORY_X);
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_memory_attr(unsigned long addr, int numpages, pgprot_t prot);
|
static inline int set_memory_np(unsigned long addr, int numpages)
|
||||||
|
{
|
||||||
|
return change_memory_attr(addr, numpages, SET_MEMORY_NP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int set_memory_p(unsigned long addr, int numpages)
|
||||||
|
{
|
||||||
|
return change_memory_attr(addr, numpages, SET_MEMORY_P);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -48,6 +48,12 @@ static int change_page_attr(pte_t *ptep, unsigned long addr, void *data)
|
|||||||
case SET_MEMORY_X:
|
case SET_MEMORY_X:
|
||||||
pte = pte_mkexec(pte);
|
pte = pte_mkexec(pte);
|
||||||
break;
|
break;
|
||||||
|
case SET_MEMORY_NP:
|
||||||
|
pte_update(&init_mm, addr, ptep, _PAGE_PRESENT, 0, 0);
|
||||||
|
break;
|
||||||
|
case SET_MEMORY_P:
|
||||||
|
pte_update(&init_mm, addr, ptep, 0, _PAGE_PRESENT, 0);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
WARN_ON_ONCE(1);
|
WARN_ON_ONCE(1);
|
||||||
break;
|
break;
|
||||||
@@ -96,36 +102,3 @@ int change_memory_attr(unsigned long addr, int numpages, long action)
|
|||||||
return apply_to_existing_page_range(&init_mm, start, size,
|
return apply_to_existing_page_range(&init_mm, start, size,
|
||||||
change_page_attr, (void *)action);
|
change_page_attr, (void *)action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the attributes of a page:
|
|
||||||
*
|
|
||||||
* This function is used by PPC32 at the end of init to set final kernel memory
|
|
||||||
* protection. It includes changing the maping of the page it is executing from
|
|
||||||
* and data pages it is using.
|
|
||||||
*/
|
|
||||||
static int set_page_attr(pte_t *ptep, unsigned long addr, void *data)
|
|
||||||
{
|
|
||||||
pgprot_t prot = __pgprot((unsigned long)data);
|
|
||||||
|
|
||||||
spin_lock(&init_mm.page_table_lock);
|
|
||||||
|
|
||||||
set_pte_at(&init_mm, addr, ptep, pte_modify(*ptep, prot));
|
|
||||||
flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
|
|
||||||
|
|
||||||
spin_unlock(&init_mm.page_table_lock);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int set_memory_attr(unsigned long addr, int numpages, pgprot_t prot)
|
|
||||||
{
|
|
||||||
unsigned long start = ALIGN_DOWN(addr, PAGE_SIZE);
|
|
||||||
unsigned long sz = numpages * PAGE_SIZE;
|
|
||||||
|
|
||||||
if (numpages <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return apply_to_existing_page_range(&init_mm, start, sz, set_page_attr,
|
|
||||||
(void *)pgprot_val(prot));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -138,10 +138,12 @@ void mark_initmem_nx(void)
|
|||||||
unsigned long numpages = PFN_UP((unsigned long)_einittext) -
|
unsigned long numpages = PFN_UP((unsigned long)_einittext) -
|
||||||
PFN_DOWN((unsigned long)_sinittext);
|
PFN_DOWN((unsigned long)_sinittext);
|
||||||
|
|
||||||
if (v_block_mapped((unsigned long)_sinittext))
|
if (v_block_mapped((unsigned long)_sinittext)) {
|
||||||
mmu_mark_initmem_nx();
|
mmu_mark_initmem_nx();
|
||||||
else
|
} else {
|
||||||
set_memory_attr((unsigned long)_sinittext, numpages, PAGE_KERNEL);
|
set_memory_nx((unsigned long)_sinittext, numpages);
|
||||||
|
set_memory_rw((unsigned long)_sinittext, numpages);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_STRICT_KERNEL_RWX
|
#ifdef CONFIG_STRICT_KERNEL_RWX
|
||||||
@@ -155,18 +157,14 @@ void mark_rodata_ro(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
numpages = PFN_UP((unsigned long)_etext) -
|
|
||||||
PFN_DOWN((unsigned long)_stext);
|
|
||||||
|
|
||||||
set_memory_attr((unsigned long)_stext, numpages, PAGE_KERNEL_ROX);
|
|
||||||
/*
|
/*
|
||||||
* mark .rodata as read only. Use __init_begin rather than __end_rodata
|
* mark .text and .rodata as read only. Use __init_begin rather than
|
||||||
* to cover NOTES and EXCEPTION_TABLE.
|
* __end_rodata to cover NOTES and EXCEPTION_TABLE.
|
||||||
*/
|
*/
|
||||||
numpages = PFN_UP((unsigned long)__init_begin) -
|
numpages = PFN_UP((unsigned long)__init_begin) -
|
||||||
PFN_DOWN((unsigned long)__start_rodata);
|
PFN_DOWN((unsigned long)_stext);
|
||||||
|
|
||||||
set_memory_attr((unsigned long)__start_rodata, numpages, PAGE_KERNEL_RO);
|
set_memory_ro((unsigned long)_stext, numpages);
|
||||||
|
|
||||||
// mark_initmem_nx() should have already run by now
|
// mark_initmem_nx() should have already run by now
|
||||||
ptdump_check_wx();
|
ptdump_check_wx();
|
||||||
@@ -182,8 +180,8 @@ void __kernel_map_pages(struct page *page, int numpages, int enable)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (enable)
|
if (enable)
|
||||||
set_memory_attr(addr, numpages, PAGE_KERNEL);
|
set_memory_p(addr, numpages);
|
||||||
else
|
else
|
||||||
set_memory_attr(addr, numpages, __pgprot(0));
|
set_memory_np(addr, numpages);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_DEBUG_PAGEALLOC */
|
#endif /* CONFIG_DEBUG_PAGEALLOC */
|
||||||
|
|||||||
Reference in New Issue
Block a user