ARM: 9113/1: uaccess: remove set_fs() implementation
There are no remaining callers of set_fs(), so just remove it along with all associated code that operates on thread_info->addr_limit. There are still further optimizations that can be done: - In get_user(), the address check could be moved entirely into the out of line code, rather than passing a constant as an argument, - I assume the DACR handling can be simplified as we now only change it during user access when CONFIG_CPU_SW_DOMAIN_PAN is set, but not during set_fs(). Acked-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
This commit is contained in:
parent
2df4c9a741
commit
8ac6f5d7f8
@ -126,7 +126,6 @@ config ARM
|
|||||||
select PCI_SYSCALL if PCI
|
select PCI_SYSCALL if PCI
|
||||||
select PERF_USE_VMALLOC
|
select PERF_USE_VMALLOC
|
||||||
select RTC_LIB
|
select RTC_LIB
|
||||||
select SET_FS
|
|
||||||
select SYS_SUPPORTS_APM_EMULATION
|
select SYS_SUPPORTS_APM_EMULATION
|
||||||
# Above selects are sorted alphabetically; please add new ones
|
# Above selects are sorted alphabetically; please add new ones
|
||||||
# according to that. Thanks.
|
# according to that. Thanks.
|
||||||
|
@ -19,7 +19,6 @@ struct pt_regs {
|
|||||||
struct svc_pt_regs {
|
struct svc_pt_regs {
|
||||||
struct pt_regs regs;
|
struct pt_regs regs;
|
||||||
u32 dacr;
|
u32 dacr;
|
||||||
u32 addr_limit;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define to_svc_pt_regs(r) container_of(r, struct svc_pt_regs, regs)
|
#define to_svc_pt_regs(r) container_of(r, struct svc_pt_regs, regs)
|
||||||
|
@ -31,8 +31,6 @@ struct task_struct;
|
|||||||
|
|
||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
|
|
||||||
typedef unsigned long mm_segment_t;
|
|
||||||
|
|
||||||
struct cpu_context_save {
|
struct cpu_context_save {
|
||||||
__u32 r4;
|
__u32 r4;
|
||||||
__u32 r5;
|
__u32 r5;
|
||||||
@ -54,7 +52,6 @@ struct cpu_context_save {
|
|||||||
struct thread_info {
|
struct thread_info {
|
||||||
unsigned long flags; /* low level flags */
|
unsigned long flags; /* low level flags */
|
||||||
int preempt_count; /* 0 => preemptable, <0 => bug */
|
int preempt_count; /* 0 => preemptable, <0 => bug */
|
||||||
mm_segment_t addr_limit; /* address limit */
|
|
||||||
struct task_struct *task; /* main task structure */
|
struct task_struct *task; /* main task structure */
|
||||||
__u32 cpu; /* cpu */
|
__u32 cpu; /* cpu */
|
||||||
__u32 cpu_domain; /* cpu domain */
|
__u32 cpu_domain; /* cpu domain */
|
||||||
@ -80,7 +77,6 @@ struct thread_info {
|
|||||||
.task = &tsk, \
|
.task = &tsk, \
|
||||||
.flags = 0, \
|
.flags = 0, \
|
||||||
.preempt_count = INIT_PREEMPT_COUNT, \
|
.preempt_count = INIT_PREEMPT_COUNT, \
|
||||||
.addr_limit = KERNEL_DS, \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -84,12 +84,8 @@
|
|||||||
* if \disable is set.
|
* if \disable is set.
|
||||||
*/
|
*/
|
||||||
.macro uaccess_entry, tsk, tmp0, tmp1, tmp2, disable
|
.macro uaccess_entry, tsk, tmp0, tmp1, tmp2, disable
|
||||||
ldr \tmp1, [\tsk, #TI_ADDR_LIMIT]
|
|
||||||
ldr \tmp2, =TASK_SIZE
|
|
||||||
str \tmp2, [\tsk, #TI_ADDR_LIMIT]
|
|
||||||
DACR( mrc p15, 0, \tmp0, c3, c0, 0)
|
DACR( mrc p15, 0, \tmp0, c3, c0, 0)
|
||||||
DACR( str \tmp0, [sp, #SVC_DACR])
|
DACR( str \tmp0, [sp, #SVC_DACR])
|
||||||
str \tmp1, [sp, #SVC_ADDR_LIMIT]
|
|
||||||
.if \disable && IS_ENABLED(CONFIG_CPU_SW_DOMAIN_PAN)
|
.if \disable && IS_ENABLED(CONFIG_CPU_SW_DOMAIN_PAN)
|
||||||
/* kernel=client, user=no access */
|
/* kernel=client, user=no access */
|
||||||
mov \tmp2, #DACR_UACCESS_DISABLE
|
mov \tmp2, #DACR_UACCESS_DISABLE
|
||||||
@ -106,9 +102,7 @@
|
|||||||
|
|
||||||
/* Restore the user access state previously saved by uaccess_entry */
|
/* Restore the user access state previously saved by uaccess_entry */
|
||||||
.macro uaccess_exit, tsk, tmp0, tmp1
|
.macro uaccess_exit, tsk, tmp0, tmp1
|
||||||
ldr \tmp1, [sp, #SVC_ADDR_LIMIT]
|
|
||||||
DACR( ldr \tmp0, [sp, #SVC_DACR])
|
DACR( ldr \tmp0, [sp, #SVC_DACR])
|
||||||
str \tmp1, [\tsk, #TI_ADDR_LIMIT]
|
|
||||||
DACR( mcr p15, 0, \tmp0, c3, c0, 0)
|
DACR( mcr p15, 0, \tmp0, c3, c0, 0)
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
@ -52,32 +52,8 @@ static __always_inline void uaccess_restore(unsigned int flags)
|
|||||||
extern int __get_user_bad(void);
|
extern int __get_user_bad(void);
|
||||||
extern int __put_user_bad(void);
|
extern int __put_user_bad(void);
|
||||||
|
|
||||||
/*
|
|
||||||
* Note that this is actually 0x1,0000,0000
|
|
||||||
*/
|
|
||||||
#define KERNEL_DS 0x00000000
|
|
||||||
|
|
||||||
#ifdef CONFIG_MMU
|
#ifdef CONFIG_MMU
|
||||||
|
|
||||||
#define USER_DS TASK_SIZE
|
|
||||||
#define get_fs() (current_thread_info()->addr_limit)
|
|
||||||
|
|
||||||
static inline void set_fs(mm_segment_t fs)
|
|
||||||
{
|
|
||||||
current_thread_info()->addr_limit = fs;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prevent a mispredicted conditional call to set_fs from forwarding
|
|
||||||
* the wrong address limit to access_ok under speculation.
|
|
||||||
*/
|
|
||||||
dsb(nsh);
|
|
||||||
isb();
|
|
||||||
|
|
||||||
modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define uaccess_kernel() (get_fs() == KERNEL_DS)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We use 33-bit arithmetic here. Success returns zero, failure returns
|
* We use 33-bit arithmetic here. Success returns zero, failure returns
|
||||||
* addr_limit. We take advantage that addr_limit will be zero for KERNEL_DS,
|
* addr_limit. We take advantage that addr_limit will be zero for KERNEL_DS,
|
||||||
@ -89,7 +65,7 @@ static inline void set_fs(mm_segment_t fs)
|
|||||||
__asm__(".syntax unified\n" \
|
__asm__(".syntax unified\n" \
|
||||||
"adds %1, %2, %3; sbcscc %1, %1, %0; movcc %0, #0" \
|
"adds %1, %2, %3; sbcscc %1, %1, %0; movcc %0, #0" \
|
||||||
: "=&r" (flag), "=&r" (roksum) \
|
: "=&r" (flag), "=&r" (roksum) \
|
||||||
: "r" (addr), "Ir" (size), "0" (current_thread_info()->addr_limit) \
|
: "r" (addr), "Ir" (size), "0" (TASK_SIZE) \
|
||||||
: "cc"); \
|
: "cc"); \
|
||||||
flag; })
|
flag; })
|
||||||
|
|
||||||
@ -120,7 +96,7 @@ static inline void __user *__uaccess_mask_range_ptr(const void __user *ptr,
|
|||||||
" subshs %1, %1, %2\n"
|
" subshs %1, %1, %2\n"
|
||||||
" movlo %0, #0\n"
|
" movlo %0, #0\n"
|
||||||
: "+r" (safe_ptr), "=&r" (tmp)
|
: "+r" (safe_ptr), "=&r" (tmp)
|
||||||
: "r" (size), "r" (current_thread_info()->addr_limit)
|
: "r" (size), "r" (TASK_SIZE)
|
||||||
: "cc");
|
: "cc");
|
||||||
|
|
||||||
csdb();
|
csdb();
|
||||||
@ -194,7 +170,7 @@ extern int __get_user_64t_4(void *);
|
|||||||
|
|
||||||
#define __get_user_check(x, p) \
|
#define __get_user_check(x, p) \
|
||||||
({ \
|
({ \
|
||||||
unsigned long __limit = current_thread_info()->addr_limit - 1; \
|
unsigned long __limit = TASK_SIZE - 1; \
|
||||||
register typeof(*(p)) __user *__p asm("r0") = (p); \
|
register typeof(*(p)) __user *__p asm("r0") = (p); \
|
||||||
register __inttype(x) __r2 asm("r2"); \
|
register __inttype(x) __r2 asm("r2"); \
|
||||||
register unsigned long __l asm("r1") = __limit; \
|
register unsigned long __l asm("r1") = __limit; \
|
||||||
@ -245,7 +221,7 @@ extern int __put_user_8(void *, unsigned long long);
|
|||||||
|
|
||||||
#define __put_user_check(__pu_val, __ptr, __err, __s) \
|
#define __put_user_check(__pu_val, __ptr, __err, __s) \
|
||||||
({ \
|
({ \
|
||||||
unsigned long __limit = current_thread_info()->addr_limit - 1; \
|
unsigned long __limit = TASK_SIZE - 1; \
|
||||||
register typeof(__pu_val) __r2 asm("r2") = __pu_val; \
|
register typeof(__pu_val) __r2 asm("r2") = __pu_val; \
|
||||||
register const void __user *__p asm("r0") = __ptr; \
|
register const void __user *__p asm("r0") = __ptr; \
|
||||||
register unsigned long __l asm("r1") = __limit; \
|
register unsigned long __l asm("r1") = __limit; \
|
||||||
@ -262,19 +238,8 @@ extern int __put_user_8(void *, unsigned long long);
|
|||||||
|
|
||||||
#else /* CONFIG_MMU */
|
#else /* CONFIG_MMU */
|
||||||
|
|
||||||
/*
|
|
||||||
* uClinux has only one addr space, so has simplified address limits.
|
|
||||||
*/
|
|
||||||
#define USER_DS KERNEL_DS
|
|
||||||
|
|
||||||
#define uaccess_kernel() (true)
|
|
||||||
#define __addr_ok(addr) ((void)(addr), 1)
|
#define __addr_ok(addr) ((void)(addr), 1)
|
||||||
#define __range_ok(addr, size) ((void)(addr), 0)
|
#define __range_ok(addr, size) ((void)(addr), 0)
|
||||||
#define get_fs() (KERNEL_DS)
|
|
||||||
|
|
||||||
static inline void set_fs(mm_segment_t fs)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#define get_user(x, p) __get_user(x, p)
|
#define get_user(x, p) __get_user(x, p)
|
||||||
#define __put_user_check __put_user_nocheck
|
#define __put_user_check __put_user_nocheck
|
||||||
@ -283,9 +248,6 @@ static inline void set_fs(mm_segment_t fs)
|
|||||||
|
|
||||||
#define access_ok(addr, size) (__range_ok(addr, size) == 0)
|
#define access_ok(addr, size) (__range_ok(addr, size) == 0)
|
||||||
|
|
||||||
#define user_addr_max() \
|
|
||||||
(uaccess_kernel() ? ~0UL : get_fs())
|
|
||||||
|
|
||||||
#ifdef CONFIG_CPU_SPECTRE
|
#ifdef CONFIG_CPU_SPECTRE
|
||||||
/*
|
/*
|
||||||
* When mitigating Spectre variant 1, it is not worth fixing the non-
|
* When mitigating Spectre variant 1, it is not worth fixing the non-
|
||||||
|
@ -43,7 +43,6 @@ int main(void)
|
|||||||
BLANK();
|
BLANK();
|
||||||
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
|
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
|
||||||
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
|
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
|
||||||
DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
|
|
||||||
DEFINE(TI_TASK, offsetof(struct thread_info, task));
|
DEFINE(TI_TASK, offsetof(struct thread_info, task));
|
||||||
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
|
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
|
||||||
DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info, cpu_domain));
|
DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info, cpu_domain));
|
||||||
@ -92,7 +91,6 @@ int main(void)
|
|||||||
DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0));
|
DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0));
|
||||||
DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs));
|
DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs));
|
||||||
DEFINE(SVC_DACR, offsetof(struct svc_pt_regs, dacr));
|
DEFINE(SVC_DACR, offsetof(struct svc_pt_regs, dacr));
|
||||||
DEFINE(SVC_ADDR_LIMIT, offsetof(struct svc_pt_regs, addr_limit));
|
|
||||||
DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs));
|
DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs));
|
||||||
BLANK();
|
BLANK();
|
||||||
DEFINE(SIGFRAME_RC3_OFFSET, offsetof(struct sigframe, retcode[3]));
|
DEFINE(SIGFRAME_RC3_OFFSET, offsetof(struct sigframe, retcode[3]));
|
||||||
|
@ -49,10 +49,6 @@ __ret_fast_syscall:
|
|||||||
UNWIND(.fnstart )
|
UNWIND(.fnstart )
|
||||||
UNWIND(.cantunwind )
|
UNWIND(.cantunwind )
|
||||||
disable_irq_notrace @ disable interrupts
|
disable_irq_notrace @ disable interrupts
|
||||||
ldr r2, [tsk, #TI_ADDR_LIMIT]
|
|
||||||
ldr r1, =TASK_SIZE
|
|
||||||
cmp r2, r1
|
|
||||||
blne addr_limit_check_failed
|
|
||||||
ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing
|
ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing
|
||||||
movs r1, r1, lsl #16
|
movs r1, r1, lsl #16
|
||||||
bne fast_work_pending
|
bne fast_work_pending
|
||||||
@ -87,10 +83,6 @@ __ret_fast_syscall:
|
|||||||
bl do_rseq_syscall
|
bl do_rseq_syscall
|
||||||
#endif
|
#endif
|
||||||
disable_irq_notrace @ disable interrupts
|
disable_irq_notrace @ disable interrupts
|
||||||
ldr r2, [tsk, #TI_ADDR_LIMIT]
|
|
||||||
ldr r1, =TASK_SIZE
|
|
||||||
cmp r2, r1
|
|
||||||
blne addr_limit_check_failed
|
|
||||||
ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing
|
ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing
|
||||||
movs r1, r1, lsl #16
|
movs r1, r1, lsl #16
|
||||||
beq no_work_pending
|
beq no_work_pending
|
||||||
@ -129,10 +121,6 @@ ret_slow_syscall:
|
|||||||
#endif
|
#endif
|
||||||
disable_irq_notrace @ disable interrupts
|
disable_irq_notrace @ disable interrupts
|
||||||
ENTRY(ret_to_user_from_irq)
|
ENTRY(ret_to_user_from_irq)
|
||||||
ldr r2, [tsk, #TI_ADDR_LIMIT]
|
|
||||||
ldr r1, =TASK_SIZE
|
|
||||||
cmp r2, r1
|
|
||||||
blne addr_limit_check_failed
|
|
||||||
ldr r1, [tsk, #TI_FLAGS]
|
ldr r1, [tsk, #TI_FLAGS]
|
||||||
movs r1, r1, lsl #16
|
movs r1, r1, lsl #16
|
||||||
bne slow_work_pending
|
bne slow_work_pending
|
||||||
|
@ -108,7 +108,7 @@ void __show_regs(struct pt_regs *regs)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
#ifndef CONFIG_CPU_V7M
|
#ifndef CONFIG_CPU_V7M
|
||||||
unsigned int domain, fs;
|
unsigned int domain;
|
||||||
#ifdef CONFIG_CPU_SW_DOMAIN_PAN
|
#ifdef CONFIG_CPU_SW_DOMAIN_PAN
|
||||||
/*
|
/*
|
||||||
* Get the domain register for the parent context. In user
|
* Get the domain register for the parent context. In user
|
||||||
@ -117,14 +117,11 @@ void __show_regs(struct pt_regs *regs)
|
|||||||
*/
|
*/
|
||||||
if (user_mode(regs)) {
|
if (user_mode(regs)) {
|
||||||
domain = DACR_UACCESS_ENABLE;
|
domain = DACR_UACCESS_ENABLE;
|
||||||
fs = get_fs();
|
|
||||||
} else {
|
} else {
|
||||||
domain = to_svc_pt_regs(regs)->dacr;
|
domain = to_svc_pt_regs(regs)->dacr;
|
||||||
fs = to_svc_pt_regs(regs)->addr_limit;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
domain = get_domain();
|
domain = get_domain();
|
||||||
fs = get_fs();
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -160,8 +157,6 @@ void __show_regs(struct pt_regs *regs)
|
|||||||
if ((domain & domain_mask(DOMAIN_USER)) ==
|
if ((domain & domain_mask(DOMAIN_USER)) ==
|
||||||
domain_val(DOMAIN_USER, DOMAIN_NOACCESS))
|
domain_val(DOMAIN_USER, DOMAIN_NOACCESS))
|
||||||
segment = "none";
|
segment = "none";
|
||||||
else if (fs == KERNEL_DS)
|
|
||||||
segment = "kernel";
|
|
||||||
else
|
else
|
||||||
segment = "user";
|
segment = "user";
|
||||||
|
|
||||||
|
@ -711,14 +711,6 @@ struct page *get_signal_page(void)
|
|||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Defer to generic check */
|
|
||||||
asmlinkage void addr_limit_check_failed(void)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_MMU
|
|
||||||
addr_limit_user_check();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_RSEQ
|
#ifdef CONFIG_DEBUG_RSEQ
|
||||||
asmlinkage void do_rseq_syscall(struct pt_regs *regs)
|
asmlinkage void do_rseq_syscall(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
@ -109,8 +109,7 @@
|
|||||||
|
|
||||||
ENTRY(arm_copy_from_user)
|
ENTRY(arm_copy_from_user)
|
||||||
#ifdef CONFIG_CPU_SPECTRE
|
#ifdef CONFIG_CPU_SPECTRE
|
||||||
get_thread_info r3
|
ldr r3, =TASK_SIZE
|
||||||
ldr r3, [r3, #TI_ADDR_LIMIT]
|
|
||||||
uaccess_mask_range_ptr r1, r2, r3, ip
|
uaccess_mask_range_ptr r1, r2, r3, ip
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -109,8 +109,7 @@
|
|||||||
ENTRY(__copy_to_user_std)
|
ENTRY(__copy_to_user_std)
|
||||||
WEAK(arm_copy_to_user)
|
WEAK(arm_copy_to_user)
|
||||||
#ifdef CONFIG_CPU_SPECTRE
|
#ifdef CONFIG_CPU_SPECTRE
|
||||||
get_thread_info r3
|
ldr r3, =TASK_SIZE
|
||||||
ldr r3, [r3, #TI_ADDR_LIMIT]
|
|
||||||
uaccess_mask_range_ptr r0, r2, r3, ip
|
uaccess_mask_range_ptr r0, r2, r3, ip
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user