Skip to content

Commit

Permalink
Merge branch 'set_fs-4' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…git/arnd/asm-generic into asm-generic

Christoph Hellwig and a few others spent a huge effort on removing
set_fs() from most of the important architectures, but about half the
other architectures were never completed even though most of them don't
actually use set_fs() at all.

I did a patch for microblaze at some point, which turned out to be fairly
generic, and now ported it to most other architectures, using new generic
implementations of access_ok() and __{get,put}_kernel_nocheck().

Three architectures (sparc64, ia64, and sh) needed some extra work,
which I also completed.

* 'set_fs-4' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic:
  uaccess: remove CONFIG_SET_FS
  ia64: remove CONFIG_SET_FS support
  sh: remove CONFIG_SET_FS support
  sparc64: remove CONFIG_SET_FS support
  lib/test_lockup: fix kernel pointer check for separate address spaces
  uaccess: generalize access_ok()
  uaccess: fix type mismatch warnings from access_ok()
  arm64: simplify access_ok()
  m68k: fix access_ok for coldfire
  MIPS: use simpler access_ok()
  MIPS: Handle address errors for accesses above CPU max virtual user address
  uaccess: add generic __{get,put}_kernel_nofault
  nios2: drop access_ok() check from __put_user()
  x86: use more conventional access_ok() definition
  x86: remove __range_not_ok()
  sparc64: add __{get,put}_kernel_nofault()
  nds32: fix access_ok() checks in get/put_user
  uaccess: fix nios2 and microblaze get_user_8()
  uaccess: fix integer overflow on access_ok()
  • Loading branch information
arndb committed Feb 25, 2022
2 parents be92e1d + 967747b commit dd865f0
Show file tree
Hide file tree
Showing 127 changed files with 403 additions and 1,292 deletions.
10 changes: 7 additions & 3 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ config KEXEC_ELF
config HAVE_IMA_KEXEC
bool

config SET_FS
bool

config HOTPLUG_SMT
bool

Expand Down Expand Up @@ -898,6 +895,13 @@ config HAVE_SOFTIRQ_ON_OWN_STACK
Architecture provides a function to run __do_softirq() on a
separate stack.

config ALTERNATE_USER_ADDRESS_SPACE
bool
help
Architectures set this when the CPU uses separate address
spaces for kernel and user space pointers. In this case, the
access_ok() check on a __user pointer is skipped.

config PGTABLE_LEVELS
int
default 2
Expand Down
1 change: 0 additions & 1 deletion arch/alpha/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ config ALPHA
select OLD_SIGSUSPEND
select CPU_NO_EFFICIENT_FFS if !ALPHA_EV67
select MMU_GATHER_NO_RANGE
select SET_FS
select SPARSEMEM_EXTREME if SPARSEMEM
select ZONE_DMA
help
Expand Down
4 changes: 0 additions & 4 deletions arch/alpha/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@
#define TASK_UNMAPPED_BASE \
((current->personality & ADDR_LIMIT_32BIT) ? 0x40000000 : TASK_SIZE / 2)

typedef struct {
unsigned long seg;
} mm_segment_t;

