Skip to content

Commit 3d2403f

Browse files
mrutland-armctmarinas
authored andcommitted
arm64: uaccess: remove set_fs()
Now that the uaccess primitives dont take addr_limit into account, we have no need to manipulate this via set_fs() and get_fs(). Remove support for these, along with some infrastructure this renders redundant. We no longer need to flip UAO to access kernel memory under KERNEL_DS, and head.S unconditionally clears UAO for all kernel configurations via an ERET in init_kernel_el. Thus, we don't need to dynamically flip UAO, nor do we need to context-switch it. However, we still need to adjust PAN during SDEI entry. Masking of __user pointers no longer needs to use the dynamic value of addr_limit, and can use a constant derived from the maximum possible userspace task size. A new TASK_SIZE_MAX constant is introduced for this, which is also used by core code. In configurations supporting 52-bit VAs, this may include a region of unusable VA space above a 48-bit TTBR0 limit, but never includes any portion of TTBR1. Note that TASK_SIZE_MAX is an exclusive limit, while USER_DS and KERNEL_DS were inclusive limits, and is converted to a mask by subtracting one. As the SDEI entry code repurposes the otherwise unnecessary pt_regs::orig_addr_limit field to store the TTBR1 of the interrupted context, for now we rename that to pt_regs::sdei_ttbr1. In future we can consider factoring that out. Signed-off-by: Mark Rutland <[email protected]> Acked-by: James Morse <[email protected]> Cc: Christoph Hellwig <[email protected]> Cc: Will Deacon <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent 7b90dc4 commit 3d2403f

File tree

13 files changed

+13
-92
lines changed

13 files changed

+13
-92
lines changed

arch/arm64/Kconfig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@ config ARM64
195195
select PCI_SYSCALL if PCI
196196
select POWER_RESET
197197
select POWER_SUPPLY
198-
select SET_FS
199198
select SPARSE_IRQ
200199
select SWIOTLB
201200
select SYSCTL_EXCEPTION_TRACE

arch/arm64/include/asm/exec.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,5 @@
1010
#include <linux/sched.h>
1111

1212
extern unsigned long arch_align_stack(unsigned long sp);
13-
void uao_thread_switch(struct task_struct *next);
1413

1514
#endif /* __ASM_EXEC_H */

arch/arm64/include/asm/processor.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
#ifndef __ASM_PROCESSOR_H
99
#define __ASM_PROCESSOR_H
1010

11-
#define KERNEL_DS UL(-1)
12-
#define USER_DS ((UL(1) << VA_BITS) - 1)
13-
1411
/*
1512
* On arm64 systems, unaligned accesses by the CPU are cheap, and so there is
1613
* no point in shifting all network buffers by 2 bytes just to make some IP
@@ -48,6 +45,7 @@
4845

4946
#define DEFAULT_MAP_WINDOW_64 (UL(1) << VA_BITS_MIN)
5047
#define TASK_SIZE_64 (UL(1) << vabits_actual)
48+
#define TASK_SIZE_MAX (UL(1) << VA_BITS)
5149

5250
#ifdef CONFIG_COMPAT
5351
#if defined(CONFIG_ARM64_64K_PAGES) && defined(CONFIG_KUSER_HELPERS)

arch/arm64/include/asm/ptrace.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,7 @@ struct pt_regs {
193193
s32 syscallno;
194194
u32 unused2;
195195
#endif
196-
197-
u64 orig_addr_limit;
196+
u64 sdei_ttbr1;
198197
/* Only valid when ARM64_HAS_IRQ_PRIO_MASKING is enabled. */
199198
u64 pmr_save;
200199
u64 stackframe[2];

arch/arm64/include/asm/thread_info.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,11 @@ struct task_struct;
1818
#include <asm/stack_pointer.h>
1919
#include <asm/types.h>
2020

