mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-19 08:46:49 +07:00
powerpc: Implement user_access_save() and user_access_restore()
Implement user_access_save() and user_access_restore() On 8xx and radix: - On save, get the value of the associated special register then prevent user access. - On restore, set back the saved value to the associated special register. On book3s/32: - On save, get the value stored in current->thread.kuap and prevent user access. - On restore, regenerate address range from the stored value and reopen read/write access for that range. 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/54f2f74938006b33c55a416674807b42ef222068.1579866752.git.christophe.leroy@c-s.fr
This commit is contained in:
parent
5cd623333e
commit
3d7dfd632f
@ -153,6 +153,29 @@ static __always_inline void prevent_user_access(void __user *to, const void __us
|
||||
kuap_update_sr(mfsrin(addr) | SR_KS, addr, end); /* set Ks */
|
||||
}
|
||||
|
||||
static inline unsigned long prevent_user_access_return(void)
|
||||
{
|
||||
unsigned long flags = current->thread.kuap;
|
||||
unsigned long addr = flags & 0xf0000000;
|
||||
unsigned long end = flags << 28;
|
||||
void __user *to = (__force void __user *)addr;
|
||||
|
||||
if (flags)
|
||||
prevent_user_access(to, to, end - addr, KUAP_READ_WRITE);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline void restore_user_access(unsigned long flags)
|
||||
{
|
||||
unsigned long addr = flags & 0xf0000000;
|
||||
unsigned long end = flags << 28;
|
||||
void __user *to = (__force void __user *)addr;
|
||||
|
||||
if (flags)
|
||||
allow_user_access(to, to, end - addr, KUAP_READ_WRITE);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
|
||||
{
|
||||
|
@ -63,6 +63,14 @@
|
||||
* because that would require an expensive read/modify write of the AMR.
|
||||
*/
|
||||
|
||||
static inline unsigned long get_kuap(void)
|
||||
{
|
||||
if (!early_mmu_has_feature(MMU_FTR_RADIX_KUAP))
|
||||
return 0;
|
||||
|
||||
return mfspr(SPRN_AMR);
|
||||
}
|
||||
|
||||
static inline void set_kuap(unsigned long value)
|
||||
{
|
||||
if (!early_mmu_has_feature(MMU_FTR_RADIX_KUAP))
|
||||
@ -98,6 +106,20 @@ static inline void prevent_user_access(void __user *to, const void __user *from,
|
||||
set_kuap(AMR_KUAP_BLOCKED);
|
||||
}
|
||||
|
||||
static inline unsigned long prevent_user_access_return(void)
|
||||
{
|
||||
unsigned long flags = get_kuap();
|
||||
|
||||
set_kuap(AMR_KUAP_BLOCKED);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline void restore_user_access(unsigned long flags)
|
||||
{
|
||||
set_kuap(flags);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
|
||||
{
|
||||
|
@ -55,6 +55,8 @@ static inline void allow_user_access(void __user *to, const void __user *from,
|
||||
unsigned long size, unsigned long dir) { }
|
||||
static inline void prevent_user_access(void __user *to, const void __user *from,
|
||||
unsigned long size, unsigned long dir) { }
|
||||
static inline unsigned long prevent_user_access_return(void) { return 0UL; }
|
||||
static inline void restore_user_access(unsigned long flags) { }
|
||||
static inline bool
|
||||
bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
|
||||
{
|
||||
|
@ -46,6 +46,20 @@ static inline void prevent_user_access(void __user *to, const void __user *from,
|
||||
mtspr(SPRN_MD_AP, MD_APG_KUAP);
|
||||
}
|
||||
|
||||
static inline unsigned long prevent_user_access_return(void)
|
||||
{
|
||||
unsigned long flags = mfspr(SPRN_MD_AP);
|
||||
|
||||
mtspr(SPRN_MD_AP, MD_APG_KUAP);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline void restore_user_access(unsigned long flags)
|
||||
{
|
||||
mtspr(SPRN_MD_AP, flags);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
|
||||
{
|
||||
|
@ -465,9 +465,8 @@ static __must_check inline bool user_access_begin(const void __user *ptr, size_t
|
||||
}
|
||||
#define user_access_begin user_access_begin
|
||||
#define user_access_end prevent_current_access_user
|
||||
|
||||
static inline unsigned long user_access_save(void) { return 0UL; }
|
||||
static inline void user_access_restore(unsigned long flags) { }
|
||||
#define user_access_save prevent_user_access_return
|
||||
#define user_access_restore restore_user_access
|
||||
|
||||
#define unsafe_op_wrap(op, err) do { if (unlikely(op)) goto err; } while (0)
|
||||
#define unsafe_get_user(x, p, e) unsafe_op_wrap(__get_user_allowed(x, p), e)
|
||||
|
Loading…
Reference in New Issue
Block a user