powerpc/book3e: Fix set_memory_x() and set_memory_nx()
set_memory_x() calls pte_mkexec() which sets _PAGE_EXEC. set_memory_nx() calls pte_exprotec() which clears _PAGE_EXEC. Book3e has 2 bits, UX and SX, which defines the exec rights resp. for user (PR=1) and for kernel (PR=0). _PAGE_EXEC is defined as UX only. An executable kernel page is set with either _PAGE_KERNEL_RWX or _PAGE_KERNEL_ROX, which both have SX set and UX cleared. So set_memory_nx() call for an executable kernel page does nothing because UX is already cleared. And set_memory_x() on a non-executable kernel page makes it executable for the user and keeps it non-executable for kernel. Also, pte_exec() always returns 'false' on kernel pages, because it checks _PAGE_EXEC which doesn't include SX, so for instance the W+X check doesn't work. To fix this: - change tlb_low_64e.S to use _PAGE_BAP_UX instead of _PAGE_USER - sets both UX and SX in _PAGE_EXEC so that pte_exec() returns true whenever one of the two bits is set and pte_exprotect() clears both bits. - Define a book3e specific version of pte_mkexec() which sets either SX or UX based on UR. Fixes: 1f9ad21c3b38 ("powerpc/mm: Implement set_memory() routines") Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/c41100f9c144dc5b62e5a751b810190c6b5d42fd.1635226743.git.christophe.leroy@csgroup.eu
This commit is contained in:
parent
b1b93cb7e7
commit
b6cb20fdc2
@ -193,10 +193,12 @@ static inline pte_t pte_wrprotect(pte_t pte)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef pte_mkexec
|
||||||
static inline pte_t pte_mkexec(pte_t pte)
|
static inline pte_t pte_mkexec(pte_t pte)
|
||||||
{
|
{
|
||||||
return __pte(pte_val(pte) | _PAGE_EXEC);
|
return __pte(pte_val(pte) | _PAGE_EXEC);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#define pmd_none(pmd) (!pmd_val(pmd))
|
#define pmd_none(pmd) (!pmd_val(pmd))
|
||||||
#define pmd_bad(pmd) (pmd_val(pmd) & _PMD_BAD)
|
#define pmd_bad(pmd) (pmd_val(pmd) & _PMD_BAD)
|
||||||
|
@ -118,11 +118,6 @@ static inline pte_t pte_wrprotect(pte_t pte)
|
|||||||
return __pte(pte_val(pte) & ~_PAGE_RW);
|
return __pte(pte_val(pte) & ~_PAGE_RW);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline pte_t pte_mkexec(pte_t pte)
|
|
||||||
{
|
|
||||||
return __pte(pte_val(pte) | _PAGE_EXEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PMD_BAD_BITS (PTE_TABLE_SIZE-1)
|
#define PMD_BAD_BITS (PTE_TABLE_SIZE-1)
|
||||||
#define PUD_BAD_BITS (PMD_TABLE_SIZE-1)
|
#define PUD_BAD_BITS (PMD_TABLE_SIZE-1)
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
#define _PAGE_WRITETHRU 0x800000 /* W: cache write-through */
|
#define _PAGE_WRITETHRU 0x800000 /* W: cache write-through */
|
||||||
|
|
||||||
/* "Higher level" linux bit combinations */
|
/* "Higher level" linux bit combinations */
|
||||||
#define _PAGE_EXEC _PAGE_BAP_UX /* .. and was cache cleaned */
|
#define _PAGE_EXEC (_PAGE_BAP_SX | _PAGE_BAP_UX) /* .. and was cache cleaned */
|
||||||
#define _PAGE_RW (_PAGE_BAP_SW | _PAGE_BAP_UW) /* User write permission */
|
#define _PAGE_RW (_PAGE_BAP_SW | _PAGE_BAP_UW) /* User write permission */
|
||||||
#define _PAGE_KERNEL_RW (_PAGE_BAP_SW | _PAGE_BAP_SR | _PAGE_DIRTY)
|
#define _PAGE_KERNEL_RW (_PAGE_BAP_SW | _PAGE_BAP_SR | _PAGE_DIRTY)
|
||||||
#define _PAGE_KERNEL_RO (_PAGE_BAP_SR)
|
#define _PAGE_KERNEL_RO (_PAGE_BAP_SR)
|
||||||
@ -93,11 +93,11 @@
|
|||||||
/* Permission masks used to generate the __P and __S table */
|
/* Permission masks used to generate the __P and __S table */
|
||||||
#define PAGE_NONE __pgprot(_PAGE_BASE)
|
#define PAGE_NONE __pgprot(_PAGE_BASE)
|
||||||
#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
|
#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
|
||||||
#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC)
|
#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_BAP_UX)
|
||||||
#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER)
|
#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER)
|
||||||
#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
|
#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_BAP_UX)
|
||||||
#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER)
|
#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER)
|
||||||
#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
|
#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_BAP_UX)
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
static inline pte_t pte_mkprivileged(pte_t pte)
|
static inline pte_t pte_mkprivileged(pte_t pte)
|
||||||
@ -113,6 +113,16 @@ static inline pte_t pte_mkuser(pte_t pte)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define pte_mkuser pte_mkuser
|
#define pte_mkuser pte_mkuser
|
||||||
|
|
||||||
|
static inline pte_t pte_mkexec(pte_t pte)
|
||||||
|
{
|
||||||
|
if (pte_val(pte) & _PAGE_BAP_UR)
|
||||||
|
return __pte((pte_val(pte) & ~_PAGE_BAP_SX) | _PAGE_BAP_UX);
|
||||||
|
else
|
||||||
|
return __pte((pte_val(pte) & ~_PAGE_BAP_UX) | _PAGE_BAP_SX);
|
||||||
|
}
|
||||||
|
#define pte_mkexec pte_mkexec
|
||||||
|
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
|
@ -222,7 +222,7 @@ tlb_miss_kernel_bolted:
|
|||||||
|
|
||||||
tlb_miss_fault_bolted:
|
tlb_miss_fault_bolted:
|
||||||
/* We need to check if it was an instruction miss */
|
/* We need to check if it was an instruction miss */
|
||||||
andi. r10,r11,_PAGE_EXEC|_PAGE_BAP_SX
|
andi. r10,r11,_PAGE_BAP_UX|_PAGE_BAP_SX
|
||||||
bne itlb_miss_fault_bolted
|
bne itlb_miss_fault_bolted
|
||||||
dtlb_miss_fault_bolted:
|
dtlb_miss_fault_bolted:
|
||||||
tlb_epilog_bolted
|
tlb_epilog_bolted
|
||||||
@ -239,7 +239,7 @@ itlb_miss_fault_bolted:
|
|||||||
srdi r15,r16,60 /* get region */
|
srdi r15,r16,60 /* get region */
|
||||||
bne- itlb_miss_fault_bolted
|
bne- itlb_miss_fault_bolted
|
||||||
|
|
||||||
li r11,_PAGE_PRESENT|_PAGE_EXEC /* Base perm */
|
li r11,_PAGE_PRESENT|_PAGE_BAP_UX /* Base perm */
|
||||||
|
|
||||||
/* We do the user/kernel test for the PID here along with the RW test
|
/* We do the user/kernel test for the PID here along with the RW test
|
||||||
*/
|
*/
|
||||||
@ -614,7 +614,7 @@ itlb_miss_fault_e6500:
|
|||||||
|
|
||||||
/* We do the user/kernel test for the PID here along with the RW test
|
/* We do the user/kernel test for the PID here along with the RW test
|
||||||
*/
|
*/
|
||||||
li r11,_PAGE_PRESENT|_PAGE_EXEC /* Base perm */
|
li r11,_PAGE_PRESENT|_PAGE_BAP_UX /* Base perm */
|
||||||
oris r11,r11,_PAGE_ACCESSED@h
|
oris r11,r11,_PAGE_ACCESSED@h
|
||||||
|
|
||||||
cmpldi cr0,r15,0 /* Check for user region */
|
cmpldi cr0,r15,0 /* Check for user region */
|
||||||
@ -734,7 +734,7 @@ normal_tlb_miss_done:
|
|||||||
|
|
||||||
normal_tlb_miss_access_fault:
|
normal_tlb_miss_access_fault:
|
||||||
/* We need to check if it was an instruction miss */
|
/* We need to check if it was an instruction miss */
|
||||||
andi. r10,r11,_PAGE_EXEC
|
andi. r10,r11,_PAGE_BAP_UX
|
||||||
bne 1f
|
bne 1f
|
||||||
ld r14,EX_TLB_DEAR(r12)
|
ld r14,EX_TLB_DEAR(r12)
|
||||||
ld r15,EX_TLB_ESR(r12)
|
ld r15,EX_TLB_ESR(r12)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user