diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/include/asm/book3s/32/kup.h | 23 | ||||
-rw-r--r-- | arch/powerpc/include/asm/book3s/64/kup-radix.h | 4 | ||||
-rw-r--r-- | arch/powerpc/include/asm/kup.h | 11 |
3 files changed, 32 insertions, 6 deletions
diff --git a/arch/powerpc/include/asm/book3s/32/kup.h b/arch/powerpc/include/asm/book3s/32/kup.h index de29fb752cca..17e069291c72 100644 --- a/arch/powerpc/include/asm/book3s/32/kup.h +++ b/arch/powerpc/include/asm/book3s/32/kup.h @@ -108,6 +108,8 @@ static __always_inline void allow_user_access(void __user *to, const void __user u32 addr, end; BUILD_BUG_ON(!__builtin_constant_p(dir)); + BUILD_BUG_ON(dir == KUAP_CURRENT); + if (!(dir & KUAP_WRITE)) return; @@ -117,6 +119,7 @@ static __always_inline void allow_user_access(void __user *to, const void __user return; end = min(addr + size, TASK_SIZE); + current->thread.kuap = (addr & 0xf0000000) | ((((end - 1) >> 28) + 1) & 0xf); kuap_update_sr(mfsrin(addr) & ~SR_KS, addr, end); /* Clear Ks */ } @@ -127,15 +130,25 @@ static __always_inline void prevent_user_access(void __user *to, const void __us u32 addr, end; BUILD_BUG_ON(!__builtin_constant_p(dir)); - if (!(dir & KUAP_WRITE)) - return; - addr = (__force u32)to; + if (dir == KUAP_CURRENT) { + u32 kuap = current->thread.kuap; - if (unlikely(addr >= TASK_SIZE || !size)) + if (unlikely(!kuap)) + return; + + addr = kuap & 0xf0000000; + end = kuap << 28; + } else if (dir & KUAP_WRITE) { + addr = (__force u32)to; + end = min(addr + size, TASK_SIZE); + + if (unlikely(addr >= TASK_SIZE || !size)) + return; + } else { return; + } - end = min(addr + size, TASK_SIZE); current->thread.kuap = 0; kuap_update_sr(mfsrin(addr) | SR_KS, addr, end); /* set Ks */ } diff --git a/arch/powerpc/include/asm/book3s/64/kup-radix.h b/arch/powerpc/include/asm/book3s/64/kup-radix.h index c8d1076e0ebb..a0263e94df33 100644 --- a/arch/powerpc/include/asm/book3s/64/kup-radix.h +++ b/arch/powerpc/include/asm/book3s/64/kup-radix.h @@ -86,8 +86,10 @@ static __always_inline void allow_user_access(void __user *to, const void __user set_kuap(AMR_KUAP_BLOCK_WRITE); else if (dir == KUAP_WRITE) set_kuap(AMR_KUAP_BLOCK_READ); - else + else if (dir == KUAP_READ_WRITE) set_kuap(0); + else + BUILD_BUG(); } static inline void prevent_user_access(void __user *to, const void __user *from, diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h index 94f24928916a..c3ce7e8ae9ea 100644 --- a/arch/powerpc/include/asm/kup.h +++ b/arch/powerpc/include/asm/kup.h @@ -5,6 +5,12 @@ #define KUAP_READ 1 #define KUAP_WRITE 2 #define KUAP_READ_WRITE (KUAP_READ | KUAP_WRITE) +/* + * For prevent_user_access() only. + * Use the current saved situation instead of the to/from/size params. + * Used on book3s/32 + */ +#define KUAP_CURRENT 4 #ifdef CONFIG_PPC64 #include <asm/book3s/64/kup-radix.h> @@ -88,6 +94,11 @@ static inline void prevent_read_write_user(void __user *to, const void __user *f prevent_user_access(to, from, size, KUAP_READ_WRITE); } +static inline void prevent_current_access_user(void) +{ + prevent_user_access(NULL, NULL, ~0UL, KUAP_CURRENT); +} + #endif /* !__ASSEMBLY__ */ #endif /* _ASM_POWERPC_KUAP_H_ */ |