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 <christophe.leroy@c-s.fr> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/55bcc1f25d8200892a31f67a0b024ff3b816c3cc.1579866752.git.christophe.leroy@c-s.fr
This commit is contained in:
parent
88f8c080d4
commit
bedb4dbe44
@ -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))
|
||||
|
||||
if (dir == KUAP_CURRENT) {
|
||||
u32 kuap = current->thread.kuap;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
addr = (__force u32)to;
|
||||
|
||||
if (unlikely(addr >= TASK_SIZE || !size))
|
||||
return;
|
||||
|
||||
end = min(addr + size, TASK_SIZE);
|
||||
current->thread.kuap = 0;
|
||||
kuap_update_sr(mfsrin(addr) | SR_KS, addr, end); /* set Ks */
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user