/* This is dead. Everything has been moved to thread_info. */
struct thread_struct { };
#define INIT_THREAD { }
Expand Down
2 changes: 0 additions & 2 deletions arch/alpha/include/asm/thread_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ struct thread_info {
unsigned int flags; /* low level flags */
unsigned int ieee_state; /* see fpu.h */

mm_segment_t addr_limit; /* thread address space */
unsigned cpu; /* current CPU */
int preempt_count; /* 0 => preemptable, <0 => BUG */
unsigned int status; /* thread-synchronous flags */
Expand All @@ -35,7 +34,6 @@ struct thread_info {
#define INIT_THREAD_INFO(tsk) \
{ \
.task = &tsk, \
.addr_limit = KERNEL_DS, \
.preempt_count = INIT_PREEMPT_COUNT, \
}

Expand Down
53 changes: 5 additions & 48 deletions arch/alpha/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,7 @@
#ifndef __ALPHA_UACCESS_H
#define __ALPHA_UACCESS_H

/*
* The fs value determines whether argument validity checking should be
* performed or not. If get_fs() == USER_DS, checking is performed, with
* get_fs() == KERNEL_DS, checking is bypassed.
*
* Or at least it did once upon a time. Nowadays it is a mask that
* defines which bits of the address space are off limits. This is a
* wee bit faster than the above.
*
* For historical reasons, these macros are grossly misnamed.
*/

#define KERNEL_DS ((mm_segment_t) { 0UL })
#define USER_DS ((mm_segment_t) { -0x40000000000UL })

#define get_fs() (current_thread_info()->addr_limit)
#define set_fs(x) (current_thread_info()->addr_limit = (x))

#define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg)

/*
* Is a address valid? This does a straightforward calculation rather
* than tests.
*
* Address valid if:
* - "addr" doesn't have any high-bits set
* - AND "size" doesn't have any high-bits set
* - AND "addr+size-(size != 0)" doesn't have any high-bits set
* - OR we are in kernel mode.
*/
#define __access_ok(addr, size) ({ \
unsigned long __ao_a = (addr), __ao_b = (size); \
unsigned long __ao_end = __ao_a + __ao_b - !!__ao_b; \
(get_fs().seg & (__ao_a | __ao_b | __ao_end)) == 0; })

#define access_ok(addr, size) \
({ \
__chk_user_ptr(addr); \
__access_ok(((unsigned long)(addr)), (size)); \
})

#include <asm-generic/access_ok.h>
/*
* These are the main single-value transfer routines. They automatically
* use the right size if we just have the right pointer type.
Expand Down Expand Up @@ -105,7 +65,7 @@ extern void __get_user_unknown(void);
long __gu_err = -EFAULT; \
unsigned long __gu_val = 0; \
const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
if (__access_ok((unsigned long)__gu_addr, size)) { \
if (__access_ok(__gu_addr, size)) { \
__gu_err = 0; \
switch (size) { \
case 1: __get_user_8(__gu_addr); break; \
Expand Down Expand Up @@ -200,7 +160,7 @@ extern void __put_user_unknown(void);
({ \
long __pu_err = -EFAULT; \
__typeof__(*(ptr)) __user *__pu_addr = (ptr); \
if (__access_ok((unsigned long)__pu_addr, size)) { \
if (__access_ok(__pu_addr, size)) { \
__pu_err = 0; \
switch (size) { \
case 1: __put_user_8(x, __pu_addr); break; \
Expand Down Expand Up @@ -316,17 +276,14 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long len)

extern long __clear_user(void __user *to, long len);

extern inline long
static inline long
clear_user(void __user *to, long len)
{
if (__access_ok((unsigned long)to, len))
if (__access_ok(to, len))
len = __clear_user(to, len);
return len;
}

#define user_addr_max() \
(uaccess_kernel() ? ~0UL : TASK_SIZE)

extern long strncpy_from_user(char *dest, const char __user *src, long count);
extern __must_check long strnlen_user(const char __user *str, long n);

Expand Down
1 change: 0 additions & 1 deletion arch/arc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ config ARC
select PCI_SYSCALL if PCI
select PERF_USE_VMALLOC if ARC_CACHE_VIPT_ALIASING
select HAVE_ARCH_JUMP_LABEL if ISA_ARCV2 && !CPU_ENDIAN_BE32
select SET_FS
select TRACE_IRQFLAGS_SUPPORT

config LOCKDEP_SUPPORT
Expand Down
20 changes: 0 additions & 20 deletions arch/arc/include/asm/segment.h

This file was deleted.

3 changes: 0 additions & 3 deletions arch/arc/include/asm/thread_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
#ifndef __ASSEMBLY__

#include <linux/thread_info.h>
#include <asm/segment.h>

/*
* low level task data that entry.S needs immediate access to
Expand All @@ -40,7 +39,6 @@ struct thread_info {
unsigned long flags; /* low level flags */
int preempt_count; /* 0 => preemptable, <0 => BUG */
struct task_struct *task; /* main task structure */
mm_segment_t addr_limit; /* thread address space */
__u32 cpu; /* current CPU */
unsigned long thr_ptr; /* TLS ptr */
};
Expand All @@ -56,7 +54,6 @@ struct thread_info {
.flags = 0, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
.addr_limit = KERNEL_DS, \
}

