2022-02-16 13:55:24

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v2 00/18] clean up asm/uaccess.h, kill set_fs for good

From: Arnd Bergmann <[email protected]>

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.

The final series contains extra cleanup changes that touch all
architectures. Please review and test these, so we can merge them
for v5.18.

The series is available at
https://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git/log/?h=set_fs-2
for testing.

Changes in v2:
- add fixes for more nios2 and microblaze bugs found in the process
- do final cleanup in a single patch
- fix sparc64 regression
- introduce CONFIG_ALTERNATE_USER_ADDRESS_SPACE
- fix access_ok() in lib/test_lockup.c

Arnd Bergmann (18):
uaccess: fix integer overflow on access_ok()
uaccess: fix nios2 and microblaze get_user_8()
nds32: fix access_ok() checks in get/put_user
sparc64: add __{get,put}_kernel_nocheck()
x86: remove __range_not_ok()
x86: use more conventional access_ok() definition
nios2: drop access_ok() check from __put_user()
uaccess: add generic __{get,put}_kernel_nofault
mips: use simpler access_ok()
m68k: fix access_ok for coldfire
arm64: simplify access_ok()
uaccess: fix type mismatch warnings from access_ok()
uaccess: generalize access_ok()
lib/test_lockup: fix kernel pointer check for separate address spaces
sparc64: remove CONFIG_SET_FS support
sh: remove CONFIG_SET_FS support
ia64: remove CONFIG_SET_FS support
uaccess: drop maining CONFIG_SET_FS users

arch/Kconfig | 10 +-
arch/alpha/Kconfig | 1 -
arch/alpha/include/asm/processor.h | 4 -
arch/alpha/include/asm/thread_info.h | 2 -
arch/alpha/include/asm/uaccess.h | 53 +---------
arch/arc/Kconfig | 1 -
arch/arc/include/asm/segment.h | 20 ----
arch/arc/include/asm/thread_info.h | 3 -
arch/arc/include/asm/uaccess.h | 30 ------
arch/arc/kernel/process.c | 2 +-
arch/arm/include/asm/uaccess.h | 22 +---
arch/arm/kernel/swp_emulate.c | 2 +-
arch/arm/kernel/traps.c | 2 +-
arch/arm/lib/uaccess_with_memcpy.c | 10 --
arch/arm64/include/asm/uaccess.h | 29 +-----
arch/csky/Kconfig | 1 -
arch/csky/include/asm/processor.h | 2 -
arch/csky/include/asm/segment.h | 10 --
arch/csky/include/asm/thread_info.h | 2 -
arch/csky/include/asm/uaccess.h | 12 ---
arch/csky/kernel/asm-offsets.c | 1 -
arch/csky/kernel/signal.c | 2 +-
arch/h8300/Kconfig | 1 -
arch/h8300/include/asm/processor.h | 1 -
arch/h8300/include/asm/segment.h | 40 --------
arch/h8300/include/asm/thread_info.h | 3 -
arch/h8300/kernel/entry.S | 1 -
arch/h8300/kernel/head_ram.S | 1 -
arch/h8300/mm/init.c | 6 --
arch/h8300/mm/memory.c | 1 -
arch/hexagon/Kconfig | 1 -
arch/hexagon/include/asm/thread_info.h | 6 --
arch/hexagon/include/asm/uaccess.h | 25 -----
arch/hexagon/kernel/process.c | 1 -
arch/ia64/Kconfig | 1 -
arch/ia64/include/asm/processor.h | 4 -
arch/ia64/include/asm/thread_info.h | 2 -
arch/ia64/include/asm/uaccess.h | 26 ++---
arch/ia64/kernel/unaligned.c | 60 +++++++----
arch/m68k/Kconfig.cpu | 1 +
arch/m68k/include/asm/uaccess.h | 14 +--
arch/microblaze/Kconfig | 1 -
arch/microblaze/include/asm/thread_info.h | 6 --
arch/microblaze/include/asm/uaccess.h | 61 ++---------
arch/microblaze/kernel/asm-offsets.c | 1 -
arch/microblaze/kernel/process.c | 1 -
arch/mips/include/asm/uaccess.h | 49 +--------
arch/mips/sibyte/common/sb_tbprof.c | 6 +-
arch/nds32/Kconfig | 1 -
arch/nds32/include/asm/thread_info.h | 4 -
arch/nds32/include/asm/uaccess.h | 40 ++++----
arch/nds32/kernel/process.c | 5 +-
arch/nds32/mm/alignment.c | 3 -
arch/nios2/Kconfig | 1 -
arch/nios2/include/asm/thread_info.h | 9 --
arch/nios2/include/asm/uaccess.h | 105 +++++++++----------
arch/nios2/kernel/signal.c | 20 ++--
arch/openrisc/Kconfig | 1 -
arch/openrisc/include/asm/thread_info.h | 7 --
arch/openrisc/include/asm/uaccess.h | 42 +-------
arch/parisc/Kconfig | 1 +
arch/parisc/include/asm/futex.h | 6 --
arch/parisc/include/asm/uaccess.h | 13 +--
arch/parisc/lib/memcpy.c | 2 +-
arch/powerpc/include/asm/uaccess.h | 13 +--
arch/powerpc/lib/sstep.c | 4 +-
arch/riscv/include/asm/uaccess.h | 33 +-----
arch/riscv/kernel/perf_callchain.c | 2 +-
arch/s390/Kconfig | 1 +
arch/s390/include/asm/uaccess.h | 16 +--
arch/sh/Kconfig | 1 -
arch/sh/include/asm/processor.h | 1 -
arch/sh/include/asm/segment.h | 33 ------
arch/sh/include/asm/thread_info.h | 2 -
arch/sh/include/asm/uaccess.h | 24 +----
arch/sh/kernel/io_trapped.c | 9 +-
arch/sh/kernel/process_32.c | 2 -
arch/sh/kernel/traps_32.c | 30 ++++--
arch/sparc/Kconfig | 3 +-
arch/sparc/include/asm/processor_32.h | 6 --
arch/sparc/include/asm/processor_64.h | 4 -
arch/sparc/include/asm/switch_to_64.h | 4 +-
arch/sparc/include/asm/thread_info_64.h | 4 +-
arch/sparc/include/asm/uaccess.h | 3 -
arch/sparc/include/asm/uaccess_32.h | 31 +-----
arch/sparc/include/asm/uaccess_64.h | 113 +++++++++++++-------
arch/sparc/kernel/process_32.c | 2 -
arch/sparc/kernel/process_64.c | 12 ---
arch/sparc/kernel/signal_32.c | 2 +-
arch/sparc/kernel/traps_64.c | 2 -
arch/sparc/lib/NGmemcpy.S | 3 +-
arch/sparc/mm/init_64.c | 7 +-
arch/um/include/asm/uaccess.h | 7 +-
arch/x86/events/core.c | 2 +-
arch/x86/include/asm/uaccess.h | 35 +------
arch/x86/kernel/dumpstack.c | 2 +-
arch/x86/kernel/stacktrace.c | 2 +-
arch/x86/lib/usercopy.c | 2 +-
arch/xtensa/Kconfig | 1 -
arch/xtensa/include/asm/asm-uaccess.h | 71 -------------
arch/xtensa/include/asm/processor.h | 7 --
arch/xtensa/include/asm/thread_info.h | 3 -
arch/xtensa/include/asm/uaccess.h | 26 +----
arch/xtensa/kernel/asm-offsets.c | 3 -
drivers/hid/uhid.c | 2 +-
drivers/scsi/sg.c | 5 -
fs/exec.c | 6 --
include/asm-generic/access_ok.h | 51 ++++++++++
include/asm-generic/uaccess.h | 46 +--------
include/linux/syscalls.h | 4 -
include/linux/uaccess.h | 59 ++++-------
include/rdma/ib.h | 2 +-
kernel/events/callchain.c | 4 -
kernel/events/core.c | 3 -
kernel/exit.c | 14 ---
kernel/kthread.c | 5 -
kernel/stacktrace.c | 3 -
kernel/trace/bpf_trace.c | 4 -
lib/test_lockup.c | 11 +-
mm/maccess.c | 119 ----------------------
mm/memory.c | 8 --
net/bpfilter/bpfilter_kern.c | 2 +-
122 files changed, 387 insertions(+), 1290 deletions(-)
delete mode 100644 arch/arc/include/asm/segment.h
delete mode 100644 arch/csky/include/asm/segment.h
delete mode 100644 arch/h8300/include/asm/segment.h
delete mode 100644 arch/sh/include/asm/segment.h
create mode 100644 include/asm-generic/access_ok.h

--
2.29.2

Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]


2022-02-16 13:58:51

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v2 09/18] mips: use simpler access_ok()

From: Arnd Bergmann <[email protected]>

Before unifying the mips version of __access_ok() with the generic
code, this converts it to the same algorithm. This is a change in
behavior on mips64, as now address in the user segment, the lower
2^62 bytes, is taken to be valid, relying on a page fault for
addresses that are within that segment but not valid on that CPU.

The new version should be the most effecient way to do this, but
it gets rid of the special handling for size=0 that most other
architectures ignore as well.

Signed-off-by: Arnd Bergmann <[email protected]>
---
arch/mips/include/asm/uaccess.h | 22 ++++------------------
1 file changed, 4 insertions(+), 18 deletions(-)

diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
index db9a8e002b62..d7c89dc3426c 100644
--- a/arch/mips/include/asm/uaccess.h
+++ b/arch/mips/include/asm/uaccess.h
@@ -19,6 +19,7 @@
#ifdef CONFIG_32BIT

#define __UA_LIMIT 0x80000000UL
+#define TASK_SIZE_MAX __UA_LIMIT

#define __UA_ADDR ".word"
#define __UA_LA "la"
@@ -33,6 +34,7 @@
extern u64 __ua_limit;

#define __UA_LIMIT __ua_limit
+#define TASK_SIZE_MAX XKSSEG

#define __UA_ADDR ".dword"
#define __UA_LA "dla"
@@ -42,22 +44,6 @@ extern u64 __ua_limit;

#endif /* CONFIG_64BIT */

-/*
- * 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" doesn't have any high-bits set
- * - OR we are in kernel mode.
- *
- * __ua_size() is a trick to avoid runtime checking of positive constant
- * sizes; for those we already know at compile time that the size is ok.
- */
-#define __ua_size(size) \
- ((__builtin_constant_p(size) && (signed long) (size) > 0) ? 0 : (size))
-
/*
* access_ok: - Checks if a user space pointer is valid
* @addr: User space pointer to start of block to check
@@ -79,9 +65,9 @@ extern u64 __ua_limit;
static inline int __access_ok(const void __user *p, unsigned long size)
{
unsigned long addr = (unsigned long)p;
- unsigned long end = addr + size - !!size;
+ unsigned long limit = TASK_SIZE_MAX;

- return (__UA_LIMIT & (addr | end | __ua_size(size))) == 0;
+ return (size <= limit) && (addr <= (limit - size));
}

#define access_ok(addr, size) \
--
2.29.2

2022-02-16 14:03:55

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v2 10/18] m68k: fix access_ok for coldfire

From: Arnd Bergmann <[email protected]>

While most m68k platforms use separate address spaces for user
and kernel space, at least coldfire does not, and the other
ones have a TASK_SIZE that is less than the entire 4GB address
range.

Using the default implementation of __access_ok() stops coldfire
user space from trivially accessing kernel memory.

Signed-off-by: Arnd Bergmann <[email protected]>
---
arch/m68k/include/asm/uaccess.h | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/m68k/include/asm/uaccess.h b/arch/m68k/include/asm/uaccess.h
index 79617c0b2f91..8eb625e75452 100644
--- a/arch/m68k/include/asm/uaccess.h
+++ b/arch/m68k/include/asm/uaccess.h
@@ -12,14 +12,21 @@
#include <asm/extable.h>

/* We let the MMU do all checking */
-static inline int access_ok(const void __user *addr,
+static inline int access_ok(const void __user *ptr,
unsigned long size)
{
+ unsigned long limit = TASK_SIZE;
+ unsigned long addr = (unsigned long)ptr;
+
/*
* XXX: for !CONFIG_CPU_HAS_ADDRESS_SPACES this really needs to check
* for TASK_SIZE!
+ * Removing this helper is probably sufficient.
*/
- return 1;
+ if (IS_ENABLED(CONFIG_CPU_HAS_ADDRESS_SPACES))
+ return 1;
+
+ return (size <= limit) && (addr <= (limit - size));
}

/*
--
2.29.2

2022-02-16 14:04:23

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v2 14/18] lib/test_lockup: fix kernel pointer check for separate address spaces

From: Arnd Bergmann <[email protected]>

test_kernel_ptr() uses access_ok() to figure out if a given address
points to user space instead of kernel space. However on architectures
that set CONFIG_ALTERNATE_USER_ADDRESS_SPACE, a pointer can be valid
for both, and the check always fails because access_ok() returns true.

Make the check for user space pointers conditional on the type of
address space layout.

Signed-off-by: Arnd Bergmann <[email protected]>
---
lib/test_lockup.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/lib/test_lockup.c b/lib/test_lockup.c
index 6a0f329a794a..c3fd87d6c2dd 100644
--- a/lib/test_lockup.c
+++ b/lib/test_lockup.c
@@ -417,9 +417,14 @@ static bool test_kernel_ptr(unsigned long addr, int size)
return false;

/* should be at least readable kernel address */
- if (access_ok((void __user *)ptr, 1) ||
- access_ok((void __user *)ptr + size - 1, 1) ||
- get_kernel_nofault(buf, ptr) ||
+ if (!IS_ENABLED(CONFIG_ALTERNATE_USER_ADDRESS_SPACE) &&
+ (access_ok((void __user *)ptr, 1) ||
+ access_ok((void __user *)ptr + size - 1, 1))) {
+ pr_err("user space ptr invalid in kernel: %#lx\n", addr);
+ return true;
+ }
+
+ if (get_kernel_nofault(buf, ptr) ||
get_kernel_nofault(buf, ptr + size - 1)) {
pr_err("invalid kernel ptr: %#lx\n", addr);
return true;
--
2.29.2

2022-02-16 14:10:46

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v2 18/18] uaccess: drop maining CONFIG_SET_FS users

From: Arnd Bergmann <[email protected]>

There are no remaining callers of set_fs(), so CONFIG_SET_FS
can be removed globally, along with the thread_info field and
any references to it.

This turns access_ok() into a cheaper check against TASK_SIZE_MAX.

With CONFIG_SET_FS gone, so drop all remaining references to
set_fs()/get_fs(), mm_segment_t and uaccess_kernel().

Signed-off-by: Arnd Bergmann <[email protected]>
---
arch/Kconfig | 3 -
arch/alpha/Kconfig | 1 -
arch/alpha/include/asm/processor.h | 4 --
arch/alpha/include/asm/thread_info.h | 2 -
arch/alpha/include/asm/uaccess.h | 19 ------
arch/arc/Kconfig | 1 -
arch/arc/include/asm/segment.h | 20 -------
arch/arc/include/asm/thread_info.h | 3 -
arch/arc/include/asm/uaccess.h | 1 -
arch/arm/lib/uaccess_with_memcpy.c | 10 ----
arch/csky/Kconfig | 1 -
arch/csky/include/asm/processor.h | 2 -
arch/csky/include/asm/segment.h | 10 ----
arch/csky/include/asm/thread_info.h | 2 -
arch/csky/include/asm/uaccess.h | 3 -
arch/csky/kernel/asm-offsets.c | 1 -
arch/h8300/Kconfig | 1 -
arch/h8300/include/asm/processor.h | 1 -
arch/h8300/include/asm/segment.h | 40 -------------
arch/h8300/include/asm/thread_info.h | 3 -
arch/h8300/kernel/entry.S | 1 -
arch/h8300/kernel/head_ram.S | 1 -
arch/h8300/mm/init.c | 6 --
arch/h8300/mm/memory.c | 1 -
arch/hexagon/Kconfig | 1 -
arch/hexagon/include/asm/thread_info.h | 6 --
arch/hexagon/kernel/process.c | 1 -
arch/microblaze/Kconfig | 1 -
arch/microblaze/include/asm/thread_info.h | 6 --
arch/microblaze/include/asm/uaccess.h | 24 --------
arch/microblaze/kernel/asm-offsets.c | 1 -
arch/microblaze/kernel/process.c | 1 -
arch/nds32/Kconfig | 1 -
arch/nds32/include/asm/thread_info.h | 4 --
arch/nds32/include/asm/uaccess.h | 15 +----
arch/nds32/kernel/process.c | 5 +-
arch/nds32/mm/alignment.c | 3 -
arch/nios2/Kconfig | 1 -
arch/nios2/include/asm/thread_info.h | 9 ---
arch/nios2/include/asm/uaccess.h | 12 ----
arch/openrisc/Kconfig | 1 -
arch/openrisc/include/asm/thread_info.h | 7 ---
arch/openrisc/include/asm/uaccess.h | 23 --------
arch/parisc/include/asm/futex.h | 6 --
arch/parisc/lib/memcpy.c | 2 +-
arch/sparc/Kconfig | 2 +-
arch/sparc/include/asm/processor_32.h | 6 --
arch/sparc/include/asm/uaccess_32.h | 13 -----
arch/sparc/kernel/process_32.c | 2 -
arch/xtensa/Kconfig | 1 -
arch/xtensa/include/asm/asm-uaccess.h | 71 -----------------------
arch/xtensa/include/asm/processor.h | 7 ---
arch/xtensa/include/asm/thread_info.h | 3 -
arch/xtensa/include/asm/uaccess.h | 16 -----
arch/xtensa/kernel/asm-offsets.c | 3 -
drivers/hid/uhid.c | 2 +-
drivers/scsi/sg.c | 5 --
fs/exec.c | 6 --
include/asm-generic/access_ok.h | 10 +---
include/asm-generic/uaccess.h | 25 +-------
include/linux/syscalls.h | 4 --
include/linux/uaccess.h | 33 -----------
include/rdma/ib.h | 2 +-
kernel/events/callchain.c | 4 --
kernel/events/core.c | 3 -
kernel/exit.c | 14 -----
kernel/kthread.c | 5 --
kernel/stacktrace.c | 3 -
kernel/trace/bpf_trace.c | 4 --
mm/maccess.c | 11 ----
mm/memory.c | 8 ---
net/bpfilter/bpfilter_kern.c | 2 +-
72 files changed, 10 insertions(+), 522 deletions(-)
delete mode 100644 arch/arc/include/asm/segment.h
delete mode 100644 arch/csky/include/asm/segment.h
delete mode 100644 arch/h8300/include/asm/segment.h

diff --git a/arch/Kconfig b/arch/Kconfig
index fa5db36bda67..99349547afed 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -24,9 +24,6 @@ config KEXEC_ELF
config HAVE_IMA_KEXEC
bool

-config SET_FS
- bool
-
config HOTPLUG_SMT
bool

diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 4e87783c90ad..eee8b5b0a58b 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -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
diff --git a/arch/alpha/include/asm/processor.h b/arch/alpha/include/asm/processor.h
index 090499c99c1c..43e234c518b1 100644
--- a/arch/alpha/include/asm/processor.h
+++ b/arch/alpha/include/asm/processor.h
@@ -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 { }
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index 2592356e3215..fdc485d7787a 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -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 */
@@ -35,7 +34,6 @@ struct thread_info {
#define INIT_THREAD_INFO(tsk) \
{ \
.task = &tsk, \
- .addr_limit = KERNEL_DS, \
.preempt_count = INIT_PREEMPT_COUNT, \
}

diff --git a/arch/alpha/include/asm/uaccess.h b/arch/alpha/include/asm/uaccess.h
index 82c5743fc9cd..c32c2584c0b7 100644
--- a/arch/alpha/include/asm/uaccess.h
+++ b/arch/alpha/include/asm/uaccess.h
@@ -2,26 +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))
-
#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.
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 3c2a4753d09b..e0a60a27e14d 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -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
diff --git a/arch/arc/include/asm/segment.h b/arch/arc/include/asm/segment.h
deleted file mode 100644
index 871f8ab11bfd..000000000000
--- a/arch/arc/include/asm/segment.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (http://www.synopsys.com)
- */
-
-#ifndef __ASMARC_SEGMENT_H
-#define __ASMARC_SEGMENT_H
-
-#ifndef __ASSEMBLY__
-
-typedef unsigned long mm_segment_t;
-
-#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
-
-#define KERNEL_DS MAKE_MM_SEG(0)
-#define USER_DS MAKE_MM_SEG(TASK_SIZE)
-#define uaccess_kernel() (get_fs() == KERNEL_DS)
-
-#endif /* __ASSEMBLY__ */
-#endif /* __ASMARC_SEGMENT_H */
diff --git a/arch/arc/include/asm/thread_info.h b/arch/arc/include/asm/thread_info.h
index d36863e34bfc..1e0b2e3914d5 100644
--- a/arch/arc/include/asm/thread_info.h
+++ b/arch/arc/include/asm/thread_info.h
@@ -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
@@ -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 */
};
@@ -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)
diff --git a/arch/arc/include/asm/uaccess.h b/arch/arc/include/asm/uaccess.h
index 30f80b4be2ab..99712471c96a 100644
--- a/arch/arc/include/asm/uaccess.h
+++ b/arch/arc/include/asm/uaccess.h
@@ -638,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
diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c
index 106f83a5ea6d..c30b689bec2e 100644
--- a/arch/arm/lib/uaccess_with_memcpy.c
+++ b/arch/arm/lib/uaccess_with_memcpy.c
@@ -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();