21-
typedef unsigned long mm_segment_t;
22-
2321
/*
2422
* low level task data that entry.S needs immediate access to.
2523
*/
2624
struct thread_info {
2725
unsigned long flags; /* low level flags */
28-
mm_segment_t addr_limit; /* address limit */
2926
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
3027
u64 ttbr0; /* saved TTBR0_EL1 */
3128
#endif
@@ -119,7 +116,6 @@ void arch_release_task_struct(struct task_struct *tsk);
119116
{ \
120117
.flags = _TIF_FOREIGN_FPSTATE, \
121118
.preempt_count = INIT_PREEMPT_COUNT, \
122-
.addr_limit = KERNEL_DS, \
123119
INIT_SCS \
124120
}
125121

arch/arm64/include/asm/uaccess.h

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,44 +26,16 @@
2626

2727
#define HAVE_GET_KERNEL_NOFAULT
2828

29-
#define get_fs() (current_thread_info()->addr_limit)
30-
31-
static inline void set_fs(mm_segment_t fs)
32-
{
33-
current_thread_info()->addr_limit = fs;
34-
35-
/*
36-
* Prevent a mispredicted conditional call to set_fs from forwarding
37-
* the wrong address limit to access_ok under speculation.
38-
*/
39-
spec_bar();
40-
41-
/* On user-mode return, check fs is correct */
42-
set_thread_flag(TIF_FSCHECK);
43-
44-
/*
45-
* Enable/disable UAO so that copy_to_user() etc can access
46-
* kernel memory with the unprivileged instructions.
47-
*/
48-
if (IS_ENABLED(CONFIG_ARM64_UAO) && fs == KERNEL_DS)
49-
asm(ALTERNATIVE("nop", SET_PSTATE_UAO(1), ARM64_HAS_UAO));
50-
else
51-
asm(ALTERNATIVE("nop", SET_PSTATE_UAO(0), ARM64_HAS_UAO,
52-
CONFIG_ARM64_UAO));
53-
}
54-
55-
#define uaccess_kernel() (get_fs() == KERNEL_DS)
56-
5729
/*
5830
* Test whether a block of memory is a valid user space address.
5931
* Returns 1 if the range is valid, 0 otherwise.
6032
*
6133
* This is equivalent to the following test:
62-
* (u65)addr + (u65)size <= (u65)current->addr_limit + 1
34+
* (u65)addr + (u65)size <= (u65)TASK_SIZE_MAX
6335
*/
6436
static inline unsigned long __range_ok(const void __user *addr, unsigned long size)
6537
{
66-
unsigned long ret, limit = current_thread_info()->addr_limit;
38+
unsigned long ret, limit = TASK_SIZE_MAX - 1;
6739

6840
/*
6941
* Asynchronous I/O running in a kernel thread does not have the
@@ -96,7 +68,6 @@ static inline unsigned long __range_ok(const void __user *addr, unsigned long si
9668
}
9769

9870
#define access_ok(addr, size) __range_ok(addr, size)
99-
#define user_addr_max get_fs
10071

10172
#define _ASM_EXTABLE(from, to) \
10273
" .pushsection __ex_table, \"a\"\n" \
@@ -226,9 +197,9 @@ static inline void uaccess_enable_not_uao(void)
226197
}
227198

228199
/*
229-
* Sanitise a uaccess pointer such that it becomes NULL if above the
230-
* current addr_limit. In case the pointer is tagged (has the top byte set),
231-
* untag the pointer before checking.
200+
* Sanitise a uaccess pointer such that it becomes NULL if above the maximum
201+
* user address. In case the pointer is tagged (has the top byte set), untag
202+
* the pointer before checking.
232203
*/
233204
#define uaccess_mask_ptr(ptr) (__typeof__(ptr))__uaccess_mask_ptr(ptr)
234205
static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
@@ -239,7 +210,7 @@ static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
239210
" bics xzr, %3, %2\n"
240211
" csel %0, %1, xzr, eq\n"
241212
: "=&r" (safe_ptr)
242-
: "r" (ptr), "r" (current_thread_info()->addr_limit),
213+
: "r" (ptr), "r" (TASK_SIZE_MAX - 1),
243214
"r" (untagged_addr(ptr))
244215
: "cc");
245216

arch/arm64/kernel/asm-offsets.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ int main(void)
3030
BLANK();
3131
DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags));
3232
DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count));
33-
DEFINE(TSK_TI_ADDR_LIMIT, offsetof(struct task_struct, thread_info.addr_limit));
3433
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
3534
DEFINE(TSK_TI_TTBR0, offsetof(struct task_struct, thread_info.ttbr0));
3635
#endif
@@ -70,7 +69,7 @@ int main(void)
7069
DEFINE(S_PSTATE, offsetof(struct pt_regs, pstate));
7170
DEFINE(S_PC, offsetof(struct pt_regs, pc));
7271
DEFINE(S_SYSCALLNO, offsetof(struct pt_regs, syscallno));
73-
DEFINE(S_ORIG_ADDR_LIMIT, offsetof(struct pt_regs, orig_addr_limit));
72+
DEFINE(S_SDEI_TTBR1, offsetof(struct pt_regs, sdei_ttbr1));
7473
DEFINE(S_PMR_SAVE, offsetof(struct pt_regs, pmr_save));
7574
DEFINE(S_STACKFRAME, offsetof(struct pt_regs, stackframe));
7675
DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));