static inline __attribute_const__ struct thread_info *current_thread_info(void)
Expand Down
30 changes: 0 additions & 30 deletions arch/arc/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,6 @@

#include <linux/string.h> /* for generic string functions */


#define __kernel_ok (uaccess_kernel())

/*
* Algorithmically, for __user_ok() we want do:
* (start < TASK_SIZE) && (start+len < TASK_SIZE)
* where TASK_SIZE could either be retrieved from thread_info->addr_limit or
* emitted directly in code.
*
* This can however be rewritten as follows:
* (len <= TASK_SIZE) && (start+len < TASK_SIZE)
*
* Because it essentially checks if buffer end is within limit and @len is
* non-ngeative, which implies that buffer start will be within limit too.
*
* The reason for rewriting being, for majority of cases, @len is generally
* compile time constant, causing first sub-expression to be compile time
* subsumed.
*
* The second part would generate weird large LIMMs e.g. (0x6000_0000 - 0x10),
* so we check for TASK_SIZE using get_fs() since the addr_limit load from mem
* would already have been done at this call site for __kernel_ok()
*
*/
#define __user_ok(addr, sz) (((sz) <= TASK_SIZE) && \
((addr) <= (get_fs() - (sz))))
#define __access_ok(addr, sz) (unlikely(__kernel_ok) || \
likely(__user_ok((addr), (sz))))

/*********** Single byte/hword/word copies ******************/

#define __get_user_fn(sz, u, k) \
Expand Down Expand Up @@ -667,7 +638,6 @@ extern unsigned long arc_clear_user_noinline(void __user *to,
#define __clear_user(d, n) arc_clear_user_noinline(d, n)
#endif

#include <asm/segment.h>
#include <asm-generic/uaccess.h>

#endif
2 changes: 1 addition & 1 deletion arch/arc/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ SYSCALL_DEFINE0(arc_gettls)
return task_thread_info(current)->thr_ptr;
}

SYSCALL_DEFINE3(arc_usr_cmpxchg, int *, uaddr, int, expected, int, new)
SYSCALL_DEFINE3(arc_usr_cmpxchg, int __user *, uaddr, int, expected, int, new)
{
struct pt_regs *regs = current_pt_regs();
u32 uval;
Expand Down
22 changes: 1 addition & 21 deletions arch/arm/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,6 @@ extern int __put_user_bad(void);

#ifdef CONFIG_MMU

/*
* 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,
* so this will always return success in that case.
*/
#define __range_ok(addr, size) ({ \
unsigned long flag, roksum; \
__chk_user_ptr(addr); \
__asm__(".syntax unified\n" \
"adds %1, %2, %3; sbcscc %1, %1, %0; movcc %0, #0" \
: "=&r" (flag), "=&r" (roksum) \
: "r" (addr), "Ir" (size), "0" (TASK_SIZE) \
: "cc"); \
flag; })

/*
* This is a type: either unsigned long, if the argument fits into
* that type, or otherwise unsigned long long.
Expand Down Expand Up @@ -241,15 +226,12 @@ extern int __put_user_8(void *, unsigned long long);

#else /* CONFIG_MMU */

#define __addr_ok(addr) ((void)(addr), 1)
#define __range_ok(addr, size) ((void)(addr), 0)

#define get_user(x, p) __get_user(x, p)
#define __put_user_check __put_user_nocheck

#endif /* CONFIG_MMU */

#define access_ok(addr, size) (__range_ok(addr, size) == 0)
#include <asm-generic/access_ok.h>