@@ -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;
diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig
index 132f43f12dd8..75ef86605d69 100644
--- a/arch/csky/Kconfig
+++ b/arch/csky/Kconfig
@@ -79,7 +79,6 @@ config CSKY
select PCI_DOMAINS_GENERIC if PCI
select PCI_SYSCALL if PCI
select PCI_MSI if PCI
- select SET_FS
select TRACE_IRQFLAGS_SUPPORT

config LOCKDEP_SUPPORT
diff --git a/arch/csky/include/asm/processor.h b/arch/csky/include/asm/processor.h
index 817dd60ff152..688c7548b559 100644
--- a/arch/csky/include/asm/processor.h
+++ b/arch/csky/include/asm/processor.h
@@ -4,7 +4,6 @@
#define __ASM_CSKY_PROCESSOR_H

#include <linux/bitops.h>
-#include <asm/segment.h>
#include <asm/ptrace.h>
#include <asm/current.h>
#include <asm/cache.h>
@@ -59,7 +58,6 @@ struct thread_struct {
*/
#define start_thread(_regs, _pc, _usp) \
do { \
- set_fs(USER_DS); /* reads from user space */ \
(_regs)->pc = (_pc); \
(_regs)->regs[1] = 0; /* ABIV1 is R7, uClibc_main rtdl arg */ \
(_regs)->regs[2] = 0; \
diff --git a/arch/csky/include/asm/segment.h b/arch/csky/include/asm/segment.h
deleted file mode 100644
index 5bc1cc62b87f..000000000000
--- a/arch/csky/include/asm/segment.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#ifndef __ASM_CSKY_SEGMENT_H
-#define __ASM_CSKY_SEGMENT_H
-
-typedef struct {
- unsigned long seg;
-} mm_segment_t;
-
-#endif /* __ASM_CSKY_SEGMENT_H */
diff --git a/arch/csky/include/asm/thread_info.h b/arch/csky/include/asm/thread_info.h
index 8c349a8f904d..b5ed788f0c68 100644
--- a/arch/csky/include/asm/thread_info.h
+++ b/arch/csky/include/asm/thread_info.h
@@ -16,7 +16,6 @@ struct thread_info {
unsigned long flags;
int preempt_count;
unsigned long tp_value;
- mm_segment_t addr_limit;
struct restart_block restart_block;
struct pt_regs *regs;
unsigned int cpu;
@@ -26,7 +25,6 @@ struct thread_info {
{ \
.task = &tsk, \
.preempt_count = INIT_PREEMPT_COUNT, \
- .addr_limit = KERNEL_DS, \
.cpu = 0, \
.restart_block = { \
.fn = do_no_restart_syscall, \
diff --git a/arch/csky/include/asm/uaccess.h b/arch/csky/include/asm/uaccess.h
index fec8f77ffc99..2e927c21d8a1 100644
--- a/arch/csky/include/asm/uaccess.h
+++ b/arch/csky/include/asm/uaccess.h
@@ -3,8 +3,6 @@
#ifndef __ASM_CSKY_UACCESS_H
#define __ASM_CSKY_UACCESS_H

-#define user_addr_max() (current_thread_info()->addr_limit.seg)
-
/*
* __put_user_fn
*/
@@ -200,7 +198,6 @@ unsigned long raw_copy_to_user(void *to, const void *from, unsigned long n);
unsigned long __clear_user(void __user *to, unsigned long n);
#define __clear_user __clear_user

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

#endif /* __ASM_CSKY_UACCESS_H */
diff --git a/arch/csky/kernel/asm-offsets.c b/arch/csky/kernel/asm-offsets.c
index 1cbcba4b0dd1..d1e903579473 100644
--- a/arch/csky/kernel/asm-offsets.c
+++ b/arch/csky/kernel/asm-offsets.c
@@ -25,7 +25,6 @@ int main(void)
/* offsets into the thread_info struct */
DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count));
- DEFINE(TINFO_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
DEFINE(TINFO_TP_VALUE, offsetof(struct thread_info, tp_value));
DEFINE(TINFO_TASK, offsetof(struct thread_info, task));

diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 3e3e0f16f7e0..fe48c4f26cc8 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -24,7 +24,6 @@ config H8300
select HAVE_ARCH_KGDB
select HAVE_ARCH_HASH
select CPU_NO_EFFICIENT_FFS
- select SET_FS
select UACCESS_MEMCPY

config CPU_BIG_ENDIAN
diff --git a/arch/h8300/include/asm/processor.h b/arch/h8300/include/asm/processor.h
index 141a23eb62b7..ba171aa4dacb 100644
--- a/arch/h8300/include/asm/processor.h
+++ b/arch/h8300/include/asm/processor.h
@@ -13,7 +13,6 @@
#define __ASM_H8300_PROCESSOR_H

#include <linux/compiler.h>
-#include <asm/segment.h>
#include <asm/ptrace.h>
#include <asm/current.h>

diff --git a/arch/h8300/include/asm/segment.h b/arch/h8300/include/asm/segment.h
deleted file mode 100644
index 37950725d9b9..000000000000
--- a/arch/h8300/include/asm/segment.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _H8300_SEGMENT_H
-#define _H8300_SEGMENT_H
-
-/* define constants */
-#define USER_DATA (1)
-#ifndef __USER_DS
-#define __USER_DS (USER_DATA)
-#endif
-#define USER_PROGRAM (2)
-#define SUPER_DATA (3)
-#ifndef __KERNEL_DS
-#define __KERNEL_DS (SUPER_DATA)
-#endif
-#define SUPER_PROGRAM (4)
-
-#ifndef __ASSEMBLY__
-
-typedef struct {
- unsigned long seg;
-} mm_segment_t;
-
-#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
-#define USER_DS MAKE_MM_SEG(__USER_DS)
-#define KERNEL_DS MAKE_MM_SEG(__KERNEL_DS)
-
-/*
- * Get/set the SFC/DFC registers for MOVES instructions
- */
-
-static inline mm_segment_t get_fs(void)
-{
- return USER_DS;
-}
-
-#define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg)
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* _H8300_SEGMENT_H */
diff --git a/arch/h8300/include/asm/thread_info.h b/arch/h8300/include/asm/thread_info.h
index a518214d4ddd..ff2d873749a4 100644
--- a/arch/h8300/include/asm/thread_info.h
+++ b/arch/h8300/include/asm/thread_info.h
@@ -10,7 +10,6 @@
#define _ASM_THREAD_INFO_H

#include <asm/page.h>
-#include <asm/segment.h>

#ifdef __KERNEL__

@@ -31,7 +30,6 @@ struct thread_info {
unsigned long flags; /* low level flags */
int cpu; /* cpu we're on */
int preempt_count; /* 0 => preemptable, <0 => BUG */
- mm_segment_t addr_limit;
};

/*
@@ -43,7 +41,6 @@ struct thread_info {
.flags = 0, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
- .addr_limit = KERNEL_DS, \
}

/* how to get the thread information struct from C */
diff --git a/arch/h8300/kernel/entry.S b/arch/h8300/kernel/entry.S
index c6e289b5f1f2..42db87c17917 100644
--- a/arch/h8300/kernel/entry.S
+++ b/arch/h8300/kernel/entry.S
@@ -17,7 +17,6 @@
#include <linux/sys.h>
#include <asm/unistd.h>
#include <asm/setup.h>
-#include <asm/segment.h>
#include <asm/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
diff --git a/arch/h8300/kernel/head_ram.S b/arch/h8300/kernel/head_ram.S
index dbf8429f5fab..489462f0ee57 100644
--- a/arch/h8300/kernel/head_ram.S
+++ b/arch/h8300/kernel/head_ram.S
@@ -4,7 +4,6 @@
#include <linux/init.h>
#include <asm/unistd.h>
#include <asm/setup.h>
-#include <asm/segment.h>
#include <asm/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
diff --git a/arch/h8300/mm/init.c b/arch/h8300/mm/init.c
index f7bf4693e3b2..9fa13312720a 100644
--- a/arch/h8300/mm/init.c
+++ b/arch/h8300/mm/init.c
@@ -34,7 +34,6 @@
#include <linux/gfp.h>

#include <asm/setup.h>
-#include <asm/segment.h>
#include <asm/page.h>
#include <asm/sections.h>

@@ -71,11 +70,6 @@ void __init paging_init(void)
panic("%s: Failed to allocate %lu bytes align=0x%lx\n",
__func__, PAGE_SIZE, PAGE_SIZE);

- /*
- * Set up SFC/DFC registers (user data space).
- */
- set_fs(USER_DS);
-
pr_debug("before free_area_init\n");

pr_debug("free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n",
diff --git a/arch/h8300/mm/memory.c b/arch/h8300/mm/memory.c
index 4a60e2b5eb96..c950571064d2 100644
--- a/arch/h8300/mm/memory.c
+++ b/arch/h8300/mm/memory.c
@@ -24,7 +24,6 @@
#include <linux/types.h>

#include <asm/setup.h>
-#include <asm/segment.h>
#include <asm/page.h>
#include <asm/traps.h>
#include <asm/io.h>
diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig
index 15dd8f38b698..54eadf265178 100644
--- a/arch/hexagon/Kconfig
+++ b/arch/hexagon/Kconfig
@@ -30,7 +30,6 @@ config HEXAGON
select GENERIC_CLOCKEVENTS_BROADCAST
select MODULES_USE_ELF_RELA
select GENERIC_CPU_DEVICES
- select SET_FS
select ARCH_WANT_LD_ORPHAN_WARN
select TRACE_IRQFLAGS_SUPPORT
help
diff --git a/arch/hexagon/include/asm/thread_info.h b/arch/hexagon/include/asm/thread_info.h
index 535976665bf0..e90f280b9ce3 100644
--- a/arch/hexagon/include/asm/thread_info.h
+++ b/arch/hexagon/include/asm/thread_info.h
@@ -22,10 +22,6 @@

#ifndef __ASSEMBLY__

-typedef struct {
- unsigned long seg;
-} mm_segment_t;
-
/*
* This is union'd with the "bottom" of the kernel stack.
* It keeps track of thread info which is handy for routines
@@ -37,7 +33,6 @@ struct thread_info {
unsigned long flags; /* low level flags */
__u32 cpu; /* current cpu */
int preempt_count; /* 0=>preemptible,<0=>BUG */
- mm_segment_t addr_limit; /* segmentation sux */
/*
* used for syscalls somehow;
* seems to have a function pointer and four arguments
@@ -66,7 +61,6 @@ struct thread_info {
.flags = 0, \
.cpu = 0, \
.preempt_count = 1, \
- .addr_limit = KERNEL_DS, \
.sp = 0, \
.regs = NULL, \
}
diff --git a/arch/hexagon/kernel/process.c b/arch/hexagon/kernel/process.c
index 232dfd8956aa..dfa6b2757c05 100644
--- a/arch/hexagon/kernel/process.c
+++ b/arch/hexagon/kernel/process.c
@@ -105,7 +105,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
/*
* Parent sees new pid -- not necessary, not even possible at
* this point in the fork process
- * Might also want to set things like ti->addr_limit
*/

return 0;
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 59798e43cdb0..1fb1cec087b7 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -42,7 +42,6 @@ config MICROBLAZE
select CPU_NO_EFFICIENT_FFS
select MMU_GATHER_NO_RANGE
select SPARSE_IRQ
- select SET_FS
select ZONE_DMA
select TRACE_IRQFLAGS_SUPPORT

diff --git a/arch/microblaze/include/asm/thread_info.h b/arch/microblaze/include/asm/thread_info.h
index 44f5ca331862..a0ddd2a36fb9 100644
--- a/arch/microblaze/include/asm/thread_info.h
+++ b/arch/microblaze/include/asm/thread_info.h
@@ -56,17 +56,12 @@ struct cpu_context {
__u32 fsr;
};

-typedef struct {
- unsigned long seg;
-} mm_segment_t;
-
struct thread_info {
struct task_struct *task; /* main task structure */
unsigned long flags; /* low level flags */
unsigned long status; /* thread-synchronous flags */
__u32 cpu; /* current CPU */
__s32 preempt_count; /* 0 => preemptable,< 0 => BUG*/
- mm_segment_t addr_limit; /* thread address space */

struct cpu_context cpu_context;
};
@@ -80,7 +75,6 @@ struct thread_info {
.flags = 0, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
- .addr_limit = KERNEL_DS, \
}

/* how to get the thread information struct from C */
diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h
index bf9b7657a65a..3aab2f17e046 100644
--- a/arch/microblaze/include/asm/uaccess.h
+++ b/arch/microblaze/include/asm/uaccess.h
@@ -15,30 +15,6 @@
#include <linux/pgtable.h>
#include <asm/extable.h>
#include <linux/string.h>
-
-/*
- * On Microblaze the fs value is actually the top of the corresponding
- * address space.
- *
- * 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.
- *
- * For historical reasons, these macros are grossly misnamed.
- *
- * For non-MMU arch like Microblaze, KERNEL_DS and USER_DS is equal.
- */
-# define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
-
-# define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)
-# define USER_DS MAKE_MM_SEG(TASK_SIZE - 1)
-
-# define get_fs() (current_thread_info()->addr_limit)
-# define set_fs(val) (current_thread_info()->addr_limit = (val))
-# define user_addr_max() get_fs().seg
-
-# define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg)
-
#include <asm-generic/access_ok.h>

# define __FIXUP_SECTION ".section .fixup,\"ax\"\n"
diff --git a/arch/microblaze/kernel/asm-offsets.c b/arch/microblaze/kernel/asm-offsets.c
index b77dd188dec4..47ee409508b1 100644
--- a/arch/microblaze/kernel/asm-offsets.c
+++ b/arch/microblaze/kernel/asm-offsets.c
@@ -86,7 +86,6 @@ int main(int argc, char *argv[])
/* struct thread_info */
DEFINE(TI_TASK, offsetof(struct thread_info, task));
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
- DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
DEFINE(TI_CPU_CONTEXT, offsetof(struct thread_info, cpu_context));
DEFINE(TI_PREEMPT_COUNT, offsetof(struct thread_info, preempt_count));
BLANK();
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index 5e2b91c1e8ce..1b944d319d73 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -18,7 +18,6 @@
#include <linux/tick.h>
#include <linux/bitops.h>
#include <linux/ptrace.h>
-#include <linux/uaccess.h> /* for USER_DS macros */
#include <asm/cacheflush.h>

void show_regs(struct pt_regs *regs)
diff --git a/arch/nds32/Kconfig b/arch/nds32/Kconfig
index 4d1421b18734..013249430fa3 100644
--- a/arch/nds32/Kconfig
+++ b/arch/nds32/Kconfig
@@ -44,7 +44,6 @@ config NDS32
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_DYNAMIC_FTRACE
- select SET_FS
select TRACE_IRQFLAGS_SUPPORT
help
Andes(nds32) Linux support.
diff --git a/arch/nds32/include/asm/thread_info.h b/arch/nds32/include/asm/thread_info.h
index d3967ad184f0..bd8f81cf2ce5 100644
--- a/arch/nds32/include/asm/thread_info.h
+++ b/arch/nds32/include/asm/thread_info.h
@@ -16,8 +16,6 @@ struct task_struct;
#include <asm/ptrace.h>
#include <asm/types.h>

-typedef unsigned long mm_segment_t;
-
/*
* low level task data that entry.S needs immediate access to.
* __switch_to() assumes cpu_context follows immediately after cpu_domain.
@@ -25,12 +23,10 @@ typedef unsigned long mm_segment_t;
struct thread_info {
unsigned long flags; /* low level flags */
__s32 preempt_count; /* 0 => preemptable, <0 => bug */
- mm_segment_t addr_limit; /* address limit */
};
#define INIT_THREAD_INFO(tsk) \
{ \
.preempt_count = INIT_PREEMPT_COUNT, \
- .addr_limit = KERNEL_DS, \
}
#define thread_saved_pc(tsk) ((unsigned long)(tsk->thread.cpu_context.pc))
#define thread_saved_fp(tsk) ((unsigned long)(tsk->thread.cpu_context.fp))
diff --git a/arch/nds32/include/asm/uaccess.h b/arch/nds32/include/asm/uaccess.h
index 832d642a4068..377548d4451a 100644
--- a/arch/nds32/include/asm/uaccess.h
+++ b/arch/nds32/include/asm/uaccess.h
@@ -11,6 +11,7 @@
#include <asm/errno.h>
#include <asm/memory.h>
#include <asm/types.h>
+#include <asm-generic/access_ok.h>

#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"

@@ -33,20 +34,6 @@ struct exception_table_entry {

extern int fixup_exception(struct pt_regs *regs);

-#define KERNEL_DS ((mm_segment_t) { ~0UL })
-#define USER_DS ((mm_segment_t) {TASK_SIZE - 1})
-
-#define get_fs() (current_thread_info()->addr_limit)
-#define user_addr_max get_fs
-#define uaccess_kernel() (get_fs() == KERNEL_DS)
-
-static inline void set_fs(mm_segment_t fs)
-{
- current_thread_info()->addr_limit = fs;
-}
-
-#include <asm-generic/access_ok.h>
-
/*
* Single-value transfer routines. They automatically use the right
* size if we just have the right pointer type. Note that the functions
diff --git a/arch/nds32/kernel/process.c b/arch/nds32/kernel/process.c
index 49fab9e39cbf..d35c1f63fa11 100644
--- a/arch/nds32/kernel/process.c
+++ b/arch/nds32/kernel/process.c
@@ -119,9 +119,8 @@ void show_regs(struct pt_regs *regs)
regs->uregs[7], regs->uregs[6], regs->uregs[5], regs->uregs[4]);
pr_info("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
regs->uregs[3], regs->uregs[2], regs->uregs[1], regs->uregs[0]);
- pr_info(" IRQs o%s Segment %s\n",
- interrupts_enabled(regs) ? "n" : "ff",
- uaccess_kernel() ? "kernel" : "user");
+ pr_info(" IRQs o%s Segment user\n",
+ interrupts_enabled(regs) ? "n" : "ff");
}

EXPORT_SYMBOL(show_regs);
diff --git a/arch/nds32/mm/alignment.c b/arch/nds32/mm/alignment.c
index 1eb7ded6992b..9c2c0a454da8 100644
--- a/arch/nds32/mm/alignment.c
+++ b/arch/nds32/mm/alignment.c
@@ -512,7 +512,6 @@ int do_unaligned_access(unsigned long addr, struct pt_regs *regs)
{
unsigned long inst;
int ret = -EFAULT;
- mm_segment_t seg;

inst = get_inst(regs->ipc);

@@ -520,12 +519,10 @@ int do_unaligned_access(unsigned long addr, struct pt_regs *regs)
"Faulting addr: 0x%08lx, pc: 0x%08lx [inst: 0x%08lx ]\n", addr,
regs->ipc, inst);

- seg = force_uaccess_begin();
if (inst & NDS32_16BIT_INSTRUCTION)
ret = do_16((inst >> 16) & 0xffff, regs);
else
ret = do_32(inst, regs);
- force_uaccess_end(seg);

return ret;
}
diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig
index 33fd06f5fa41..4167f1eb4cd8 100644
--- a/arch/nios2/Kconfig
+++ b/arch/nios2/Kconfig
@@ -24,7 +24,6 @@ config NIOS2
select USB_ARCH_HAS_HCD if USB_SUPPORT
select CPU_NO_EFFICIENT_FFS
select MMU_GATHER_NO_RANGE if MMU
- select SET_FS

config GENERIC_CSUM
def_bool y
diff --git a/arch/nios2/include/asm/thread_info.h b/arch/nios2/include/asm/thread_info.h
index 272d2c72a727..bcc0e9915ebd 100644
--- a/arch/nios2/include/asm/thread_info.h
+++ b/arch/nios2/include/asm/thread_info.h
@@ -26,10 +26,6 @@

#ifndef __ASSEMBLY__

-typedef struct {
- unsigned long seg;
-} mm_segment_t;
-
/*
* low level task data that entry.S needs immediate access to
* - this struct should fit entirely inside of one cache line
@@ -42,10 +38,6 @@ struct thread_info {
unsigned long flags; /* low level flags */
__u32 cpu; /* current CPU */
int preempt_count; /* 0 => preemptable,<0 => BUG */
- mm_segment_t addr_limit; /* thread address space:
- 0-0x7FFFFFFF for user-thead
- 0-0xFFFFFFFF for kernel-thread
- */
struct pt_regs *regs;
};

@@ -60,7 +52,6 @@ struct thread_info {
.flags = 0, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
- .addr_limit = KERNEL_DS, \
}

/* how to get the thread information struct from C */
diff --git a/arch/nios2/include/asm/uaccess.h b/arch/nios2/include/asm/uaccess.h
index 6664ddc0e8e5..b8299082adbe 100644
--- a/arch/nios2/include/asm/uaccess.h
+++ b/arch/nios2/include/asm/uaccess.h
@@ -18,18 +18,6 @@
#include <asm/page.h>

#include <asm/extable.h>
-
-/*
- * Segment stuff
- */
-#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
-#define USER_DS MAKE_MM_SEG(0x80000000UL)
-#define KERNEL_DS MAKE_MM_SEG(0)
-
-
-#define get_fs() (current_thread_info()->addr_limit)
-#define set_fs(seg) (current_thread_info()->addr_limit = (seg))
-
#include <asm-generic/access_ok.h>

# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n"
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index f724b3f1aeed..0d68adf6e02b 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -36,7 +36,6 @@ config OPENRISC
select ARCH_WANT_FRAME_POINTERS
select GENERIC_IRQ_MULTI_HANDLER
select MMU_GATHER_NO_RANGE if MMU
- select SET_FS
select TRACE_IRQFLAGS_SUPPORT

config CPU_BIG_ENDIAN
diff --git a/arch/openrisc/include/asm/thread_info.h b/arch/openrisc/include/asm/thread_info.h
index 659834ab87fa..4af3049c34c2 100644
--- a/arch/openrisc/include/asm/thread_info.h
+++ b/arch/openrisc/include/asm/thread_info.h
@@ -40,18 +40,12 @@
*/
#ifndef __ASSEMBLY__

-typedef unsigned long mm_segment_t;
-
struct thread_info {
struct task_struct *task; /* main task structure */
unsigned long flags; /* low level flags */
__u32 cpu; /* current CPU */
__s32 preempt_count; /* 0 => preemptable, <0 => BUG */

- mm_segment_t addr_limit; /* thread address space:
- 0-0x7FFFFFFF for user-thead
- 0-0xFFFFFFFF for kernel-thread
- */
__u8 supervisor_stack[0];

/* saved context data */
@@ -71,7 +65,6 @@ struct thread_info {
.flags = 0, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
- .addr_limit = KERNEL_DS, \
.ksp = 0, \
}

diff --git a/arch/openrisc/include/asm/uaccess.h b/arch/openrisc/include/asm/uaccess.h
index 8f049ec99b3e..d6500a374e18 100644
--- a/arch/openrisc/include/asm/uaccess.h
+++ b/arch/openrisc/include/asm/uaccess.h
@@ -22,29 +22,6 @@
#include <linux/string.h>
#include <asm/page.h>
#include <asm/extable.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.
- *
- * For historical reasons, these macros are grossly misnamed.
- */
-
-/* addr_limit is the maximum accessible address for the task. we misuse
- * the KERNEL_DS and USER_DS values to both assign and compare the
- * addr_limit values through the equally misnamed get/set_fs macros.
- * (see above)
- */
-
-#define KERNEL_DS (~0UL)
-
-#define USER_DS (TASK_SIZE)
-#define get_fs() (current_thread_info()->addr_limit)
-#define set_fs(x) (current_thread_info()->addr_limit = (x))
-
-#define uaccess_kernel() (get_fs() == KERNEL_DS)
-
#include <asm-generic/access_ok.h>

/*
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
index b5835325d44b..3222206cb3ea 100644
--- a/arch/parisc/include/asm/futex.h
+++ b/arch/parisc/include/asm/futex.h
@@ -96,12 +96,6 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
u32 val;
unsigned long flags;

- /* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
- * our gateway page, and causes no end of trouble...
- */
- if (uaccess_kernel() && !uaddr)
- return -EFAULT;
-
if (!access_ok(uaddr, sizeof(u32)))
return -EFAULT;

diff --git a/arch/parisc/lib/memcpy.c b/arch/parisc/lib/memcpy.c
index ea70a0e08321..468704ce8a1c 100644
--- a/arch/parisc/lib/memcpy.c
+++ b/arch/parisc/lib/memcpy.c
@@ -13,7 +13,7 @@
#include <linux/compiler.h>
#include <linux/uaccess.h>

-#define get_user_space() (uaccess_kernel() ? 0 : mfsp(3))
+#define get_user_space() (mfsp(3))
#define get_kernel_space() (0)

/* Returns 0 for success, otherwise, returns number of bytes not transferred. */
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 9f6f9bce5292..9276f321b3e3 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -46,7 +46,6 @@ config SPARC
select LOCKDEP_SMALL if LOCKDEP
select NEED_DMA_MAP_STATE
select NEED_SG_DMA_LENGTH
- select SET_FS
select TRACE_IRQFLAGS_SUPPORT

config SPARC32
@@ -101,6 +100,7 @@ config SPARC64
select HAVE_SETUP_PER_CPU_AREA
select NEED_PER_CPU_EMBED_FIRST_CHUNK
select NEED_PER_CPU_PAGE_FIRST_CHUNK
+ select SET_FS

config ARCH_PROC_KCORE_TEXT
def_bool y
diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h
index 647bf0ac7beb..b26c35336b51 100644
--- a/arch/sparc/include/asm/processor_32.h
+++ b/arch/sparc/include/asm/processor_32.h
@@ -32,10 +32,6 @@ struct fpq {
};
#endif

-typedef struct {
- int seg;
-} mm_segment_t;
-
/* The Sparc processor specific thread struct. */
struct thread_struct {
struct pt_regs *kregs;
@@ -50,11 +46,9 @@ struct thread_struct {
unsigned long fsr;
unsigned long fpqdepth;
struct fpq fpqueue[16];
- mm_segment_t current_ds;
};

#define INIT_THREAD { \
- .current_ds = KERNEL_DS, \
.kregs = (struct pt_regs *)(init_stack+THREAD_SIZE)-1 \
}

diff --git a/arch/sparc/include/asm/uaccess_32.h b/arch/sparc/include/asm/uaccess_32.h
index 367747116260..9fd6c53644b6 100644
--- a/arch/sparc/include/asm/uaccess_32.h
+++ b/arch/sparc/include/asm/uaccess_32.h
@@ -12,19 +12,6 @@
#include <linux/string.h>

#include <asm/processor.h>
-
-/* Sparc is not segmented, however we need to be able to fool access_ok()
- * when doing system calls from kernel mode legitimately.
- *
- * "For historical reasons, these macros are grossly misnamed." -Linus
- */
-
-#define KERNEL_DS ((mm_segment_t) { 0 })
-#define USER_DS ((mm_segment_t) { -1 })
-
-#define get_fs() (current->thread.current_ds)
-#define set_fs(val) ((current->thread.current_ds) = (val))
-
#include <asm-generic/access_ok.h>

/* Uh, these should become the main single-value transfer routines..
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
index 2dc0bf9fe62e..88c0c14aaff0 100644
--- a/arch/sparc/kernel/process_32.c
+++ b/arch/sparc/kernel/process_32.c
@@ -300,7 +300,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
extern int nwindows;
unsigned long psr;
memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ);
- p->thread.current_ds = KERNEL_DS;
ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8);
childregs->u_regs[UREG_G1] = sp; /* function */
childregs->u_regs[UREG_G2] = arg;
@@ -311,7 +310,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
}
memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
childregs->u_regs[UREG_FP] = sp;
- p->thread.current_ds = USER_DS;
ti->kpc = (((unsigned long) ret_from_fork) - 0x8);
ti->kpsr = current->thread.fork_kpsr | PSR_PIL;
ti->kwim = current->thread.fork_kwim;
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 8ac599aa6d99..09f7616a0b46 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -40,7 +40,6 @@ config XTENSA
select IRQ_DOMAIN
select MODULES_USE_ELF_RELA
select PERF_USE_VMALLOC
- select SET_FS
select TRACE_IRQFLAGS_SUPPORT
select VIRT_TO_BUS
help
diff --git a/arch/xtensa/include/asm/asm-uaccess.h b/arch/xtensa/include/asm/asm-uaccess.h
index 7f6cf4151843..7cec869136e3 100644
--- a/arch/xtensa/include/asm/asm-uaccess.h
+++ b/arch/xtensa/include/asm/asm-uaccess.h
@@ -23,76 +23,6 @@
#include <asm/asm-offsets.h>
#include <asm/processor.h>

-/*
- * These assembly macros mirror the C macros in asm/uaccess.h. They
- * should always have identical functionality. See
- * arch/xtensa/kernel/sys.S for usage.
- */
-
-#define KERNEL_DS 0
-#define USER_DS 1
-
-/*
- * get_fs reads current->thread.current_ds into a register.
- * On Entry:
- * <ad> anything
- * <sp> stack
- * On Exit:
- * <ad> contains current->thread.current_ds
- */
- .macro get_fs ad, sp
- GET_CURRENT(\ad,\sp)
-#if THREAD_CURRENT_DS > 1020
- addi \ad, \ad, TASK_THREAD
- l32i \ad, \ad, THREAD_CURRENT_DS - TASK_THREAD
-#else
- l32i \ad, \ad, THREAD_CURRENT_DS
-#endif
- .endm
-
-/*
- * set_fs sets current->thread.current_ds to some value.
- * On Entry:
- * <at> anything (temp register)
- * <av> value to write
- * <sp> stack
- * On Exit:
- * <at> destroyed (actually, current)
- * <av> preserved, value to write
- */
- .macro set_fs at, av, sp
- GET_CURRENT(\at,\sp)
- s32i \av, \at, THREAD_CURRENT_DS
- .endm
-
-/*
- * kernel_ok determines whether we should bypass addr/size checking.
- * See the equivalent C-macro version below for clarity.
- * On success, kernel_ok branches to a label indicated by parameter
- * <success>. This implies that the macro falls through to the next
- * insruction on an error.
- *
- * Note that while this macro can be used independently, we designed
- * in for optimal use in the access_ok macro below (i.e., we fall
- * through on error).
- *
- * On Entry:
- * <at> anything (temp register)
- * <success> label to branch to on success; implies
- * fall-through macro on error
- * <sp> stack pointer
- * On Exit:
- * <at> destroyed (actually, current->thread.current_ds)
- */
-
-#if ((KERNEL_DS != 0) || (USER_DS == 0))
-# error Assembly macro kernel_ok fails
-#endif
- .macro kernel_ok at, sp, success
- get_fs \at, \sp
- beqz \at, \success
- .endm
-
/*
* user_ok determines whether the access to user-space memory is allowed.
* See the equivalent C-macro version below for clarity.
@@ -147,7 +77,6 @@
* <at> destroyed
*/
.macro access_ok aa, as, at, sp, error
- kernel_ok \at, \sp, .Laccess_ok_\@
user_ok \aa, \as, \at, \error
.Laccess_ok_\@:
.endm
diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h
index 37d3e9887fe7..abad7c3df46f 100644
--- a/arch/xtensa/include/asm/processor.h
+++ b/arch/xtensa/include/asm/processor.h
@@ -152,18 +152,12 @@
*/
#define SPILL_SLOT_CALL12(sp, reg) (*(((unsigned long *)(sp)) - 16 + (reg)))

-typedef struct {
- unsigned long seg;
-} mm_segment_t;
-
struct thread_struct {

/* kernel's return address and stack pointer for context switching */
unsigned long ra; /* kernel's a0: return address and window call size */
unsigned long sp; /* kernel's a1: stack pointer */

- mm_segment_t current_ds; /* see uaccess.h for example uses */
-
/* struct xtensa_cpuinfo info; */

unsigned long bad_vaddr; /* last user fault */
@@ -186,7 +180,6 @@ struct thread_struct {
{ \
ra: 0, \
sp: sizeof(init_stack) + (long) &init_stack, \
- current_ds: {0}, \
/*info: {0}, */ \
bad_vaddr: 0, \
bad_uaddr: 0, \
diff --git a/arch/xtensa/include/asm/thread_info.h b/arch/xtensa/include/asm/thread_info.h
index a312333a9add..f6fcbba1d02f 100644
--- a/arch/xtensa/include/asm/thread_info.h
+++ b/arch/xtensa/include/asm/thread_info.h
@@ -52,8 +52,6 @@ struct thread_info {
__u32 cpu; /* current CPU */
__s32 preempt_count; /* 0 => preemptable,< 0 => BUG*/

- mm_segment_t addr_limit; /* thread address space */
-
unsigned long cpenable;
#if XCHAL_HAVE_EXCLUSIVE
/* result of the most recent exclusive store */
@@ -81,7 +79,6 @@ struct thread_info {
.flags = 0, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
- .addr_limit = KERNEL_DS, \
}

/* how to get the thread information struct from C */
diff --git a/arch/xtensa/include/asm/uaccess.h b/arch/xtensa/include/asm/uaccess.h
index 0edd9e4b23d0..56aec6d504fe 100644
--- a/arch/xtensa/include/asm/uaccess.h
+++ b/arch/xtensa/include/asm/uaccess.h
@@ -19,22 +19,6 @@
#include <linux/prefetch.h>
#include <asm/types.h>
#include <asm/extable.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.
- *
- * For historical reasons (Data Segment Register?), these macros are
- * grossly misnamed.
- */
-
-#define KERNEL_DS ((mm_segment_t) { 0 })
-#define USER_DS ((mm_segment_t) { 1 })
-
-#define get_fs() (current->thread.current_ds)
-#define set_fs(val) (current->thread.current_ds = (val))
-
#include <asm-generic/access_ok.h>

/*
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
index dc5c83cad9be..f1fd1390d069 100644
--- a/arch/xtensa/kernel/asm-offsets.c
+++ b/arch/xtensa/kernel/asm-offsets.c
@@ -87,7 +87,6 @@ int main(void)
OFFSET(TI_STSTUS, thread_info, status);
OFFSET(TI_CPU, thread_info, cpu);
OFFSET(TI_PRE_COUNT, thread_info, preempt_count);
- OFFSET(TI_ADDR_LIMIT, thread_info, addr_limit);

/* struct thread_info (offset from start_struct) */
DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
@@ -108,8 +107,6 @@ int main(void)
#endif
DEFINE(THREAD_XTREGS_USER, offsetof (struct thread_info, xtregs_user));
DEFINE(XTREGS_USER_SIZE, sizeof(xtregs_user_t));
- DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, \
- thread.current_ds));

/* struct mm_struct */
DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users));
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 614adb510dbd..2a918aeb0af1 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -747,7 +747,7 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
* copied from, so it's unsafe to allow this with elevated
* privileges (e.g. from a setuid binary) or via kernel_write().
*/
- if (file->f_cred != current_cred() || uaccess_kernel()) {
+ if (file->f_cred != current_cred()) {
pr_err_once("UHID_CREATE from different security context by process %d (%s), this is not allowed.\n",
task_tgid_vnr(current), current->comm);
ret = -EACCES;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 6b43e97bd417..aaa2376b9d34 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -224,11 +224,6 @@ static int sg_check_file_access(struct file *filp, const char *caller)
caller, task_tgid_vnr(current), current->comm);
return -EPERM;
}
- if (uaccess_kernel()) {
- pr_err_once("%s: process %d (%s) called from kernel context, this is not allowed.\n",
- caller, task_tgid_vnr(current), current->comm);
- return -EACCES;
- }
return 0;
}

diff --git a/fs/exec.c b/fs/exec.c
index 79f2c9483302..bc68a0c089ac 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1303,12 +1303,6 @@ int begin_new_exec(struct linux_binprm * bprm)
if (retval)
goto out_unlock;

- /*
- * Ensure that the uaccess routines can actually operate on userspace
- * pointers:
- */
- force_uaccess_begin();
-
if (me->flags & PF_KTHREAD)
free_kthread_struct(me);
me->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD |
diff --git a/include/asm-generic/access_ok.h b/include/asm-generic/access_ok.h
index 1aad8964d2ed..88a7cb5d9aad 100644
--- a/include/asm-generic/access_ok.h
+++ b/include/asm-generic/access_ok.h
@@ -16,16 +16,8 @@
#define TASK_SIZE_MAX TASK_SIZE
#endif

-#ifndef uaccess_kernel
-#ifdef CONFIG_SET_FS
-#define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg)
-#else
-#define uaccess_kernel() (0)
-#endif
-#endif
-
#ifndef user_addr_max
-#define user_addr_max() (uaccess_kernel() ? ~0UL : TASK_SIZE_MAX)
+#define user_addr_max() TASK_SIZE_MAX
#endif

#ifndef __access_ok
diff --git a/include/asm-generic/uaccess.h b/include/asm-generic/uaccess.h
index ebc685dc8d74..a5be9e61a2a2 100644
--- a/include/asm-generic/uaccess.h
+++ b/include/asm-generic/uaccess.h
@@ -8,6 +8,7 @@
* address space, e.g. all NOMMU machines.
*/
#include <linux/string.h>
+#include <asm-generic/access_ok.h>

#ifdef CONFIG_UACCESS_MEMCPY
#include <asm/unaligned.h>
@@ -94,30 +95,6 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
#define INLINE_COPY_TO_USER
#endif /* CONFIG_UACCESS_MEMCPY */

-#ifdef CONFIG_SET_FS
-#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
-
-#ifndef KERNEL_DS
-#define KERNEL_DS MAKE_MM_SEG(~0UL)
-#endif
-
-#ifndef USER_DS
-#define USER_DS MAKE_MM_SEG(TASK_SIZE - 1)
-#endif
-
-#ifndef get_fs
-#define get_fs() (current_thread_info()->addr_limit)
-
-static inline void set_fs(mm_segment_t fs)
-{
- current_thread_info()->addr_limit = fs;
-}
-#endif
-
-#endif /* CONFIG_SET_FS */
-
-#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.
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 819c0cb00b6d..a34b0f9a9972 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -290,10 +290,6 @@ static inline void addr_limit_user_check(void)
return;
#endif

- if (CHECK_DATA_CORRUPTION(uaccess_kernel(),
- "Invalid address limit on user-mode return"))
- force_sig(SIGKILL);
-
#ifdef TIF_FSCHECK
clear_thread_flag(TIF_FSCHECK);
#endif
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index 2c31667e62e0..2421a41f3a8e 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -10,39 +10,6 @@

#include <asm/uaccess.h>

-#ifdef CONFIG_SET_FS
-/*
- * Force the uaccess routines to be wired up for actual userspace access,
- * overriding any possible set_fs(KERNEL_DS) still lingering around. Undone
- * using force_uaccess_end below.
- */
-static inline mm_segment_t force_uaccess_begin(void)
-{
- mm_segment_t fs = get_fs();
-
- set_fs(USER_DS);
- return fs;
-}
-
-static inline void force_uaccess_end(mm_segment_t oldfs)
-{
- set_fs(oldfs);
-}
-#else /* CONFIG_SET_FS */
-typedef struct {
- /* empty dummy */
-} mm_segment_t;
-
-static inline mm_segment_t force_uaccess_begin(void)
-{
- return (mm_segment_t) { };
-}
-
-static inline void force_uaccess_end(mm_segment_t oldfs)
-{
-}
-#endif /* CONFIG_SET_FS */
-
/*
* Architectures should provide two primitives (raw_copy_{to,from}_user())
* and get rid of their private instances of copy_{to,from}_user() and
diff --git a/include/rdma/ib.h b/include/rdma/ib.h
index 83139b9ce409..f7c185ff7a11 100644
--- a/include/rdma/ib.h
+++ b/include/rdma/ib.h
@@ -75,7 +75,7 @@ struct sockaddr_ib {
*/
static inline bool ib_safe_file_access(struct file *filp)
{
- return filp->f_cred == current_cred() && !uaccess_kernel();
+ return filp->f_cred == current_cred();
}

#endif /* _RDMA_IB_H */
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
index 58cbe357fb2b..1273be84392c 100644
--- a/kernel/events/callchain.c
+++ b/kernel/events/callchain.c
@@ -209,17 +209,13 @@ get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,
}

if (regs) {
- mm_segment_t fs;
-
if (crosstask)
goto exit_put;

if (add_mark)
perf_callchain_store_context(&ctx, PERF_CONTEXT_USER);

- fs = force_uaccess_begin();
perf_callchain_user(&ctx, regs);
- force_uaccess_end(fs);
}
}

diff --git a/kernel/events/core.c b/kernel/events/core.c
index 57c7197838db..11ca7303d6df 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -6746,7 +6746,6 @@ perf_output_sample_ustack(struct perf_output_handle *handle, u64 dump_size,
unsigned long sp;
unsigned int rem;
u64 dyn_size;
- mm_segment_t fs;

/*
* We dump:
@@ -6764,9 +6763,7 @@ perf_output_sample_ustack(struct perf_output_handle *handle, u64 dump_size,

/* Data. */
sp = perf_user_stack_pointer(regs);
- fs = force_uaccess_begin();
rem = __output_copy_user(handle, (void *) sp, dump_size);
- force_uaccess_end(fs);
dyn_size = dump_size - rem;

perf_output_skip(handle, rem);
diff --git a/kernel/exit.c b/kernel/exit.c
index b00a25bb4ab9..0884a75bc2f8 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -737,20 +737,6 @@ void __noreturn do_exit(long code)

WARN_ON(blk_needs_flush_plug(tsk));

- /*
- * If do_dead is called because this processes oopsed, it's possible
- * that get_fs() was left as KERNEL_DS, so reset it to USER_DS before
- * continuing. Amongst other possible reasons, this is to prevent
- * mm_release()->clear_child_tid() from writing to a user-controlled
- * kernel address.
- *
- * On uptodate architectures force_uaccess_begin is a noop. On
- * architectures that still have set_fs/get_fs in addition to handling
- * oopses handles kernel threads that run as set_fs(KERNEL_DS) by
- * default.
- */
- force_uaccess_begin();
-
kcov_task_exit(tsk);

coredump_task_exit(tsk);
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 38c6dd822da8..16c2275d4b50 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -55,7 +55,6 @@ struct kthread {
int result;
int (*threadfn)(void *);
void *data;
- mm_segment_t oldfs;
struct completion parked;
struct completion exited;
#ifdef CONFIG_BLK_CGROUP
@@ -1441,8 +1440,6 @@ void kthread_use_mm(struct mm_struct *mm)
mmdrop(active_mm);
else
smp_mb();
-
- to_kthread(tsk)->oldfs = force_uaccess_begin();
}
EXPORT_SYMBOL_GPL(kthread_use_mm);

@@ -1457,8 +1454,6 @@ void kthread_unuse_mm(struct mm_struct *mm)
WARN_ON_ONCE(!(tsk->flags & PF_KTHREAD));
WARN_ON_ONCE(!tsk->mm);

- force_uaccess_end(to_kthread(tsk)->oldfs);
-
task_lock(tsk);
/*
* When a kthread stops operating on an address space, the loop
diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c
index 9c625257023d..9ed5ce989415 100644
--- a/kernel/stacktrace.c
+++ b/kernel/stacktrace.c
@@ -226,15 +226,12 @@ unsigned int stack_trace_save_user(unsigned long *store, unsigned int size)
.store = store,
.size = size,
};
- mm_segment_t fs;

/* Trace user stack if not a kernel thread */
if (current->flags & PF_KTHREAD)
return 0;

- fs = force_uaccess_begin();
arch_stack_walk_user(consume_entry, &c, task_pt_regs(current));
- force_uaccess_end(fs);

return c.len;
}
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 21aa30644219..8115fff17018 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -332,8 +332,6 @@ BPF_CALL_3(bpf_probe_write_user, void __user *, unsafe_ptr, const void *, src,
if (unlikely(in_interrupt() ||
current->flags & (PF_KTHREAD | PF_EXITING)))
return -EPERM;
- if (unlikely(uaccess_kernel()))
- return -EPERM;
if (unlikely(!nmi_uaccess_okay()))
return -EPERM;

@@ -835,8 +833,6 @@ static int bpf_send_signal_common(u32 sig, enum pid_type type)
*/
if (unlikely(current->flags & (PF_KTHREAD | PF_EXITING)))
return -EPERM;
- if (unlikely(uaccess_kernel()))
- return -EPERM;
if (unlikely(!nmi_uaccess_okay()))
return -EPERM;

diff --git a/mm/maccess.c b/mm/maccess.c
index cbd1b3959af2..106820b33a2b 100644
--- a/mm/maccess.c
+++ b/mm/maccess.c
@@ -113,14 +113,11 @@ long strncpy_from_kernel_nofault(char *dst, const void *unsafe_addr, long count)
long copy_from_user_nofault(void *dst, const void __user *src, size_t size)
{
long ret = -EFAULT;
- mm_segment_t old_fs = force_uaccess_begin();
-
if (access_ok(src, size)) {
pagefault_disable();
ret = __copy_from_user_inatomic(dst, src, size);
pagefault_enable();
}
- force_uaccess_end(old_fs);

if (ret)
return -EFAULT;
@@ -140,14 +137,12 @@ EXPORT_SYMBOL_GPL(copy_from_user_nofault);
long copy_to_user_nofault(void __user *dst, const void *src, size_t size)
{
long ret = -EFAULT;
- mm_segment_t old_fs = force_uaccess_begin();

if (access_ok(dst, size)) {
pagefault_disable();
ret = __copy_to_user_inatomic(dst, src, size);
pagefault_enable();
}
- force_uaccess_end(old_fs);

if (ret)
return -EFAULT;
@@ -176,17 +171,14 @@ EXPORT_SYMBOL_GPL(copy_to_user_nofault);
long strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
long count)
{
- mm_segment_t old_fs;
long ret;

if (unlikely(count <= 0))
return 0;

- old_fs = force_uaccess_begin();
pagefault_disable();
ret = strncpy_from_user(dst, unsafe_addr, count);
pagefault_enable();
- force_uaccess_end(old_fs);

if (ret >= count) {
ret = count;
@@ -216,14 +208,11 @@ long strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
*/
long strnlen_user_nofault(const void __user *unsafe_addr, long count)
{
- mm_segment_t old_fs;
int ret;

- old_fs = force_uaccess_begin();
pagefault_disable();
ret = strnlen_user(unsafe_addr, count);
pagefault_enable();
- force_uaccess_end(old_fs);

return ret;
}
diff --git a/mm/memory.c b/mm/memory.c
index c125c4969913..9a6ebf68a846 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -5256,14 +5256,6 @@ void print_vma_addr(char *prefix, unsigned long ip)
#if defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_DEBUG_ATOMIC_SLEEP)
void __might_fault(const char *file, int line)
{
- /*
- * Some code (nfs/sunrpc) uses socket ops on kernel memory while
- * holding the mmap_lock, this is safe because kernel memory doesn't
- * get paged out, therefore we'll never actually fault, and the
- * below annotations will generate false positives.
- */
- if (uaccess_kernel())
- return;
if (pagefault_disabled())
return;
__might_sleep(file, line);
diff --git a/net/bpfilter/bpfilter_kern.c b/net/bpfilter/bpfilter_kern.c
index 51a941b56ec3..422ec6e7ccff 100644
--- a/net/bpfilter/bpfilter_kern.c
+++ b/net/bpfilter/bpfilter_kern.c
@@ -70,7 +70,7 @@ static int bpfilter_process_sockopt(struct sock *sk, int optname,
.addr = (uintptr_t)optval.user,
.len = optlen,
};
- if (uaccess_kernel() || sockptr_is_kernel(optval)) {
+ if (sockptr_is_kernel(optval)) {
pr_err("kernel access not supported\n");
return -EFAULT;
}
--
2.29.2

2022-02-16 14:13:51

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v2 08/18] uaccess: add generic __{get,put}_kernel_nofault

From: Arnd Bergmann <[email protected]>

Nine architectures are still missing __{get,put}_kernel_nofault:
alpha, ia64, microblaze, nds32, nios2, openrisc, sh, sparc32, xtensa.

Add a generic version that lets everything use the normal
copy_{from,to}_kernel_nofault() code based on these, removing the last
use of get_fs()/set_fs() from architecture-independent code.

Reviewed-by: Christoph Hellwig <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
arch/arm/include/asm/uaccess.h | 2 -
arch/arm64/include/asm/uaccess.h | 2 -
arch/m68k/include/asm/uaccess.h | 2 -
arch/mips/include/asm/uaccess.h | 2 -
arch/parisc/include/asm/uaccess.h | 1 -
arch/powerpc/include/asm/uaccess.h | 2 -
arch/riscv/include/asm/uaccess.h | 2 -
arch/s390/include/asm/uaccess.h | 2 -
arch/sparc/include/asm/uaccess_64.h | 2 -
arch/um/include/asm/uaccess.h | 2 -
arch/x86/include/asm/uaccess.h | 2 -
include/asm-generic/uaccess.h | 2 -
include/linux/uaccess.h | 19 +++++
mm/maccess.c | 108 ----------------------------
14 files changed, 19 insertions(+), 131 deletions(-)

diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 32dbfd81f42a..d20d78c34b94 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -476,8 +476,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); \
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 3a5ff5e20586..2e20879fe3cf 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -26,8 +26,6 @@
#include <asm/memory.h>
#include <asm/extable.h>

-#define HAVE_GET_KERNEL_NOFAULT
-
/*
* Test whether a block of memory is a valid user space address.
* Returns 1 if the range is valid, 0 otherwise.
diff --git a/arch/m68k/include/asm/uaccess.h b/arch/m68k/include/asm/uaccess.h
index ba670523885c..79617c0b2f91 100644
--- a/arch/m68k/include/asm/uaccess.h
+++ b/arch/m68k/include/asm/uaccess.h
@@ -390,8 +390,6 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
#define INLINE_COPY_FROM_USER
#define INLINE_COPY_TO_USER

-#define HAVE_GET_KERNEL_NOFAULT
-
#define __get_kernel_nofault(dst, src, type, err_label) \
do { \
type *__gk_dst = (type *)(dst); \
diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
index f8f74f9f5883..db9a8e002b62 100644
--- a/arch/mips/include/asm/uaccess.h
+++ b/arch/mips/include/asm/uaccess.h
@@ -296,8 +296,6 @@ struct __large_struct { unsigned long buf[100]; };
(val) = __gu_tmp.t; \
}

-#define HAVE_GET_KERNEL_NOFAULT
-
#define __get_kernel_nofault(dst, src, type, err_label) \
do { \
int __gu_err; \
diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h
index ebf8a845b017..0925bbd6db67 100644
--- a/arch/parisc/include/asm/uaccess.h
+++ b/arch/parisc/include/asm/uaccess.h
@@ -95,7 +95,6 @@ struct exception_table_entry {
(val) = (__force __typeof__(*(ptr))) __gu_val; \
}

-#define HAVE_GET_KERNEL_NOFAULT
#define __get_kernel_nofault(dst, src, type, err_label) \
{ \
type __z; \
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index 63316100080c..a0032c2e7550 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -467,8 +467,6 @@ do { \
unsafe_put_user(*(u8*)(_src + _i), (u8 __user *)(_dst + _i), e); \
} while (0)

-#define HAVE_GET_KERNEL_NOFAULT
-
#define __get_kernel_nofault(dst, src, type, err_label) \
__get_user_size_goto(*((type *)(dst)), \
(__force type __user *)(src), sizeof(type), err_label)
diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h
index c701a5e57a2b..4407b9e48d2c 100644
--- a/arch/riscv/include/asm/uaccess.h
+++ b/arch/riscv/include/asm/uaccess.h
@@ -346,8 +346,6 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n)
__clear_user(to, n) : n;
}

-#define HAVE_GET_KERNEL_NOFAULT
-
#define __get_kernel_nofault(dst, src, type, err_label) \
do { \
long __kr_err; \
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index d74e26b48604..29332edf46f0 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -282,8 +282,6 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo
int copy_to_user_real(void __user *dest, void *src, unsigned long count);
void *s390_kernel_write(void *dst, const void *src, size_t size);

-#define HAVE_GET_KERNEL_NOFAULT
-
int __noreturn __put_kernel_bad(void);

#define __put_kernel_asm(val, to, insn) \
diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h
index b283798315b1..5c12fb46bc61 100644
--- a/arch/sparc/include/asm/uaccess_64.h
+++ b/arch/sparc/include/asm/uaccess_64.h
@@ -210,8 +210,6 @@ __asm__ __volatile__( \
: "=r" (ret), "=r" (x) : "r" (__m(addr)), \
"i" (-EFAULT))

-#define HAVE_GET_KERNEL_NOFAULT
-
#define __get_user_nocheck(data, addr, size, type) ({ \
register int __gu_ret; \
register unsigned long __gu_val; \
diff --git a/arch/um/include/asm/uaccess.h b/arch/um/include/asm/uaccess.h
index 17d18cfd82a5..1ecfc96bcc50 100644
--- a/arch/um/include/asm/uaccess.h
+++ b/arch/um/include/asm/uaccess.h
@@ -44,8 +44,6 @@ static inline int __access_ok(unsigned long addr, unsigned long size)
}

/* no pagefaults for kernel addresses in um */
-#define HAVE_GET_KERNEL_NOFAULT 1
-
#define __get_kernel_nofault(dst, src, type, err_label) \
do { \
*((type *)dst) = get_unaligned((type *)(src)); \
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index a59ba2578e64..201efcec66b7 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -507,8 +507,6 @@ do { \
unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u8, label); \
} while (0)

-#define HAVE_GET_KERNEL_NOFAULT
-
#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
#define __get_kernel_nofault(dst, src, type, err_label) \
__get_user_size(*((type *)(dst)), (__force type __user *)(src), \
diff --git a/include/asm-generic/uaccess.h b/include/asm-generic/uaccess.h
index 10ffa8b5c117..0870fa11a7c5 100644
--- a/include/asm-generic/uaccess.h
+++ b/include/asm-generic/uaccess.h
@@ -77,8 +77,6 @@ do { \
goto err_label; \
} while (0)

-#define HAVE_GET_KERNEL_NOFAULT 1
-
static inline __must_check unsigned long
raw_copy_from_user(void *to, const void __user * from, unsigned long n)
{
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index ac0394087f7d..67e9bc94dc40 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -368,6 +368,25 @@ long strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
long count);
long strnlen_user_nofault(const void __user *unsafe_addr, long count);

+#ifndef __get_kernel_nofault
+#define __get_kernel_nofault(dst, src, type, label) \
+do { \
+ type __user *p = (type __force __user *)(src); \
+ type data; \
+ if (__get_user(data, p)) \
+ goto label; \
+ *(type *)dst = data; \
+} while (0)
+
+#define __put_kernel_nofault(dst, src, type, label) \
+do { \
+ type __user *p = (type __force __user *)(dst); \
+ type data = *(type *)src; \
+ if (__put_user(data, p)) \
+ goto label; \
+} while (0)
+#endif
+
/**
* get_kernel_nofault(): safely attempt to read from a location
* @val: read into this variable
diff --git a/mm/maccess.c b/mm/maccess.c
index d3f1a1f0b1c1..cbd1b3959af2 100644
--- a/mm/maccess.c
+++ b/mm/maccess.c
@@ -12,8 +12,6 @@ bool __weak copy_from_kernel_nofault_allowed(const void *unsafe_src,
return true;
}

-#ifdef HAVE_GET_KERNEL_NOFAULT
-
#define copy_from_kernel_nofault_loop(dst, src, len, type, err_label) \
while (len >= sizeof(type)) { \
__get_kernel_nofault(dst, src, type, err_label); \
@@ -102,112 +100,6 @@ long strncpy_from_kernel_nofault(char *dst, const void *unsafe_addr, long count)
dst[-1] = '\0';
return -EFAULT;
}
-#else /* HAVE_GET_KERNEL_NOFAULT */
-/**
- * copy_from_kernel_nofault(): safely attempt to read from kernel-space
- * @dst: pointer to the buffer that shall take the data
- * @src: address to read from
- * @size: size of the data chunk
- *
- * Safely read from kernel address @src to the buffer at @dst. If a kernel
- * fault happens, handle that and return -EFAULT. If @src is not a valid kernel
- * address, return -ERANGE.
- *
- * We ensure that the copy_from_user is executed in atomic context so that
- * do_page_fault() doesn't attempt to take mmap_lock. This makes
- * copy_from_kernel_nofault() suitable for use within regions where the caller
- * already holds mmap_lock, or other locks which nest inside mmap_lock.
- */
-long copy_from_kernel_nofault(void *dst, const void *src, size_t size)
-{
- long ret;
- mm_segment_t old_fs = get_fs();
-
- if (!copy_from_kernel_nofault_allowed(src, size))
- return -ERANGE;
-
- set_fs(KERNEL_DS);
- pagefault_disable();
- ret = __copy_from_user_inatomic(dst, (__force const void __user *)src,
- size);
- pagefault_enable();
- set_fs(old_fs);
-
- if (ret)
- return -EFAULT;
- return 0;
-}
-EXPORT_SYMBOL_GPL(copy_from_kernel_nofault);
-
-/**
- * copy_to_kernel_nofault(): safely attempt to write to a location
- * @dst: address to write to
- * @src: pointer to the data that shall be written
- * @size: size of the data chunk
- *
- * Safely write to address @dst from the buffer at @src. If a kernel fault
- * happens, handle that and return -EFAULT.
- */
-long copy_to_kernel_nofault(void *dst, const void *src, size_t size)
-{
- long ret;
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- pagefault_disable();
- ret = __copy_to_user_inatomic((__force void __user *)dst, src, size);
- pagefault_enable();
- set_fs(old_fs);
-
- if (ret)
- return -EFAULT;
- return 0;
-}
-
-/**
- * strncpy_from_kernel_nofault: - Copy a NUL terminated string from unsafe
- * address.
- * @dst: Destination address, in kernel space. This buffer must be at
- * least @count bytes long.
- * @unsafe_addr: Unsafe address.
- * @count: Maximum number of bytes to copy, including the trailing NUL.
- *
- * Copies a NUL-terminated string from unsafe address to kernel buffer.
- *
- * On success, returns the length of the string INCLUDING the trailing NUL.
- *
- * If access fails, returns -EFAULT (some data may have been copied and the
- * trailing NUL added). If @unsafe_addr is not a valid kernel address, return
- * -ERANGE.
- *
- * If @count is smaller than the length of the string, copies @count-1 bytes,
- * sets the last byte of @dst buffer to NUL and returns @count.
- */
-long strncpy_from_kernel_nofault(char *dst, const void *unsafe_addr, long count)
-{
- mm_segment_t old_fs = get_fs();
- const void *src = unsafe_addr;
- long ret;
-
- if (unlikely(count <= 0))
- return 0;
- if (!copy_from_kernel_nofault_allowed(unsafe_addr, count))
- return -ERANGE;
-
- set_fs(KERNEL_DS);
- pagefault_disable();
-
- do {
- ret = __get_user(*dst++, (const char __user __force *)src++);
- } while (dst[-1] && ret == 0 && src - unsafe_addr < count);
-
- dst[-1] = '\0';
- pagefault_enable();
- set_fs(old_fs);
-
- return ret ? -EFAULT : src - unsafe_addr;
-}
-#endif /* HAVE_GET_KERNEL_NOFAULT */

/**
* copy_from_user_nofault(): safely attempt to read from a user-space location
--
2.29.2

2022-02-16 14:20:54

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v2 11/18] arm64: simplify access_ok()

From: Arnd Bergmann <[email protected]>

arm64 has an inline asm implementation of access_ok() that is derived from
the 32-bit arm version and optimized for the case that both the limit and
the size are variable. With set_fs() gone, the limit is always constant,
and the size usually is as well, so just using the default implementation
reduces the check into a comparison against a constant that can be
scheduled by the compiler.

On a defconfig build, this saves over 28KB of .text.

Acked-by: Robin Murphy <[email protected]>
Acked-by: Mark Rutland <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
arch/arm64/include/asm/uaccess.h | 34 ++++++++++----------------------
1 file changed, 10 insertions(+), 24 deletions(-)

diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 2e20879fe3cf..199c553b740a 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -26,6 +26,14 @@
#include <asm/memory.h>
#include <asm/extable.h>

+static inline int __access_ok(const void __user *ptr, unsigned long size)
+{
+ unsigned long limit = TASK_SIZE_MAX;
+ unsigned long addr = (unsigned long)ptr;
+
+ return (size <= limit) && (addr <= (limit - size));
+}
+
/*
* Test whether a block of memory is a valid user space address.
* Returns 1 if the range is valid, 0 otherwise.
@@ -33,10 +41,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
@@ -46,29 +52,9 @@ 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(addr, size) __range_ok(addr, size)
-
/*
* User access enabling/disabling.
*/
--
2.29.2

2022-02-16 16:23:57

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v2 02/18] uaccess: fix nios2 and microblaze get_user_8()

From: Arnd Bergmann <[email protected]>

These two architectures implement 8-byte get_user() through
a memcpy() into a four-byte variable, which won't fit.

Use a temporary 64-bit variable instead here, and use a double
cast the way that risc-v and openrisc do to avoid compile-time
warnings.

Fixes: 6a090e97972d ("arch/microblaze: support get_user() of size 8 bytes")
Fixes: 5ccc6af5e88e ("nios2: Memory management")
Signed-off-by: Arnd Bergmann <[email protected]>
---
arch/microblaze/include/asm/uaccess.h | 18 +++++++++---------
arch/nios2/include/asm/uaccess.h | 26 ++++++++++++++++----------
2 files changed, 25 insertions(+), 19 deletions(-)

diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h
index 5b6e0e7788f4..3fe96979d2c6 100644
--- a/arch/microblaze/include/asm/uaccess.h
+++ b/arch/microblaze/include/asm/uaccess.h
@@ -130,27 +130,27 @@ extern long __user_bad(void);

#define __get_user(x, ptr) \
({ \
- unsigned long __gu_val = 0; \
long __gu_err; \
switch (sizeof(*(ptr))) { \
case 1: \
- __get_user_asm("lbu", (ptr), __gu_val, __gu_err); \
+ __get_user_asm("lbu", (ptr), x, __gu_err); \
break; \
case 2: \
- __get_user_asm("lhu", (ptr), __gu_val, __gu_err); \
+ __get_user_asm("lhu", (ptr), x, __gu_err); \
break; \
case 4: \
- __get_user_asm("lw", (ptr), __gu_val, __gu_err); \
+ __get_user_asm("lw", (ptr), x, __gu_err); \
break; \
- case 8: \
- __gu_err = __copy_from_user(&__gu_val, ptr, 8); \
- if (__gu_err) \
- __gu_err = -EFAULT; \
+ case 8: { \
+ __u64 __x = 0; \
+ __gu_err = raw_copy_from_user(&__x, ptr, 8) ? \
+ -EFAULT : 0; \
+ (x) = (typeof(x))(typeof((x) - (x)))__x; \
break; \
+ } \
default: \
/* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\
} \
- x = (__force __typeof__(*(ptr))) __gu_val; \
__gu_err; \
})

diff --git a/arch/nios2/include/asm/uaccess.h b/arch/nios2/include/asm/uaccess.h
index ba9340e96fd4..ca9285a915ef 100644
--- a/arch/nios2/include/asm/uaccess.h
+++ b/arch/nios2/include/asm/uaccess.h
@@ -88,6 +88,7 @@ extern __must_check long strnlen_user(const char __user *s, long n);
/* Optimized macros */
#define __get_user_asm(val, insn, addr, err) \
{ \
+ unsigned long __gu_val; \
__asm__ __volatile__( \
" movi %0, %3\n" \
"1: " insn " %1, 0(%2)\n" \
@@ -96,14 +97,20 @@ extern __must_check long strnlen_user(const char __user *s, long n);
" .section __ex_table,\"a\"\n" \
" .word 1b, 2b\n" \
" .previous" \
- : "=&r" (err), "=r" (val) \
+ : "=&r" (err), "=r" (__gu_val) \
: "r" (addr), "i" (-EFAULT)); \
+ val = (__force __typeof__(*(addr)))__gu_val; \
}

-#define __get_user_unknown(val, size, ptr, err) do { \
+extern void __get_user_unknown(void);
+
+#define __get_user_8(val, ptr, err) do { \
+ u64 __val = 0; \
err = 0; \
- if (__copy_from_user(&(val), ptr, size)) { \
+ if (raw_copy_from_user(&(__val), ptr, sizeof(val))) { \
err = -EFAULT; \
+ } else { \
+ val = (typeof(val))(typeof((val) - (val)))__val; \
} \
} while (0)

@@ -119,8 +126,11 @@ do { \
case 4: \
__get_user_asm(val, "ldw", ptr, err); \
break; \
+ case 8: \
+ __get_user_8(val, ptr, err); \
+ break; \
default: \
- __get_user_unknown(val, size, ptr, err); \
+ __get_user_unknown(); \
break; \
} \
} while (0)
@@ -129,9 +139,7 @@ do { \
({ \
long __gu_err = -EFAULT; \
const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
- unsigned long __gu_val = 0; \
- __get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err);\
- (x) = (__force __typeof__(x))__gu_val; \
+ __get_user_common(x, sizeof(*(ptr)), __gu_ptr, __gu_err); \
__gu_err; \
})

@@ -139,11 +147,9 @@ do { \
({ \
long __gu_err = -EFAULT; \
const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
- unsigned long __gu_val = 0; \
if (access_ok( __gu_ptr, sizeof(*__gu_ptr))) \
- __get_user_common(__gu_val, sizeof(*__gu_ptr), \
+ __get_user_common(x, sizeof(*__gu_ptr), \
__gu_ptr, __gu_err); \
- (x) = (__force __typeof__(x))__gu_val; \
__gu_err; \
})

--
2.29.2

2022-02-16 17:43:26

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v2 12/18] uaccess: fix type mismatch warnings from access_ok()

From: Arnd Bergmann <[email protected]>

On some architectures, access_ok() does not do any argument type
checking, so replacing the definition with a generic one causes
a few warnings for harmless issues that were never caught before.

Fix the ones that I found either through my own test builds or
that were reported by the 0-day bot.

Reported-by: kernel test robot <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
arch/arc/kernel/process.c | 2 +-
arch/arm/kernel/swp_emulate.c | 2 +-
arch/arm/kernel/traps.c | 2 +-
arch/csky/kernel/signal.c | 2 +-
arch/mips/sibyte/common/sb_tbprof.c | 6 +++---
arch/nios2/kernel/signal.c | 20 +++++++++++---------
arch/powerpc/lib/sstep.c | 4 ++--
arch/riscv/kernel/perf_callchain.c | 2 +-
arch/sparc/kernel/signal_32.c | 2 +-
lib/test_lockup.c | 4 ++--
10 files changed, 24 insertions(+), 22 deletions(-)

diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c
index 8e90052f6f05..5f7f5aab361f 100644
--- a/arch/arc/kernel/process.c
+++ b/arch/arc/kernel/process.c
@@ -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;
diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c
index 6166ba38bf99..b74bfcf94fb1 100644
--- a/arch/arm/kernel/swp_emulate.c
+++ b/arch/arm/kernel/swp_emulate.c
@@ -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;
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index da04ed85855a..26c8c8276297 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -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);
diff --git a/arch/csky/kernel/signal.c b/arch/csky/kernel/signal.c
index c7b763d2f526..8867ddf3e6c7 100644
--- a/arch/csky/kernel/signal.c
+++ b/arch/csky/kernel/signal.c
@@ -136,7 +136,7 @@ static inline void __user *get_sigframe(struct ksignal *ksig,
static int
setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
{
- struct rt_sigframe *frame;
+ struct rt_sigframe __user *frame;
int err = 0;

frame = get_sigframe(ksig, regs, sizeof(*frame));
diff --git a/arch/mips/sibyte/common/sb_tbprof.c b/arch/mips/sibyte/common/sb_tbprof.c
index f80d7a710333..01d00b87d0f5 100644
--- a/arch/mips/sibyte/common/sb_tbprof.c
+++ b/arch/mips/sibyte/common/sb_tbprof.c
@@ -437,13 +437,13 @@ static int sbprof_tb_release(struct inode *inode, struct file *filp)
return 0;
}

-static ssize_t sbprof_tb_read(struct file *filp, char *buf,
+static ssize_t sbprof_tb_read(struct file *filp, char __user *buf,
size_t size, loff_t *offp)
{
int cur_sample, sample_off, cur_count, sample_left;
char *src;
int count = 0;
- char *dest = buf;
+ char __user *dest = buf;
long cur_off = *offp;

if (!access_ok(buf, size))
@@ -512,7 +512,7 @@ static long sbprof_tb_ioctl(struct file *filp,
if (err)
break;

- err = put_user(TB_FULL, (int *) arg);
+ err = put_user(TB_FULL, (int __user *) arg);
break;
}

diff --git a/arch/nios2/kernel/signal.c b/arch/nios2/kernel/signal.c
index 2009ae2d3c3b..386e46443b60 100644
--- a/arch/nios2/kernel/signal.c
+++ b/arch/nios2/kernel/signal.c
@@ -36,10 +36,10 @@ struct rt_sigframe {

static inline int rt_restore_ucontext(struct pt_regs *regs,
struct switch_stack *sw,
- struct ucontext *uc, int *pr2)
+ struct ucontext __user *uc, int *pr2)
{
int temp;
- unsigned long *gregs = uc->uc_mcontext.gregs;
+ unsigned long __user *gregs = uc->uc_mcontext.gregs;
int err;

/* Always make any pending restarted system calls return -EINTR */
@@ -102,10 +102,11 @@ asmlinkage int do_rt_sigreturn(struct switch_stack *sw)
{
struct pt_regs *regs = (struct pt_regs *)(sw + 1);
/* Verify, can we follow the stack back */
- struct rt_sigframe *frame = (struct rt_sigframe *) regs->sp;
+ struct rt_sigframe __user *frame;
sigset_t set;
int rval;

+ frame = (struct rt_sigframe __user *) regs->sp;
if (!access_ok(frame, sizeof(*frame)))
goto badframe;

@@ -124,10 +125,10 @@ asmlinkage int do_rt_sigreturn(struct switch_stack *sw)
return 0;
}

-static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
+static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs)
{
struct switch_stack *sw = (struct switch_stack *)regs - 1;
- unsigned long *gregs = uc->uc_mcontext.gregs;
+ unsigned long __user *gregs = uc->uc_mcontext.gregs;
int err = 0;

err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
@@ -162,8 +163,9 @@ static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
return err;
}

-static inline void *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
- size_t frame_size)
+static inline void __user *get_sigframe(struct ksignal *ksig,
+ struct pt_regs *regs,
+ size_t frame_size)
{
unsigned long usp;

@@ -174,13 +176,13 @@ static inline void *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
usp = sigsp(usp, ksig);

/* Verify, is it 32 or 64 bit aligned */
- return (void *)((usp - frame_size) & -8UL);
+ return (void __user *)((usp - frame_size) & -8UL);
}

static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs)
{
- struct rt_sigframe *frame;
+ struct rt_sigframe __user *frame;
int err = 0;

frame = get_sigframe(ksig, regs, sizeof(*frame));
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index a94b0cd0bdc5..022d23ae300b 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -112,9 +112,9 @@ static nokprobe_inline long address_ok(struct pt_regs *regs,
{
if (!user_mode(regs))
return 1;
- if (__access_ok(ea, nb))
+ if (access_ok((void __user *)ea, nb))
return 1;
- if (__access_ok(ea, 1))
+ if (access_ok((void __user *)ea, 1))
/* Access overlaps the end of the user region */
regs->dar = TASK_SIZE_MAX - 1;
else
diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c
index 1fc075b8f764..f0c7bb98119a 100644
--- a/arch/riscv/kernel/perf_callchain.c
+++ b/arch/riscv/kernel/perf_callchain.c
@@ -15,7 +15,7 @@ static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry,
{
struct stackframe buftail;
unsigned long ra = 0;
- unsigned long *user_frame_tail =
+ unsigned long __user *user_frame_tail =
(unsigned long *)(fp - sizeof(struct stackframe));

/* Check accessibility of one struct frame_tail beyond */
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index ffab16369bea..74f80443b195 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -65,7 +65,7 @@ struct rt_signal_frame {
*/
static inline bool invalid_frame_pointer(void __user *fp, int fplen)
{
- if ((((unsigned long) fp) & 15) || !__access_ok((unsigned long)fp, fplen))
+ if ((((unsigned long) fp) & 15) || !access_ok(fp, fplen))
return true;

return false;
diff --git a/lib/test_lockup.c b/lib/test_lockup.c
index 906b598740a7..6a0f329a794a 100644
--- a/lib/test_lockup.c
+++ b/lib/test_lockup.c
@@ -417,8 +417,8 @@ static bool test_kernel_ptr(unsigned long addr, int size)
return false;

/* should be at least readable kernel address */
- if (access_ok(ptr, 1) ||
- access_ok(ptr + size - 1, 1) ||
+ if (access_ok((void __user *)ptr, 1) ||
+ access_ok((void __user *)ptr + size - 1, 1) ||
get_kernel_nofault(buf, ptr) ||
get_kernel_nofault(buf, ptr + size - 1)) {
pr_err("invalid kernel ptr: %#lx\n", addr);
--
2.29.2

2022-02-17 08:28:50

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v2 18/18] uaccess: drop maining CONFIG_SET_FS users

On Wed, Feb 16, 2022 at 7:44 PM Sam Ravnborg <[email protected]> wrote:
>
> Hi Arnd,
>
> Fix spelling in $subject...

done

> sparc/Kconfig b/arch/sparc/Kconfig
> > index 9f6f9bce5292..9276f321b3e3 100644
> > --- a/arch/sparc/Kconfig
> > +++ b/arch/sparc/Kconfig
> > @@ -46,7 +46,6 @@ config SPARC
> > select LOCKDEP_SMALL if LOCKDEP
> > select NEED_DMA_MAP_STATE
> > select NEED_SG_DMA_LENGTH
> > - select SET_FS
> > select TRACE_IRQFLAGS_SUPPORT
> >
> > config SPARC32
> > @@ -101,6 +100,7 @@ config SPARC64
> > select HAVE_SETUP_PER_CPU_AREA
> > select NEED_PER_CPU_EMBED_FIRST_CHUNK
> > select NEED_PER_CPU_PAGE_FIRST_CHUNK
> > + select SET_FS
> This looks wrong - looks like some merge went wrong here.

Fixed now.

>
> Other than the above the sparc32 changes looks fine, and with the Kconf
> stuff fixed:
> Acked-by: Sam Ravnborg <[email protected]> # for sparc32 changes

Thanks!

Arnd

2022-02-17 08:50:47

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH v2 18/18] uaccess: drop maining CONFIG_SET_FS users

Hi Arnd,

Fix spelling in $subject...

sparc/Kconfig b/arch/sparc/Kconfig
> index 9f6f9bce5292..9276f321b3e3 100644
> --- a/arch/sparc/Kconfig
> +++ b/arch/sparc/Kconfig
> @@ -46,7 +46,6 @@ config SPARC
> select LOCKDEP_SMALL if LOCKDEP
> select NEED_DMA_MAP_STATE
> select NEED_SG_DMA_LENGTH
> - select SET_FS
> select TRACE_IRQFLAGS_SUPPORT
>
> config SPARC32
> @@ -101,6 +100,7 @@ config SPARC64
> select HAVE_SETUP_PER_CPU_AREA
> select NEED_PER_CPU_EMBED_FIRST_CHUNK
> select NEED_PER_CPU_PAGE_FIRST_CHUNK
> + select SET_FS
This looks wrong - looks like some merge went wrong here.

>
> config ARCH_PROC_KCORE_TEXT
> def_bool y
> diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h
> index 647bf0ac7beb..b26c35336b51 100644
> --- a/arch/sparc/include/asm/processor_32.h
> +++ b/arch/sparc/include/asm/processor_32.h
> @@ -32,10 +32,6 @@ struct fpq {
> };
> #endif
>
> -typedef struct {
> - int seg;
> -} mm_segment_t;
> -
> /* The Sparc processor specific thread struct. */
> struct thread_struct {
> struct pt_regs *kregs;
> @@ -50,11 +46,9 @@ struct thread_struct {
> unsigned long fsr;
> unsigned long fpqdepth;
> struct fpq fpqueue[16];
> - mm_segment_t current_ds;
> };
>
> #define INIT_THREAD { \
> - .current_ds = KERNEL_DS, \
> .kregs = (struct pt_regs *)(init_stack+THREAD_SIZE)-1 \
> }
>
> diff --git a/arch/sparc/include/asm/uaccess_32.h b/arch/sparc/include/asm/uaccess_32.h
> index 367747116260..9fd6c53644b6 100644
> --- a/arch/sparc/include/asm/uaccess_32.h
> +++ b/arch/sparc/include/asm/uaccess_32.h
> @@ -12,19 +12,6 @@
> #include <linux/string.h>
>
> #include <asm/processor.h>
> -
> -/* Sparc is not segmented, however we need to be able to fool access_ok()
> - * when doing system calls from kernel mode legitimately.
> - *
> - * "For historical reasons, these macros are grossly misnamed." -Linus
> - */
> -
> -#define KERNEL_DS ((mm_segment_t) { 0 })
> -#define USER_DS ((mm_segment_t) { -1 })
> -
> -#define get_fs() (current->thread.current_ds)
> -#define set_fs(val) ((current->thread.current_ds) = (val))
> -
> #include <asm-generic/access_ok.h>
>
> /* Uh, these should become the main single-value transfer routines..
> diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
> index 2dc0bf9fe62e..88c0c14aaff0 100644
> --- a/arch/sparc/kernel/process_32.c
> +++ b/arch/sparc/kernel/process_32.c
> @@ -300,7 +300,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
> extern int nwindows;
> unsigned long psr;
> memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ);
> - p->thread.current_ds = KERNEL_DS;
> ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8);
> childregs->u_regs[UREG_G1] = sp; /* function */
> childregs->u_regs[UREG_G2] = arg;
> @@ -311,7 +310,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
> }
> memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
> childregs->u_regs[UREG_FP] = sp;
> - p->thread.current_ds = USER_DS;
> ti->kpc = (((unsigned long) ret_from_fork) - 0x8);
> ti->kpsr = current->thread.fork_kpsr | PSR_PIL;
> ti->kwim = current->thread.fork_kwim;

Other than the above the sparc32 changes looks fine, and with the Kconf
stuff fixed:
Acked-by: Sam Ravnborg <[email protected]> # for sparc32 changes

2022-02-17 15:24:52

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v2 00/18] clean up asm/uaccess.h, kill set_fs for good

On Thu, Feb 17, 2022 at 8:20 AM Christophe Leroy
<[email protected]> wrote:
> Le 16/02/2022 à 14:13, Arnd Bergmann a écrit :
> >
> > 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.
> >
> > The final series contains extra cleanup changes that touch all
> > architectures. Please review and test these, so we can merge them
> > for v5.18.
>
> As a further cleanup, have you thought about making a generic version of
> clear_user() ? On almost all architectures, clear_user() does an
> access_ok() then calls __clear_user() or similar.

This already exists in include/asm-generic/uaccess.h, but that file is
currently not as easy to use as it should be. I've previously looked into
what it would take to get more architectures to use common code
in that file, but I currently have no plans to work on that.

> Maybe also the same with put_user() and get_user() ? After all it is
> just access_ok() followed by __put_user() or __get_user() ? It seems
> more tricky though, as some architectures seems to have less trivial
> stuff there.

Same here: architectures can already provide a __put_user_fn()
and __get_user_fn(), to get the generic versions of the interface,
but few architectures use that. You can actually get all the interfaces
by just providing raw_copy_from_user() and raw_copy_to_user(),
but the get_user/put_user versions you get from that are fairly
inefficient.

> I also see all architectures have a prototype for strncpy_from_user()
> and strnlen_user(). Could be a common prototype instead when we have
> GENERIC_STRNCPY_FROM_USER / GENERIC_STRNLEN_USER
>
> And we have also
> user_access_begin()/user_read_access_begin()/user_write_access_begin()
> which call access_ok() then do the real work. Could be made generic with
> call to some arch specific __user_access_begin() and friends after the
> access_ok() and eventually the might_fault().

In my opinion, the biggest win would be to move the type-agnostic part of
get_user/put_user into completely generic code, this is what architectures
get wrong the most, see patch 02/18 in this series for instance.

What I'd like to see is that architectures only provide fixed-length
versions of unsafe_get_user()/unsafe_put_user(), with the type-agnostic
versions (get_user(), __get_user(), unsafe_get_user() and their put
versions) all defined once in include/linux/uaccess.h based on those.

I tried implementing this in the past, but unfortunately the resulting
object code from my generalized implementation was worse than
what we have today, so I did not continue that work.

Arnd

2022-02-17 15:58:33

by Christophe Leroy

[permalink] [raw]
Subject: Re: [PATCH v2 00/18] clean up asm/uaccess.h, kill set_fs for good



Le 16/02/2022 à 14:13, Arnd Bergmann a écrit :
> From: Arnd Bergmann <[email protected]>
>
> 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.
>
> The final series contains extra cleanup changes that touch all
> architectures. Please review and test these, so we can merge them
> for v5.18.

As a further cleanup, have you thought about making a generic version of
clear_user() ? On almost all architectures, clear_user() does an
access_ok() then calls __clear_user() or similar.

Maybe also the same with put_user() and get_user() ? After all it is
just access_ok() followed by __put_user() or __get_user() ? It seems
more tricky though, as some architectures seems to have less trivial
stuff there.

I also see all architectures have a prototype for strncpy_from_user()
and strnlen_user(). Could be a common prototype instead when we have
GENERIC_STRNCPY_FROM_USER / GENERIC_STRNLEN_USER

And we have also
user_access_begin()/user_read_access_begin()/user_write_access_begin()
which call access_ok() then do the real work. Could be made generic with
call to some arch specific __user_access_begin() and friends after the
access_ok() and eventually the might_fault().

Christophe

2022-02-17 15:59:41

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v2 00/18] clean up asm/uaccess.h, kill set_fs for good

On Wed, Feb 16, 2022 at 2:13 PM Arnd Bergmann <[email protected]> wrote:
>
> From: Arnd Bergmann <[email protected]>
>
> 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.
>
> The final series contains extra cleanup changes that touch all
> architectures. Please review and test these, so we can merge them
> for v5.18.
>
> The series is available at
> https://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git/log/?h=set_fs-2
> for testing.

I've added the updated contents to my asm-generic tree now to put them
into linux-next.

Arnd

2022-02-17 23:57:49

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH v2 18/18] uaccess: drop maining CONFIG_SET_FS users

Arnd Bergmann <[email protected]> writes:

> From: Arnd Bergmann <[email protected]>
>
> There are no remaining callers of set_fs(), so CONFIG_SET_FS
> can be removed globally, along with the thread_info field and
> any references to it.
>
> This turns access_ok() into a cheaper check against TASK_SIZE_MAX.
>
> With CONFIG_SET_FS gone, so drop all remaining references to
> set_fs()/get_fs(), mm_segment_t and uaccess_kernel().

For the bits I have looked at recently, and think I understand.

Acked-by: "Eric W. Biederman" <[email protected]>

>
> Signed-off-by: Arnd Bergmann <[email protected]>
> ---
> fs/exec.c | 6 --
> kernel/exit.c | 14 -----
> kernel/kthread.c | 5 --
>
> diff --git a/fs/exec.c b/fs/exec.c
> index 79f2c9483302..bc68a0c089ac 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -1303,12 +1303,6 @@ int begin_new_exec(struct linux_binprm * bprm)
> if (retval)
> goto out_unlock;
>
> - /*
> - * Ensure that the uaccess routines can actually operate on userspace
> - * pointers:
> - */
> - force_uaccess_begin();
> -
> if (me->flags & PF_KTHREAD)
> free_kthread_struct(me);
> me->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD |
> diff --git a/kernel/exit.c b/kernel/exit.c
> index b00a25bb4ab9..0884a75bc2f8 100644
> --- a/kernel/exit.c
> +++ b/kernel/exit.c
> @@ -737,20 +737,6 @@ void __noreturn do_exit(long code)
>
> WARN_ON(blk_needs_flush_plug(tsk));
>
> - /*
> - * If do_dead is called because this processes oopsed, it's possible
> - * that get_fs() was left as KERNEL_DS, so reset it to USER_DS before
> - * continuing. Amongst other possible reasons, this is to prevent
> - * mm_release()->clear_child_tid() from writing to a user-controlled
> - * kernel address.
> - *
> - * On uptodate architectures force_uaccess_begin is a noop. On
> - * architectures that still have set_fs/get_fs in addition to handling
> - * oopses handles kernel threads that run as set_fs(KERNEL_DS) by
> - * default.
> - */
> - force_uaccess_begin();
> -
> kcov_task_exit(tsk);
>
> coredump_task_exit(tsk);
> diff --git a/kernel/kthread.c b/kernel/kthread.c
> index 38c6dd822da8..16c2275d4b50 100644
> --- a/kernel/kthread.c
> +++ b/kernel/kthread.c
> @@ -55,7 +55,6 @@ struct kthread {
> int result;
> int (*threadfn)(void *);
> void *data;
> - mm_segment_t oldfs;
> struct completion parked;
> struct completion exited;
> #ifdef CONFIG_BLK_CGROUP
> @@ -1441,8 +1440,6 @@ void kthread_use_mm(struct mm_struct *mm)
> mmdrop(active_mm);
> else
> smp_mb();
> -
> - to_kthread(tsk)->oldfs = force_uaccess_begin();
> }
> EXPORT_SYMBOL_GPL(kthread_use_mm);
>
> @@ -1457,8 +1454,6 @@ void kthread_unuse_mm(struct mm_struct *mm)
> WARN_ON_ONCE(!(tsk->flags & PF_KTHREAD));
> WARN_ON_ONCE(!tsk->mm);
>
> - force_uaccess_end(to_kthread(tsk)->oldfs);
> -
> task_lock(tsk);
> /*
> * When a kthread stops operating on an address space, the loop

2022-02-18 01:51:13

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH v2 00/18] clean up asm/uaccess.h, kill set_fs for good

On Thu, Feb 17, 2022 at 07:20:11AM +0000, Christophe Leroy wrote:

> And we have also
> user_access_begin()/user_read_access_begin()/user_write_access_begin()
> which call access_ok() then do the real work. Could be made generic with
> call to some arch specific __user_access_begin() and friends after the
> access_ok() and eventually the might_fault().

Not a good idea, considering the fact that we do not want to invite
uses of "faster" variants...

2022-02-18 02:21:16

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH v2 00/18] clean up asm/uaccess.h, kill set_fs for good

On Thu, Feb 17, 2022 at 08:49:59AM +0100, Arnd Bergmann wrote:

> Same here: architectures can already provide a __put_user_fn()
> and __get_user_fn(), to get the generic versions of the interface,
> but few architectures use that. You can actually get all the interfaces
> by just providing raw_copy_from_user() and raw_copy_to_user(),
> but the get_user/put_user versions you get from that are fairly
> inefficient.

FWIW, __{get,put}_user_{8,16,32,64} would probably make it easier to
unify. That's where the really variable part tends to be, anyway.
IMO __get_user_fn() had been a mistake.

One thing I somewhat dislike about the series is the boilerplate in
asm/uaccess.h instances - #include <asm-generic/access-ok.h> in
a lot of them might make sense as a transitory state, but getting
stuck with those indefinitely...

BTW, do we need user_addr_max() anymore? The definition in
asm-generic/access-ok.h is the only one, so ifndef around it is pointless.

2022-02-18 06:47:03

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v2 18/18] uaccess: drop maining CONFIG_SET_FS users

s/maining/remaining/ ?

Or maybe rather:

uaccess: remove CONFIG_SET_FS

because it is all gone now.

> With CONFIG_SET_FS gone, so drop all remaining references to
> set_fs()/get_fs(), mm_segment_t and uaccess_kernel().

And this sentence does not parse.

2022-02-18 06:53:08

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v2 10/18] m68k: fix access_ok for coldfire

Looks good,

Reviewed-by: Christoph Hellwig <[email protected]>

2022-02-18 07:00:10

by Christoph Hellwig

[permalink] [raw]

2022-02-18 07:16:27

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v2 14/18] lib/test_lockup: fix kernel pointer check for separate address spaces

On Wed, Feb 16, 2022 at 02:13:28PM +0100, Arnd Bergmann wrote:
> From: Arnd Bergmann <[email protected]>
>
> test_kernel_ptr() uses access_ok() to figure out if a given address
> points to user space instead of kernel space. However on architectures
> that set CONFIG_ALTERNATE_USER_ADDRESS_SPACE, a pointer can be valid
> for both, and the check always fails because access_ok() returns true.
>
> Make the check for user space pointers conditional on the type of
> address space layout.

What is this code even trying to do? It looks extremly broken.

2022-02-18 07:31:05

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v2 18/18] uaccess: drop maining CONFIG_SET_FS users

On Fri, Feb 18, 2022 at 7:37 AM Christoph Hellwig <[email protected]> wrote:
>
> s/maining/remaining/ ?
>
> Or maybe rather:
>
> uaccess: remove CONFIG_SET_FS
>
> because it is all gone now.
>
> > With CONFIG_SET_FS gone, so drop all remaining references to
> > set_fs()/get_fs(), mm_segment_t and uaccess_kernel().
>
> And this sentence does not parse.

Both fixed now, thanks!

Arnd

2022-02-18 07:51:48

by Christoph Hellwig

[permalink] [raw]

2022-02-18 08:33:14

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v2 14/18] lib/test_lockup: fix kernel pointer check for separate address spaces

On Fri, Feb 18, 2022 at 7:35 AM Christoph Hellwig <[email protected]> wrote:
>
> On Wed, Feb 16, 2022 at 02:13:28PM +0100, Arnd Bergmann wrote:
> > From: Arnd Bergmann <[email protected]>
> >
> > test_kernel_ptr() uses access_ok() to figure out if a given address
> > points to user space instead of kernel space. However on architectures
> > that set CONFIG_ALTERNATE_USER_ADDRESS_SPACE, a pointer can be valid
> > for both, and the check always fails because access_ok() returns true.
> >
> > Make the check for user space pointers conditional on the type of
> > address space layout.
>
> What is this code even trying to do? It looks extremly broken.

As I understand it, this is only meant for debugging, and the module contains
intentionally broken lock usage to test whether the watchdog and lockup
detection in the kernel is able to find them.

I did not try that hard to understand how it works though.

Arnd

2022-02-18 09:31:26

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v2 00/18] clean up asm/uaccess.h, kill set_fs for good

n Fri, Feb 18, 2022 at 3:21 AM Al Viro <[email protected]> wrote:
>
> On Thu, Feb 17, 2022 at 08:49:59AM +0100, Arnd Bergmann wrote:
>
> > Same here: architectures can already provide a __put_user_fn()
> > and __get_user_fn(), to get the generic versions of the interface,
> > but few architectures use that. You can actually get all the interfaces
> > by just providing raw_copy_from_user() and raw_copy_to_user(),
> > but the get_user/put_user versions you get from that are fairly
> > inefficient.
>
> FWIW, __{get,put}_user_{8,16,32,64} would probably make it easier to
> unify. That's where the really variable part tends to be, anyway.
> IMO __get_user_fn() had been a mistake.

I've prototyped this now, to see what this might look like, see
https://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git/commit/?h=generic-get_user-prototype

This adds generic inline version of {__get,get,__put,put}_user()
and converts x86 to (optionally) use it. This builds with gcc-5
through gcc-11 on 32-bit and 64-bit x86, using asm-goto with
outputs where possible, and requiring a minimum set of macro
definitions from the architecture. Compiling with clang produces
no warnings but does cause a linker issue at the moment, so
there is probably at least one bug in it.

Aside from compile-testing, I have not tried to verify if this
is correct or efficient, but let me know if you think this is headed
in the right direction.

> One thing I somewhat dislike about the series is the boilerplate in
> asm/uaccess.h instances - #include <asm-generic/access-ok.h> in
> a lot of them might make sense as a transitory state, but getting
> stuck with those indefinitely...

Christoph also complained about it, the problem for now is that
asm-generic/access_ok.h must first see the macro definitions for
architectures that override any of the contents, but access_ok()
itself is used at least in some of the asm/uaccess.h files as well,
so it must be included in the middle of it, until more of the uaccess.h
implementation is moved to linux/uaccess.h in an architecture
independent way.

Would you prefer having an asm/access_ok.h that falls back to
the asm-generic version but can have an architecture specific
override when needed (ia64, arm64, x86, um)?

> BTW, do we need user_addr_max() anymore? The definition in
> asm-generic/access-ok.h is the only one, so ifndef around it is pointless.

Right, the v2 changes got rid of the last override, so it could get
hardcoded to TASK_SIZE_MAX, or we can convert the five
references to just use that instead and remove it altogether:

arch/arm64/kernel/traps.c: if (address >= user_addr_max()) {
\
arch/parisc/kernel/signal.c: if (start >= user_addr_max() - sigframe_size)
arch/parisc/kernel/signal.c: if (A(&usp[0]) >=
user_addr_max() - 5 * sizeof(int))
lib/strncpy_from_user.c: max_addr = user_addr_max();
lib/strnlen_user.c: max_addr = user_addr_max();

user_addr_max() first showed up in architecture-independent code in
c5389831cda3 ("sparc: Fix user_addr_max() definition."), and from that
I think the original intent is no longer useful.

Arnd

2022-02-18 10:16:59

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH v2 08/18] uaccess: add generic __{get,put}_kernel_nofault

On Wed, Feb 16, 2022 at 2:17 PM Arnd Bergmann <[email protected]> wrote:
> From: Arnd Bergmann <[email protected]>
>
> Nine architectures are still missing __{get,put}_kernel_nofault:
> alpha, ia64, microblaze, nds32, nios2, openrisc, sh, sparc32, xtensa.
>
> Add a generic version that lets everything use the normal
> copy_{from,to}_kernel_nofault() code based on these, removing the last
> use of get_fs()/set_fs() from architecture-independent code.
>
> Reviewed-by: Christoph Hellwig <[email protected]>
> Signed-off-by: Arnd Bergmann <[email protected]>

> arch/m68k/include/asm/uaccess.h | 2 -

Acked-by: Geert Uytterhoeven <[email protected]>

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2022-02-18 10:23:10

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v2 10/18] m68k: fix access_ok for coldfire

On Fri, Feb 18, 2022 at 10:00 AM Geert Uytterhoeven
<[email protected]> wrote:
> > /* We let the MMU do all checking */
> > -static inline int access_ok(const void __user *addr,
> > +static inline int access_ok(const void __user *ptr,
> > unsigned long size)
> > {
> > + unsigned long limit = TASK_SIZE;
> > + unsigned long addr = (unsigned long)ptr;
> > +
> > /*
> > * XXX: for !CONFIG_CPU_HAS_ADDRESS_SPACES this really needs to check
> > * for TASK_SIZE!
> > + * Removing this helper is probably sufficient.
> > */
>
> Shouldn't the above comment block be removed completely,
> as this is now implemented below?

Yes, obviously. Fixed now.

> > - return 1;
> > + if (IS_ENABLED(CONFIG_CPU_HAS_ADDRESS_SPACES))
> > + return 1;

I just noticed this should have the same change that I made for the
generic version, changed it now to

+ if (IS_ENABLED(CONFIG_CPU_HAS_ADDRESS_SPACES) ||
+ !IS_ENABLED(CONFIG_MMU))

This is gone again after the cleanup patch, when the generic version
is used instead.

> > + return (size <= limit) && (addr <= (limit - size));
> > }
>
> Any pesky compilers that warn (or worse with -Werror) about
> "condition always true" for TASK_SIZE = 0xFFFFFFFFUL?

No, using a local variable avoids this warning.

Arnd

2022-02-18 11:33:09

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH v2 10/18] m68k: fix access_ok for coldfire

Hi Arnd,

On Wed, Feb 16, 2022 at 2:17 PM Arnd Bergmann <[email protected]> wrote:
> From: Arnd Bergmann <[email protected]>
>
> While most m68k platforms use separate address spaces for user
> and kernel space, at least coldfire does not, and the other
> ones have a TASK_SIZE that is less than the entire 4GB address
> range.
>
> Using the default implementation of __access_ok() stops coldfire
> user space from trivially accessing kernel memory.
>
> Signed-off-by: Arnd Bergmann <[email protected]>

Thanks for your patch!

> --- a/arch/m68k/include/asm/uaccess.h
> +++ b/arch/m68k/include/asm/uaccess.h
> @@ -12,14 +12,21 @@
> #include <asm/extable.h>
>
> /* We let the MMU do all checking */
> -static inline int access_ok(const void __user *addr,
> +static inline int access_ok(const void __user *ptr,
> unsigned long size)
> {
> + unsigned long limit = TASK_SIZE;
> + unsigned long addr = (unsigned long)ptr;
> +
> /*
> * XXX: for !CONFIG_CPU_HAS_ADDRESS_SPACES this really needs to check
> * for TASK_SIZE!
> + * Removing this helper is probably sufficient.
> */

Shouldn't the above comment block be removed completely,
as this is now implemented below?

> - return 1;
> + if (IS_ENABLED(CONFIG_CPU_HAS_ADDRESS_SPACES))
> + return 1;
> +
> + return (size <= limit) && (addr <= (limit - size));
> }

Any pesky compilers that warn (or worse with -Werror) about
"condition always true" for TASK_SIZE = 0xFFFFFFFFUL?

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2022-02-18 11:37:50

by Christophe Leroy

[permalink] [raw]
Subject: Re: [PATCH v2 00/18] clean up asm/uaccess.h, kill set_fs for good



Le 18/02/2022 à 02:50, Al Viro a écrit :
> On Thu, Feb 17, 2022 at 07:20:11AM +0000, Christophe Leroy wrote:
>
>> And we have also
>> user_access_begin()/user_read_access_begin()/user_write_access_begin()
>> which call access_ok() then do the real work. Could be made generic with
>> call to some arch specific __user_access_begin() and friends after the
>> access_ok() and eventually the might_fault().
>
> Not a good idea, considering the fact that we do not want to invite
> uses of "faster" variants...

I'm not sure I understand your concern.

Today in powerpc we have:

static __must_check inline bool
user_read_access_begin(const void __user *ptr, size_t len)
{
if (unlikely(!access_ok(ptr, len)))
return false;

might_fault();

allow_read_from_user(ptr, len);
return true;
}

We could instead have a generic

static __must_check inline bool
user_read_access_begin(const void __user *ptr, size_t len)
{
if (unlikely(!access_ok(ptr, len)))
return false;

might_fault();

return arch_user_read_access_begin(ptr, len);
}

And then a powerpc specific

static __must_check __always_inline bool
arch_user_read_access_begin(const void __user *ptr, size_t len)
{
allow_read_from_user(ptr, len);
return true;
}
#define arch_user_read_access_begin arch_user_read_access_begin

And a generic fallback for arch_user_read_access_begin() that does
nothing at all.

Do you mean that in that case people might be tempted to use
arch_user_read_access_begin() instead of using user_read_access_begin() ?

If that's the case isn't it something we could verify via checkpatch.pl ?

Today it seems to be problematic that functions in asm/uaccess.h use
access_ok(). Such an approach would allow to get rid of access_ok() use
in architecture's uaccess.h

Christophe

2022-02-19 09:20:33

by Sergey Matyukevich

[permalink] [raw]
Subject: Re: [PATCH v2 18/18] uaccess: drop maining CONFIG_SET_FS users

Hi Arnd,

> From: Arnd Bergmann <[email protected]>
>
> There are no remaining callers of set_fs(), so CONFIG_SET_FS
> can be removed globally, along with the thread_info field and
> any references to it.
>
> This turns access_ok() into a cheaper check against TASK_SIZE_MAX.
>
> With CONFIG_SET_FS gone, so drop all remaining references to
> set_fs()/get_fs(), mm_segment_t and uaccess_kernel().
>
> Signed-off-by: Arnd Bergmann <[email protected]>

Tested-by: Sergey Matyukevich <[email protected]> # for arc changes

Regards,
Sergey

2022-02-21 18:36:37

by Thomas Bogendoerfer

[permalink] [raw]
Subject: Re: [PATCH v2 09/18] mips: use simpler access_ok()

On Mon, Feb 21, 2022 at 03:31:23PM +0100, Arnd Bergmann wrote:
> On Mon, Feb 21, 2022 at 2:24 PM Thomas Bogendoerfer
> <[email protected]> wrote:
> > On Wed, Feb 16, 2022 at 02:13:23PM +0100, Arnd Bergmann wrote:
> > >
> > > diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
> > > index db9a8e002b62..d7c89dc3426c 100644
> >
> > this doesn't work. For every access above maximum implemented virtual address
> > space of the CPU an address error will be issued, but not a TLB miss.
> > And address error isn't able to handle this situation.
>
> Ah, so the __ex_table entry only catches TLB misses?

no, but there is no __ex_table handling in address error hanlder (yet).

> Does this mean it also traps for kernel memory accesses, or do those
> work again?

it will trap for every access.


> If the addresses on mips64 are separate like on
> sparc64 or s390, the entire access_ok() step could be replaced
> by a fixup code in the exception handler. I suppose this depends on
> CONFIG_EVA and you still need a limit check at least when EVA is
> disabled.

only EVA has seperate address spaces for kernel/user.

> > Is there a reason to not also #define TASK_SIZE_MAX __UA_LIMIT like
> > for the 32bit case ?
> >
>
> For 32-bit, the __UA_LIMIT is a compile-time constant, so the check
> ends up being trivial. On all other architectures, the same thing can
> be done after the set_fs removal, so I was hoping it would work here
> as well.

ic

> I suspect doing the generic (size <= limit) && (addr <= (limit - size))
> check on mips64 with the runtime limit ends up slightly slower
> than the current code that checks a bit mask instead. If you like,
> I'll update it this way, otherwise I'd need help in form of a patch
> that changes the exception handling so __get_user/__put_user
> also return -EFAULT for an address error.

that's what the patch does. For aligned accesses the patch should
do the right thing, but it breaks unaligned get_user/put_user.
Checking if the trapping vaddr is between end of CPU VM space and
TASK_MAX_SIZE before exception handling should do the trick. I'll
send a patch, if this works.

Thomas.

--
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea. [ RFC1925, 2.3 ]

2022-02-22 02:34:08

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v2 09/18] mips: use simpler access_ok()

On Mon, Feb 21, 2022 at 2:24 PM Thomas Bogendoerfer
<[email protected]> wrote:
> On Wed, Feb 16, 2022 at 02:13:23PM +0100, Arnd Bergmann wrote:
> >
> > diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
> > index db9a8e002b62..d7c89dc3426c 100644
>
> this doesn't work. For every access above maximum implemented virtual address
> space of the CPU an address error will be issued, but not a TLB miss.
> And address error isn't able to handle this situation.

Ah, so the __ex_table entry only catches TLB misses?

Does this mean it also traps for kernel memory accesses, or do those
work again? If the addresses on mips64 are separate like on
sparc64 or s390, the entire access_ok() step could be replaced
by a fixup code in the exception handler. I suppose this depends on
CONFIG_EVA and you still need a limit check at least when EVA is
disabled.

> With this patch
>
> diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
> index df4b708c04a9..3911f1481f3d 100644
> --- a/arch/mips/kernel/unaligned.c
> +++ b/arch/mips/kernel/unaligned.c
> @@ -1480,6 +1480,13 @@ asmlinkage void do_ade(struct pt_regs *regs)
> prev_state = exception_enter();
> perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
> 1, regs, regs->cp0_badvaddr);
> +
> + /* Are we prepared to handle this kernel fault? */
> + if (fixup_exception(regs)) {
> + current->thread.cp0_baduaddr = regs->cp0_badvaddr;
> + return;
> + }
> +
> /*
> * Did we catch a fault trying to load an instruction?
> */
>
> I at least get my simple test cases fixed, but I'm not sure this is
> correct.
>
> Is there a reason to not also #define TASK_SIZE_MAX __UA_LIMIT like
> for the 32bit case ?
>

For 32-bit, the __UA_LIMIT is a compile-time constant, so the check
ends up being trivial. On all other architectures, the same thing can
be done after the set_fs removal, so I was hoping it would work here
as well.

I suspect doing the generic (size <= limit) && (addr <= (limit - size))
check on mips64 with the runtime limit ends up slightly slower
than the current code that checks a bit mask instead. If you like,
I'll update it this way, otherwise I'd need help in form of a patch
that changes the exception handling so __get_user/__put_user
also return -EFAULT for an address error.

Arnd

2022-02-22 05:45:57

by Thomas Bogendoerfer

[permalink] [raw]
Subject: Re: [PATCH v2 09/18] mips: use simpler access_ok()

On Wed, Feb 16, 2022 at 02:13:23PM +0100, Arnd Bergmann wrote:
>
> diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
> index db9a8e002b62..d7c89dc3426c 100644
> --- a/arch/mips/include/asm/uaccess.h
> +++ b/arch/mips/include/asm/uaccess.h
> @@ -19,6 +19,7 @@
> #ifdef CONFIG_32BIT
>
> #define __UA_LIMIT 0x80000000UL
> +#define TASK_SIZE_MAX __UA_LIMIT
>
> #define __UA_ADDR ".word"
> #define __UA_LA "la"
> @@ -33,6 +34,7 @@
> extern u64 __ua_limit;
>
> #define __UA_LIMIT __ua_limit
> +#define TASK_SIZE_MAX XKSSEG

this doesn't work. For every access above maximum implemented virtual address
space of the CPU an address error will be issued, but not a TLB miss.
And address error isn't able to handle this situation.

With this patch

diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index df4b708c04a9..3911f1481f3d 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -1480,6 +1480,13 @@ asmlinkage void do_ade(struct pt_regs *regs)
prev_state = exception_enter();
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
1, regs, regs->cp0_badvaddr);
+
+ /* Are we prepared to handle this kernel fault? */
+ if (fixup_exception(regs)) {
+ current->thread.cp0_baduaddr = regs->cp0_badvaddr;
+ return;
+ }
+
/*
* Did we catch a fault trying to load an instruction?
*/

I at least get my simple test cases fixed, but I'm not sure this is
correct.

Is there a reason to not also #define TASK_SIZE_MAX __UA_LIMIT like
for the 32bit case ?

Thomas.

--
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea. [ RFC1925, 2.3 ]

2022-02-23 02:29:01

by Thomas Bogendoerfer

[permalink] [raw]
Subject: Re: [PATCH v2 09/18] mips: use simpler access_ok()

On Mon, Feb 21, 2022 at 03:31:23PM +0100, Arnd Bergmann wrote:
> I'll update it this way, otherwise I'd need help in form of a patch
> that changes the exception handling so __get_user/__put_user
> also return -EFAULT for an address error.

https://lore.kernel.org/all/[email protected]/

That does the trick.

Thomas.

--
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea. [ RFC1925, 2.3 ]

2022-02-23 11:25:46

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v2 09/18] mips: use simpler access_ok()

On Wed, Feb 23, 2022 at 8:41 AM Thomas Bogendoerfer
<[email protected]> wrote:
>
> On Wed, Feb 16, 2022 at 02:13:23PM +0100, Arnd Bergmann wrote:
> > diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
> > index db9a8e002b62..d7c89dc3426c 100644
> > --- a/arch/mips/include/asm/uaccess.h
> > +++ b/arch/mips/include/asm/uaccess.h
> > @@ -19,6 +19,7 @@
> > #ifdef CONFIG_32BIT
> >
> > #define __UA_LIMIT 0x80000000UL
> > +#define TASK_SIZE_MAX __UA_LIMIT
>
> using KSEG0 instead would IMHO be the better choice. This gives the
> chance to remove __UA_LIMIT completly after cleaning up ptrace.c

Ok, changed now.

Arnd

2022-02-23 13:44:41

by Thomas Bogendoerfer

[permalink] [raw]
Subject: Re: [PATCH v2 09/18] mips: use simpler access_ok()

On Wed, Feb 16, 2022 at 02:13:23PM +0100, Arnd Bergmann wrote:
> diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
> index db9a8e002b62..d7c89dc3426c 100644
> --- a/arch/mips/include/asm/uaccess.h
> +++ b/arch/mips/include/asm/uaccess.h
> @@ -19,6 +19,7 @@
> #ifdef CONFIG_32BIT
>
> #define __UA_LIMIT 0x80000000UL
> +#define TASK_SIZE_MAX __UA_LIMIT

using KSEG0 instead would IMHO be the better choice. This gives the
chance to remove __UA_LIMIT completly after cleaning up ptrace.c

Thomas.

--
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea. [ RFC1925, 2.3 ]

2022-02-24 01:18:33

by Linus Torvalds

[permalink] [raw]
Subject: Re: [PATCH v2 09/18] mips: use simpler access_ok()

On Mon, Feb 21, 2022 at 5:25 AM Thomas Bogendoerfer
<[email protected]> wrote:
>
> With this patch
[ .. snip snip ..]
> I at least get my simple test cases fixed, but I'm not sure this is
> correct.

I think you really want to do that anyway, just to get things like
wild kernel pointers right (ie think get_kernel_nofault() and friends
for ftrace etc).

They shouldn't happen in any normal situation, but those kinds of
unverified pointers is why we _have_ get_kernel_nofault() in the first
place.

On x86-64, the roughly equivalent situation is that addresses that
aren't in canonical format do not take a #PF (page fault), they take a
#GP (general protection) fault.

So I think you want to do that fixup_exception() for any possible addresses.

> Is there a reason to not also #define TASK_SIZE_MAX __UA_LIMIT like
> for the 32bit case ?

I would suggest against using a non-constant TASK_SIZE_MAX. Being
constant is literally one reason why it exists, when TASK_SIZE itself
has often been about other things (ie "32-bit process").

Having to load variables for things like get_user() is annoying, if
you could do it with a simple constant instead (where that "simple"
part is to avoid having to load big values from a constant pool -
often constants like "high bit set" can be loaded and compared against
more efficiently).

Linus

2022-02-24 09:05:30

by Stafford Horne

[permalink] [raw]
Subject: Re: [PATCH v2 18/18] uaccess: drop maining CONFIG_SET_FS users

On Wed, Feb 16, 2022 at 02:13:32PM +0100, Arnd Bergmann wrote:
> From: Arnd Bergmann <[email protected]>
>
> There are no remaining callers of set_fs(), so CONFIG_SET_FS
> can be removed globally, along with the thread_info field and
> any references to it.
>
> This turns access_ok() into a cheaper check against TASK_SIZE_MAX.
>
> With CONFIG_SET_FS gone, so drop all remaining references to
> set_fs()/get_fs(), mm_segment_t and uaccess_kernel().
>
> Signed-off-by: Arnd Bergmann <[email protected]>
> ---
...
> arch/openrisc/Kconfig | 1 -
> arch/openrisc/include/asm/thread_info.h | 7 ---
> arch/openrisc/include/asm/uaccess.h | 23 --------
...
> fs/exec.c | 6 --
> include/asm-generic/access_ok.h | 10 +---
> include/asm-generic/uaccess.h | 25 +-------
> include/linux/syscalls.h | 4 --
> include/linux/uaccess.h | 33 -----------
> include/rdma/ib.h | 2 +-
> kernel/events/callchain.c | 4 --
> kernel/events/core.c | 3 -
> kernel/exit.c | 14 -----
> kernel/kthread.c | 5 --
> kernel/stacktrace.c | 3 -
> kernel/trace/bpf_trace.c | 4 --
> mm/maccess.c | 11 ----
> mm/memory.c | 8 ---
> net/bpfilter/bpfilter_kern.c | 2 +-
> 72 files changed, 10 insertions(+), 522 deletions(-)
> delete mode 100644 arch/arc/include/asm/segment.h
> delete mode 100644 arch/csky/include/asm/segment.h
> delete mode 100644 arch/h8300/include/asm/segment.h
>
> diff --git a/arch/Kconfig b/arch/Kconfig
> index fa5db36bda67..99349547afed 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -24,9 +24,6 @@ config KEXEC_ELF
> config HAVE_IMA_KEXEC
> bool
>
> -config SET_FS
> - bool
> -
> config HOTPLUG_SMT
> bool
>
...
> diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
> index f724b3f1aeed..0d68adf6e02b 100644
> --- a/arch/openrisc/Kconfig
> +++ b/arch/openrisc/Kconfig
> @@ -36,7 +36,6 @@ config OPENRISC
> select ARCH_WANT_FRAME_POINTERS
> select GENERIC_IRQ_MULTI_HANDLER
> select MMU_GATHER_NO_RANGE if MMU
> - select SET_FS
> select TRACE_IRQFLAGS_SUPPORT
>
> config CPU_BIG_ENDIAN
> diff --git a/arch/openrisc/include/asm/thread_info.h b/arch/openrisc/include/asm/thread_info.h
> index 659834ab87fa..4af3049c34c2 100644
> --- a/arch/openrisc/include/asm/thread_info.h
> +++ b/arch/openrisc/include/asm/thread_info.h
> @@ -40,18 +40,12 @@
> */
> #ifndef __ASSEMBLY__
>
> -typedef unsigned long mm_segment_t;
> -
> struct thread_info {
> struct task_struct *task; /* main task structure */
> unsigned long flags; /* low level flags */
> __u32 cpu; /* current CPU */
> __s32 preempt_count; /* 0 => preemptable, <0 => BUG */
>
> - mm_segment_t addr_limit; /* thread address space:
> - 0-0x7FFFFFFF for user-thead
> - 0-0xFFFFFFFF for kernel-thread
> - */
> __u8 supervisor_stack[0];
>
> /* saved context data */
> @@ -71,7 +65,6 @@ struct thread_info {
> .flags = 0, \
> .cpu = 0, \
> .preempt_count = INIT_PREEMPT_COUNT, \
> - .addr_limit = KERNEL_DS, \
> .ksp = 0, \
> }
>
> diff --git a/arch/openrisc/include/asm/uaccess.h b/arch/openrisc/include/asm/uaccess.h
> index 8f049ec99b3e..d6500a374e18 100644
> --- a/arch/openrisc/include/asm/uaccess.h
> +++ b/arch/openrisc/include/asm/uaccess.h
> @@ -22,29 +22,6 @@
> #include <linux/string.h>
> #include <asm/page.h>
> #include <asm/extable.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.
> - *
> - * For historical reasons, these macros are grossly misnamed.
> - */
> -
> -/* addr_limit is the maximum accessible address for the task. we misuse
> - * the KERNEL_DS and USER_DS values to both assign and compare the
> - * addr_limit values through the equally misnamed get/set_fs macros.
> - * (see above)
> - */
> -
> -#define KERNEL_DS (~0UL)
> -
> -#define USER_DS (TASK_SIZE)
> -#define get_fs() (current_thread_info()->addr_limit)
> -#define set_fs(x) (current_thread_info()->addr_limit = (x))
> -
> -#define uaccess_kernel() (get_fs() == KERNEL_DS)
> -
> #include <asm-generic/access_ok.h>
>
> /*
...
> diff --git a/fs/exec.c b/fs/exec.c
> index 79f2c9483302..bc68a0c089ac 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -1303,12 +1303,6 @@ int begin_new_exec(struct linux_binprm * bprm)
> if (retval)
> goto out_unlock;
>
> - /*
> - * Ensure that the uaccess routines can actually operate on userspace
> - * pointers:
> - */
> - force_uaccess_begin();
> -
> if (me->flags & PF_KTHREAD)
> free_kthread_struct(me);
> me->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD |
> diff --git a/include/asm-generic/access_ok.h b/include/asm-generic/access_ok.h
> index 1aad8964d2ed..88a7cb5d9aad 100644
> --- a/include/asm-generic/access_ok.h
> +++ b/include/asm-generic/access_ok.h
> @@ -16,16 +16,8 @@
> #define TASK_SIZE_MAX TASK_SIZE
> #endif
>
> -#ifndef uaccess_kernel
> -#ifdef CONFIG_SET_FS
> -#define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg)
> -#else
> -#define uaccess_kernel() (0)
> -#endif
> -#endif
> -
> #ifndef user_addr_max
> -#define user_addr_max() (uaccess_kernel() ? ~0UL : TASK_SIZE_MAX)
> +#define user_addr_max() TASK_SIZE_MAX
> #endif
>
> #ifndef __access_ok
> diff --git a/include/asm-generic/uaccess.h b/include/asm-generic/uaccess.h
> index ebc685dc8d74..a5be9e61a2a2 100644
> --- a/include/asm-generic/uaccess.h
> +++ b/include/asm-generic/uaccess.h
> @@ -8,6 +8,7 @@
> * address space, e.g. all NOMMU machines.
> */
> #include <linux/string.h>
> +#include <asm-generic/access_ok.h>
>
> #ifdef CONFIG_UACCESS_MEMCPY
> #include <asm/unaligned.h>
> @@ -94,30 +95,6 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
> #define INLINE_COPY_TO_USER
> #endif /* CONFIG_UACCESS_MEMCPY */
>
> -#ifdef CONFIG_SET_FS
> -#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
> -
> -#ifndef KERNEL_DS
> -#define KERNEL_DS MAKE_MM_SEG(~0UL)
> -#endif
> -
> -#ifndef USER_DS
> -#define USER_DS MAKE_MM_SEG(TASK_SIZE - 1)
> -#endif
> -
> -#ifndef get_fs
> -#define get_fs() (current_thread_info()->addr_limit)
> -
> -static inline void set_fs(mm_segment_t fs)
> -{
> - current_thread_info()->addr_limit = fs;
> -}
> -#endif
> -
> -#endif /* CONFIG_SET_FS */
> -
> -#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.
> diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
> index 819c0cb00b6d..a34b0f9a9972 100644
> --- a/include/linux/syscalls.h
> +++ b/include/linux/syscalls.h
> @@ -290,10 +290,6 @@ static inline void addr_limit_user_check(void)
> return;
> #endif
>
> - if (CHECK_DATA_CORRUPTION(uaccess_kernel(),
> - "Invalid address limit on user-mode return"))
> - force_sig(SIGKILL);
> -
> #ifdef TIF_FSCHECK
> clear_thread_flag(TIF_FSCHECK);
> #endif
> diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
> index 2c31667e62e0..2421a41f3a8e 100644
> --- a/include/linux/uaccess.h
> +++ b/include/linux/uaccess.h
> @@ -10,39 +10,6 @@
>
> #include <asm/uaccess.h>
>
> -#ifdef CONFIG_SET_FS
> -/*
> - * Force the uaccess routines to be wired up for actual userspace access,
> - * overriding any possible set_fs(KERNEL_DS) still lingering around. Undone
> - * using force_uaccess_end below.
> - */
> -static inline mm_segment_t force_uaccess_begin(void)
> -{
> - mm_segment_t fs = get_fs();
> -
> - set_fs(USER_DS);
> - return fs;
> -}
> -
> -static inline void force_uaccess_end(mm_segment_t oldfs)
> -{
> - set_fs(oldfs);
> -}
> -#else /* CONFIG_SET_FS */
> -typedef struct {
> - /* empty dummy */
> -} mm_segment_t;
> -
> -static inline mm_segment_t force_uaccess_begin(void)
> -{
> - return (mm_segment_t) { };
> -}
> -
> -static inline void force_uaccess_end(mm_segment_t oldfs)
> -{
> -}
> -#endif /* CONFIG_SET_FS */
> -
> /*
> * Architectures should provide two primitives (raw_copy_{to,from}_user())
> * and get rid of their private instances of copy_{to,from}_user() and
> diff --git a/include/rdma/ib.h b/include/rdma/ib.h
> index 83139b9ce409..f7c185ff7a11 100644
> --- a/include/rdma/ib.h
> +++ b/include/rdma/ib.h
> @@ -75,7 +75,7 @@ struct sockaddr_ib {
> */
> static inline bool ib_safe_file_access(struct file *filp)
> {
> - return filp->f_cred == current_cred() && !uaccess_kernel();
> + return filp->f_cred == current_cred();
> }
>
> #endif /* _RDMA_IB_H */
> diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
> index 58cbe357fb2b..1273be84392c 100644
> --- a/kernel/events/callchain.c
> +++ b/kernel/events/callchain.c
> @@ -209,17 +209,13 @@ get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,
> }
>
> if (regs) {
> - mm_segment_t fs;
> -
> if (crosstask)
> goto exit_put;
>
> if (add_mark)
> perf_callchain_store_context(&ctx, PERF_CONTEXT_USER);
>
> - fs = force_uaccess_begin();
> perf_callchain_user(&ctx, regs);
> - force_uaccess_end(fs);
> }
> }
>
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index 57c7197838db..11ca7303d6df 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -6746,7 +6746,6 @@ perf_output_sample_ustack(struct perf_output_handle *handle, u64 dump_size,
> unsigned long sp;
> unsigned int rem;
> u64 dyn_size;
> - mm_segment_t fs;
>
> /*
> * We dump:
> @@ -6764,9 +6763,7 @@ perf_output_sample_ustack(struct perf_output_handle *handle, u64 dump_size,
>
> /* Data. */
> sp = perf_user_stack_pointer(regs);
> - fs = force_uaccess_begin();
> rem = __output_copy_user(handle, (void *) sp, dump_size);
> - force_uaccess_end(fs);
> dyn_size = dump_size - rem;
>
> perf_output_skip(handle, rem);
> diff --git a/kernel/exit.c b/kernel/exit.c
> index b00a25bb4ab9..0884a75bc2f8 100644
> --- a/kernel/exit.c
> +++ b/kernel/exit.c
> @@ -737,20 +737,6 @@ void __noreturn do_exit(long code)
>
> WARN_ON(blk_needs_flush_plug(tsk));
>
> - /*
> - * If do_dead is called because this processes oopsed, it's possible
> - * that get_fs() was left as KERNEL_DS, so reset it to USER_DS before
> - * continuing. Amongst other possible reasons, this is to prevent
> - * mm_release()->clear_child_tid() from writing to a user-controlled
> - * kernel address.
> - *
> - * On uptodate architectures force_uaccess_begin is a noop. On
> - * architectures that still have set_fs/get_fs in addition to handling
> - * oopses handles kernel threads that run as set_fs(KERNEL_DS) by
> - * default.
> - */
> - force_uaccess_begin();
> -
> kcov_task_exit(tsk);
>
> coredump_task_exit(tsk);
> diff --git a/kernel/kthread.c b/kernel/kthread.c
> index 38c6dd822da8..16c2275d4b50 100644
> --- a/kernel/kthread.c
> +++ b/kernel/kthread.c
> @@ -55,7 +55,6 @@ struct kthread {
> int result;
> int (*threadfn)(void *);
> void *data;
> - mm_segment_t oldfs;
> struct completion parked;
> struct completion exited;
> #ifdef CONFIG_BLK_CGROUP
> @@ -1441,8 +1440,6 @@ void kthread_use_mm(struct mm_struct *mm)
> mmdrop(active_mm);
> else
> smp_mb();
> -
> - to_kthread(tsk)->oldfs = force_uaccess_begin();
> }
> EXPORT_SYMBOL_GPL(kthread_use_mm);
>
> @@ -1457,8 +1454,6 @@ void kthread_unuse_mm(struct mm_struct *mm)
> WARN_ON_ONCE(!(tsk->flags & PF_KTHREAD));
> WARN_ON_ONCE(!tsk->mm);
>
> - force_uaccess_end(to_kthread(tsk)->oldfs);
> -
> task_lock(tsk);
> /*
> * When a kthread stops operating on an address space, the loop
> diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c
> index 9c625257023d..9ed5ce989415 100644
> --- a/kernel/stacktrace.c
> +++ b/kernel/stacktrace.c
> @@ -226,15 +226,12 @@ unsigned int stack_trace_save_user(unsigned long *store, unsigned int size)
> .store = store,
> .size = size,
> };
> - mm_segment_t fs;
>
> /* Trace user stack if not a kernel thread */
> if (current->flags & PF_KTHREAD)
> return 0;
>
> - fs = force_uaccess_begin();
> arch_stack_walk_user(consume_entry, &c, task_pt_regs(current));
> - force_uaccess_end(fs);
>
> return c.len;
> }
> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> index 21aa30644219..8115fff17018 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
> @@ -332,8 +332,6 @@ BPF_CALL_3(bpf_probe_write_user, void __user *, unsafe_ptr, const void *, src,
> if (unlikely(in_interrupt() ||
> current->flags & (PF_KTHREAD | PF_EXITING)))
> return -EPERM;
> - if (unlikely(uaccess_kernel()))
> - return -EPERM;
> if (unlikely(!nmi_uaccess_okay()))
> return -EPERM;
>
> @@ -835,8 +833,6 @@ static int bpf_send_signal_common(u32 sig, enum pid_type type)
> */
> if (unlikely(current->flags & (PF_KTHREAD | PF_EXITING)))
> return -EPERM;
> - if (unlikely(uaccess_kernel()))
> - return -EPERM;
> if (unlikely(!nmi_uaccess_okay()))
> return -EPERM;
>
> diff --git a/mm/maccess.c b/mm/maccess.c
> index cbd1b3959af2..106820b33a2b 100644
> --- a/mm/maccess.c
> +++ b/mm/maccess.c
> @@ -113,14 +113,11 @@ long strncpy_from_kernel_nofault(char *dst, const void *unsafe_addr, long count)
> long copy_from_user_nofault(void *dst, const void __user *src, size_t size)
> {
> long ret = -EFAULT;
> - mm_segment_t old_fs = force_uaccess_begin();
> -
> if (access_ok(src, size)) {
> pagefault_disable();
> ret = __copy_from_user_inatomic(dst, src, size);
> pagefault_enable();
> }
> - force_uaccess_end(old_fs);
>
> if (ret)
> return -EFAULT;
> @@ -140,14 +137,12 @@ EXPORT_SYMBOL_GPL(copy_from_user_nofault);
> long copy_to_user_nofault(void __user *dst, const void *src, size_t size)
> {
> long ret = -EFAULT;
> - mm_segment_t old_fs = force_uaccess_begin();
>
> if (access_ok(dst, size)) {
> pagefault_disable();
> ret = __copy_to_user_inatomic(dst, src, size);
> pagefault_enable();
> }
> - force_uaccess_end(old_fs);
>
> if (ret)
> return -EFAULT;
> @@ -176,17 +171,14 @@ EXPORT_SYMBOL_GPL(copy_to_user_nofault);
> long strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
> long count)
> {
> - mm_segment_t old_fs;
> long ret;
>
> if (unlikely(count <= 0))
> return 0;
>
> - old_fs = force_uaccess_begin();
> pagefault_disable();
> ret = strncpy_from_user(dst, unsafe_addr, count);
> pagefault_enable();
> - force_uaccess_end(old_fs);
>
> if (ret >= count) {
> ret = count;
> @@ -216,14 +208,11 @@ long strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
> */
> long strnlen_user_nofault(const void __user *unsafe_addr, long count)
> {
> - mm_segment_t old_fs;
> int ret;
>
> - old_fs = force_uaccess_begin();
> pagefault_disable();
> ret = strnlen_user(unsafe_addr, count);
> pagefault_enable();
> - force_uaccess_end(old_fs);
>
> return ret;
> }
> diff --git a/mm/memory.c b/mm/memory.c
> index c125c4969913..9a6ebf68a846 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -5256,14 +5256,6 @@ void print_vma_addr(char *prefix, unsigned long ip)
> #if defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_DEBUG_ATOMIC_SLEEP)
> void __might_fault(const char *file, int line)
> {
> - /*
> - * Some code (nfs/sunrpc) uses socket ops on kernel memory while
> - * holding the mmap_lock, this is safe because kernel memory doesn't
> - * get paged out, therefore we'll never actually fault, and the
> - * below annotations will generate false positives.
> - */
> - if (uaccess_kernel())
> - return;
> if (pagefault_disabled())
> return;
> __might_sleep(file, line);
> diff --git a/net/bpfilter/bpfilter_kern.c b/net/bpfilter/bpfilter_kern.c
> index 51a941b56ec3..422ec6e7ccff 100644

Acked-by: Stafford Horne <[email protected]> [openrisc, asm-generic]

Thanks!

2022-02-25 12:41:53

by Dinh Nguyen

[permalink] [raw]
Subject: Re: [PATCH v2 18/18] uaccess: drop maining CONFIG_SET_FS users



On 2/16/22 07:13, Arnd Bergmann wrote:
> From: Arnd Bergmann <[email protected]>
>
> There are no remaining callers of set_fs(), so CONFIG_SET_FS
> can be removed globally, along with the thread_info field and
> any references to it.
>
> This turns access_ok() into a cheaper check against TASK_SIZE_MAX.
>
> With CONFIG_SET_FS gone, so drop all remaining references to
> set_fs()/get_fs(), mm_segment_t and uaccess_kernel().
>
> Signed-off-by: Arnd Bergmann <[email protected]>
> ---
> arch/Kconfig | 3 -
> arch/alpha/Kconfig | 1 -
> arch/alpha/include/asm/processor.h | 4 --
> arch/alpha/include/asm/thread_info.h | 2 -
> arch/alpha/include/asm/uaccess.h | 19 ------
> arch/arc/Kconfig | 1 -
> arch/arc/include/asm/segment.h | 20 -------
> arch/arc/include/asm/thread_info.h | 3 -
> arch/arc/include/asm/uaccess.h | 1 -
> arch/arm/lib/uaccess_with_memcpy.c | 10 ----
> arch/csky/Kconfig | 1 -
> arch/csky/include/asm/processor.h | 2 -
> arch/csky/include/asm/segment.h | 10 ----
> arch/csky/include/asm/thread_info.h | 2 -
> arch/csky/include/asm/uaccess.h | 3 -
> arch/csky/kernel/asm-offsets.c | 1 -
> arch/h8300/Kconfig | 1 -
> arch/h8300/include/asm/processor.h | 1 -
> arch/h8300/include/asm/segment.h | 40 -------------
> arch/h8300/include/asm/thread_info.h | 3 -
> arch/h8300/kernel/entry.S | 1 -
> arch/h8300/kernel/head_ram.S | 1 -
> arch/h8300/mm/init.c | 6 --
> arch/h8300/mm/memory.c | 1 -
> arch/hexagon/Kconfig | 1 -
> arch/hexagon/include/asm/thread_info.h | 6 --
> arch/hexagon/kernel/process.c | 1 -
> arch/microblaze/Kconfig | 1 -
> arch/microblaze/include/asm/thread_info.h | 6 --
> arch/microblaze/include/asm/uaccess.h | 24 --------
> arch/microblaze/kernel/asm-offsets.c | 1 -
> arch/microblaze/kernel/process.c | 1 -
> arch/nds32/Kconfig | 1 -
> arch/nds32/include/asm/thread_info.h | 4 --
> arch/nds32/include/asm/uaccess.h | 15 +----
> arch/nds32/kernel/process.c | 5 +-
> arch/nds32/mm/alignment.c | 3 -
> arch/nios2/Kconfig | 1 -
> arch/nios2/include/asm/thread_info.h | 9 ---
> arch/nios2/include/asm/uaccess.h | 12 ----

For NIOS2:

Acked-by: Dinh Nguyen <[email protected]>

2022-02-25 12:46:10

by Dinh Nguyen

[permalink] [raw]
Subject: Re: [PATCH v2 02/18] uaccess: fix nios2 and microblaze get_user_8()



On 2/16/22 07:13, Arnd Bergmann wrote:
> From: Arnd Bergmann <[email protected]>
>
> These two architectures implement 8-byte get_user() through
> a memcpy() into a four-byte variable, which won't fit.
>
> Use a temporary 64-bit variable instead here, and use a double
> cast the way that risc-v and openrisc do to avoid compile-time
> warnings.
>
> Fixes: 6a090e97972d ("arch/microblaze: support get_user() of size 8 bytes")
> Fixes: 5ccc6af5e88e ("nios2: Memory management")
> Signed-off-by: Arnd Bergmann <[email protected]>
> ---
> arch/microblaze/include/asm/uaccess.h | 18 +++++++++---------
> arch/nios2/include/asm/uaccess.h | 26 ++++++++++++++++----------
> 2 files changed, 25 insertions(+), 19 deletions(-)
>
> diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h
> index 5b6e0e7788f4..3fe96979d2c6 100644
> --- a/arch/microblaze/include/asm/uaccess.h
> +++ b/arch/microblaze/include/asm/uaccess.h
> @@ -130,27 +130,27 @@ extern long __user_bad(void);
>
> #define __get_user(x, ptr) \
> ({ \
> - unsigned long __gu_val = 0; \
> long __gu_err; \
> switch (sizeof(*(ptr))) { \
> case 1: \
> - __get_user_asm("lbu", (ptr), __gu_val, __gu_err); \
> + __get_user_asm("lbu", (ptr), x, __gu_err); \
> break; \
> case 2: \
> - __get_user_asm("lhu", (ptr), __gu_val, __gu_err); \
> + __get_user_asm("lhu", (ptr), x, __gu_err); \
> break; \
> case 4: \
> - __get_user_asm("lw", (ptr), __gu_val, __gu_err); \
> + __get_user_asm("lw", (ptr), x, __gu_err); \
> break; \
> - case 8: \
> - __gu_err = __copy_from_user(&__gu_val, ptr, 8); \
> - if (__gu_err) \
> - __gu_err = -EFAULT; \
> + case 8: { \
> + __u64 __x = 0; \
> + __gu_err = raw_copy_from_user(&__x, ptr, 8) ? \
> + -EFAULT : 0; \
> + (x) = (typeof(x))(typeof((x) - (x)))__x; \
> break; \
> + } \
> default: \
> /* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\
> } \
> - x = (__force __typeof__(*(ptr))) __gu_val; \
> __gu_err; \
> })
>
> diff --git a/arch/nios2/include/asm/uaccess.h b/arch/nios2/include/asm/uaccess.h
> index ba9340e96fd4..ca9285a915ef 100644
> --- a/arch/nios2/include/asm/uaccess.h
> +++ b/arch/nios2/include/asm/uaccess.h
> @@ -88,6 +88,7 @@ extern __must_check long strnlen_user(const char __user *s, long n);
> /* Optimized macros */
> #define __get_user_asm(val, insn, addr, err) \
> { \
> + unsigned long __gu_val; \
> __asm__ __volatile__( \
> " movi %0, %3\n" \
> "1: " insn " %1, 0(%2)\n" \
> @@ -96,14 +97,20 @@ extern __must_check long strnlen_user(const char __user *s, long n);
> " .section __ex_table,\"a\"\n" \
> " .word 1b, 2b\n" \
> " .previous" \
> - : "=&r" (err), "=r" (val) \
> + : "=&r" (err), "=r" (__gu_val) \
> : "r" (addr), "i" (-EFAULT)); \
> + val = (__force __typeof__(*(addr)))__gu_val; \
> }
>
> -#define __get_user_unknown(val, size, ptr, err) do { \
> +extern void __get_user_unknown(void);
> +
> +#define __get_user_8(val, ptr, err) do { \
> + u64 __val = 0; \
> err = 0; \
> - if (__copy_from_user(&(val), ptr, size)) { \
> + if (raw_copy_from_user(&(__val), ptr, sizeof(val))) { \
> err = -EFAULT; \
> + } else { \
> + val = (typeof(val))(typeof((val) - (val)))__val; \
> } \
> } while (0)
>
> @@ -119,8 +126,11 @@ do { \
> case 4: \
> __get_user_asm(val, "ldw", ptr, err); \
> break; \
> + case 8: \
> + __get_user_8(val, ptr, err); \
> + break; \
> default: \
> - __get_user_unknown(val, size, ptr, err); \
> + __get_user_unknown(); \
> break; \
> } \
> } while (0)
> @@ -129,9 +139,7 @@ do { \
> ({ \
> long __gu_err = -EFAULT; \
> const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
> - unsigned long __gu_val = 0; \
> - __get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err);\
> - (x) = (__force __typeof__(x))__gu_val; \
> + __get_user_common(x, sizeof(*(ptr)), __gu_ptr, __gu_err); \
> __gu_err; \
> })
>
> @@ -139,11 +147,9 @@ do { \
> ({ \
> long __gu_err = -EFAULT; \
> const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
> - unsigned long __gu_val = 0; \
> if (access_ok( __gu_ptr, sizeof(*__gu_ptr))) \
> - __get_user_common(__gu_val, sizeof(*__gu_ptr), \
> + __get_user_common(x, sizeof(*__gu_ptr), \
> __gu_ptr, __gu_err); \
> - (x) = (__force __typeof__(x))__gu_val; \
> __gu_err; \
> })
>

Acked-by: Dinh Nguyen <[email protected]>

2022-02-25 13:47:22

by Dinh Nguyen

[permalink] [raw]
Subject: Re: [PATCH v2 12/18] uaccess: fix type mismatch warnings from access_ok()



On 2/16/22 07:13, Arnd Bergmann wrote:
> From: Arnd Bergmann <[email protected]>
>
> On some architectures, access_ok() does not do any argument type
> checking, so replacing the definition with a generic one causes
> a few warnings for harmless issues that were never caught before.
>
> Fix the ones that I found either through my own test builds or
> that were reported by the 0-day bot.
>
> Reported-by: kernel test robot <[email protected]>
> Signed-off-by: Arnd Bergmann <[email protected]>
> ---
> arch/arc/kernel/process.c | 2 +-
> arch/arm/kernel/swp_emulate.c | 2 +-
> arch/arm/kernel/traps.c | 2 +-
> arch/csky/kernel/signal.c | 2 +-
> arch/mips/sibyte/common/sb_tbprof.c | 6 +++---
> arch/nios2/kernel/signal.c | 20 +++++++++++---------

Acked-by: Dinh Nguyen <[email protected]>