From bedb4dbe443c11ff551b4ae4e48c8676fdc96467 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 24 Jan 2020 11:54:43 +0000 Subject: powerpc/32s: Prepare prevent_user_access() for user_access_end() In preparation of implementing user_access_begin and friends on powerpc, the book3s/32 version of prevent_user_access() need to be prepared for user_access_end(). user_access_end() doesn't provide the address and size which were passed to user_access_begin(), required by prevent_user_access() to know which segment to modify. The list of segments which where unprotected by allow_user_access() are available in current->kuap. But we don't want prevent_user_access() to read this all the time, especially everytime it is 0 (for instance because the access was not a write access). Implement a special direction named KUAP_CURRENT. In this case only, the addr and end are retrieved from current->kuap. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/55bcc1f25d8200892a31f67a0b024ff3b816c3cc.1579866752.git.christophe.leroy@c-s.fr --- arch/powerpc/include/asm/book3s/32/kup.h | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/include/asm/book3s/32/kup.h') 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 */ } -- cgit