#ifdef CONFIG_CPU_SPECTRE
/*
Expand Down Expand Up @@ -476,8 +458,6 @@ do { \
: "r" (x), "i" (-EFAULT) \
: "cc")

#define HAVE_GET_KERNEL_NOFAULT

#define __get_kernel_nofault(dst, src, type, err_label) \
do { \
const type *__pk_ptr = (src); \
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/kernel/swp_emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ static int swp_handler(struct pt_regs *regs, unsigned int instr)
destreg, EXTRACT_REG_NUM(instr, RT2_OFFSET), data);

/* Check access in reasonable access range for both SWP and SWPB */
if (!access_ok((address & ~3), 4)) {
if (!access_ok((void __user *)(address & ~3), 4)) {
pr_debug("SWP{B} emulation: access to %p not allowed!\n",
(void *)address);
res = -EFAULT;
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ do_cache_op(unsigned long start, unsigned long end, int flags)
if (end < start || flags)
return -EINVAL;

if (!access_ok(start, end - start))
if (!access_ok((void __user *)start, end - start))
return -EFAULT;

return __do_cache_op(start, end);
Expand Down
10 changes: 0 additions & 10 deletions arch/arm/lib/uaccess_with_memcpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,6 @@ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
unsigned long ua_flags;
int atomic;

if (uaccess_kernel()) {
memcpy((void *)to, from, n);
return 0;
}

/* the mmap semaphore is taken only if not in an atomic context */
atomic = faulthandler_disabled();

Expand Down Expand Up @@ -165,11 +160,6 @@ __clear_user_memset(void __user *addr, unsigned long n)
{
unsigned long ua_flags;

if (uaccess_kernel()) {
memset((void *)addr, 0, n);
return 0;
}

mmap_read_lock(current->mm);
while (n) {
pte_t *pte;
Expand Down
29 changes: 5 additions & 24 deletions arch/arm64/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <asm/memory.h>
#include <asm/extable.h>

#define HAVE_GET_KERNEL_NOFAULT
static inline int __access_ok(const void __user *ptr, unsigned long size);

/*
* Test whether a block of memory is a valid user space address.
Expand All @@ -35,10 +35,8 @@
* This is equivalent to the following test:
* (u65)addr + (u65)size <= (u65)TASK_SIZE_MAX
*/
static inline unsigned long __range_ok(const void __user *addr, unsigned long size)
static inline int access_ok(const void __user *addr, unsigned long size)
{
unsigned long ret, limit = TASK_SIZE_MAX - 1;

/*
* Asynchronous I/O running in a kernel thread does not have the
* TIF_TAGGED_ADDR flag of the process owning the mm, so always untag
Expand All @@ -48,28 +46,11 @@ static inline unsigned long __range_ok(const void __user *addr, unsigned long si
(current->flags & PF_KTHREAD || test_thread_flag(TIF_TAGGED_ADDR)))
addr = untagged_addr(addr);

__chk_user_ptr(addr);
asm volatile(
// A + B <= C + 1 for all A,B,C, in four easy steps:
// 1: X = A + B; X' = X % 2^64
" adds %0, %3, %2\n"
// 2: Set C = 0 if X > 2^64, to guarantee X' > C in step 4
" csel %1, xzr, %1, hi\n"
// 3: Set X' = ~0 if X >= 2^64. For X == 2^64, this decrements X'
// to compensate for the carry flag being set in step 4. For
// X > 2^64, X' merely has to remain nonzero, which it does.
" csinv %0, %0, xzr, cc\n"
// 4: For X < 2^64, this gives us X' - C - 1 <= 0, where the -1
// comes from the carry in being clear. Otherwise, we are
// testing X' - C == 0, subject to the previous adjustments.
" sbcs xzr, %0, %1\n"
" cset %0, ls\n"
: "=&r" (ret), "+r" (limit) : "Ir" (size), "0" (addr) : "cc");

return ret;
return likely(__access_ok(addr, size));
}
#define access_ok access_ok

#define access_ok(addr, size) __range_ok(addr, size)
#include <asm-generic/access_ok.h>

/*
* User access enabling/disabling.
Expand Down
Loading

0 comments on commit dd865f0

Please sign in to comment.