arch/arm64/kernel/cpufeature.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,10 +1777,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
17771777
.sys_reg = SYS_ID_AA64MMFR2_EL1,
17781778
.field_pos = ID_AA64MMFR2_UAO_SHIFT,
17791779
.min_field_value = 1,
1780-
/*
1781-
* We rely on stop_machine() calling uao_thread_switch() to set
1782-
* UAO immediately after patching.
1783-
*/
17841780
},
17851781
#endif /* CONFIG_ARM64_UAO */
17861782
#ifdef CONFIG_ARM64_PAN

arch/arm64/kernel/entry.S

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -216,12 +216,6 @@ alternative_else_nop_endif
216216
.else
217217
add x21, sp, #S_FRAME_SIZE
218218
get_current_task tsk
219-
/* Save the task's original addr_limit and set USER_DS */
220-
ldr x20, [tsk, #TSK_TI_ADDR_LIMIT]
221-
str x20, [sp, #S_ORIG_ADDR_LIMIT]
222-
mov x20, #USER_DS
223-
str x20, [tsk, #TSK_TI_ADDR_LIMIT]
224-
/* No need to reset PSTATE.UAO, hardware's already set it to 0 for us */
225219
.endif /* \el == 0 */
226220
mrs x22, elr_el1
227221
mrs x23, spsr_el1
@@ -279,12 +273,6 @@ alternative_else_nop_endif
279273
.macro kernel_exit, el
280274
.if \el != 0
281275
disable_daif
282-
283-
/* Restore the task's original addr_limit. */
284-
ldr x20, [sp, #S_ORIG_ADDR_LIMIT]
285-
str x20, [tsk, #TSK_TI_ADDR_LIMIT]
286-
287-
/* No need to restore UAO, it will be restored from SPSR_EL1 */
288276
.endif
289277

290278
/* Restore pmr */
@@ -999,10 +987,9 @@ SYM_CODE_START(__sdei_asm_entry_trampoline)
999987
mov x4, xzr
1000988

1001989
/*
1002-
* Use reg->interrupted_regs.addr_limit to remember whether to unmap
1003-
* the kernel on exit.
990+
* Remember whether to unmap the kernel on exit.
1004991
*/
1005-
1: str x4, [x1, #(SDEI_EVENT_INTREGS + S_ORIG_ADDR_LIMIT)]
992+
1: str x4, [x1, #(SDEI_EVENT_INTREGS + S_SDEI_TTBR1)]
1006993

1007994
#ifdef CONFIG_RANDOMIZE_BASE
1008995
adr x4, tramp_vectors + PAGE_SIZE
@@ -1023,7 +1010,7 @@ NOKPROBE(__sdei_asm_entry_trampoline)
10231010
* x4: struct sdei_registered_event argument from registration time.
10241011
*/
10251012
SYM_CODE_START(__sdei_asm_exit_trampoline)
1026-
ldr x4, [x4, #(SDEI_EVENT_INTREGS + S_ORIG_ADDR_LIMIT)]
1013+
ldr x4, [x4, #(SDEI_EVENT_INTREGS + S_SDEI_TTBR1)]
10271014
cbnz x4, 1f
10281015

10291016
tramp_unmap_kernel tmp=x4

arch/arm64/kernel/process.c

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -460,17 +460,6 @@ static void tls_thread_switch(struct task_struct *next)
460460
write_sysreg(*task_user_tls(next), tpidr_el0);
461461
}
462462

463-
/* Restore the UAO state depending on next's addr_limit */
464-
void uao_thread_switch(struct task_struct *next)
465-
{
466-
if (IS_ENABLED(CONFIG_ARM64_UAO)) {
467-
if (task_thread_info(next)->addr_limit == KERNEL_DS)
468-
asm(ALTERNATIVE("nop", SET_PSTATE_UAO(1), ARM64_HAS_UAO));
469-
else
470-
asm(ALTERNATIVE("nop", SET_PSTATE_UAO(0), ARM64_HAS_UAO));
471-
}
472-
}
473-
474463
/*
475464
* Force SSBS state on context-switch, since it may be lost after migrating
476465
* from a CPU which treats the bit as RES0 in a heterogeneous system.
@@ -554,7 +543,6 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
554543
hw_breakpoint_thread_switch(next);
555544
contextidr_thread_switch(next);
556545
entry_task_switch(next);
557-
uao_thread_switch(next);
558546
ssbs_thread_switch(next);
559547
erratum_1418040_thread_switch(prev, next);
560548

arch/arm64/kernel/sdei.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,23 +242,18 @@ asmlinkage __kprobes notrace unsigned long
242242
__sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
243243
{
244244
unsigned long ret;
245-
mm_segment_t orig_addr_limit;
246245

247246
/*
248247
* We didn't take an exception to get here, so the HW hasn't
249-
* set/cleared bits in PSTATE that we may rely on. Initialize PAN, then
250-
* use force_uaccess_begin() to reset addr_limit.
248+
* set/cleared bits in PSTATE that we may rely on. Initialize PAN.
251249
*/
252250
__sdei_pstate_entry();
253-
orig_addr_limit = force_uaccess_begin();
254251

255252
nmi_enter();
256253

257254
ret = _sdei_handler(regs, arg);
258255

259256
nmi_exit();
260257

261-
force_uaccess_end(orig_addr_limit);
262-
263258
return ret;
264259
}

arch/arm64/kernel/suspend.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ void notrace __cpu_suspend_exit(void)
5858
* features that might not have been set correctly.
5959
*/
6060
__uaccess_enable_hw_pan();
61-
uao_thread_switch(current);
6261

6362
/*
6463
* Restore HW breakpoint registers to sane values

arch/arm64/mm/fault.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -479,11 +479,6 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
479479
}
480480

481481
if (is_ttbr0_addr(addr) && is_el1_permission_fault(addr, esr, regs)) {
482-
/* regs->orig_addr_limit may be 0 if we entered from EL0 */
483-
if (regs->orig_addr_limit == KERNEL_DS)
484-
die_kernel_fault("access to user memory with fs=KERNEL_DS",
485-
addr, esr, regs);
486-
487482
if (is_el1_instruction_abort(esr))
488483
die_kernel_fault("execution of user memory",
489484
addr, esr, regs);

0 commit comments

Comments
 (0)