diff options
author | Linus Torvalds | 2021-09-01 15:13:02 -0700 |
---|---|---|
committer | Linus Torvalds | 2021-09-01 15:13:02 -0700 |
commit | 4cdc4cc2ad35f92338497d53d3e8b7876cf2a51d (patch) | |
tree | 6d603bb48eeed47a4d37547c3a96c79800a2390f | |
parent | 57c78a234e809e3a0516491e37ae5ccc6eeb21e8 (diff) | |
parent | 8f76f9c46952659dd925c21c3f62a0d05a3f3e71 (diff) |
Merge tag 'asm-generic-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic
Pull asm-generic updates from Arnd Bergmann:
"The main content for 5.15 is a series that cleans up the handling of
strncpy_from_user() and strnlen_user(), removing a lot of slightly
incorrect versions of these in favor of the lib/strn*.c helpers that
implement these correctly and more efficiently.
The only architectures that retain a private version now are mips,
ia64, um and parisc. I had offered to convert those at all, but Thomas
Bogendoerfer wanted to keep the mips version for the moment until he
had a chance to do regression testing.
The branch also contains two patches for bitops and for ffs()"
* tag 'asm-generic-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic:
bitops/non-atomic: make @nr unsigned to avoid any DIV
asm-generic: ffs: Drop bogus reference to ffz location
asm-generic: reverse GENERIC_{STRNCPY_FROM,STRNLEN}_USER symbols
asm-generic: remove extra strn{cpy_from,len}_user declarations
asm-generic: uaccess: remove inline strncpy_from_user/strnlen_user
s390: use generic strncpy/strnlen from_user
microblaze: use generic strncpy/strnlen from_user
csky: use generic strncpy/strnlen from_user
arc: use generic strncpy/strnlen from_user
hexagon: use generic strncpy/strnlen from_user
h8300: remove stale strncpy_from_user
asm-generic/uaccess.h: remove __strncpy_from_user/__strnlen_user
42 files changed, 56 insertions, 657 deletions
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 6c50877841df..02e5b673bdad 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -28,8 +28,6 @@ config ALPHA select AUDIT_ARCH select GENERIC_CPU_VULNERABILITIES select GENERIC_SMP_IDLE_THREAD - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER select HAVE_ARCH_AUDITSYSCALL select HAVE_MOD_ARCH_SPECIFIC select MODULES_USE_ELF_RELA diff --git a/arch/arc/include/asm/uaccess.h b/arch/arc/include/asm/uaccess.h index ea40ec7f6cae..783bfdb3bfa3 100644 --- a/arch/arc/include/asm/uaccess.h +++ b/arch/arc/include/asm/uaccess.h @@ -655,88 +655,16 @@ static inline unsigned long __arc_clear_user(void __user *to, unsigned long n) return res; } -static inline long -__arc_strncpy_from_user(char *dst, const char __user *src, long count) -{ - long res = 0; - char val; - - if (count == 0) - return 0; - - __asm__ __volatile__( - " mov lp_count, %5 \n" - " lp 3f \n" - "1: ldb.ab %3, [%2, 1] \n" - " breq.d %3, 0, 3f \n" - " stb.ab %3, [%1, 1] \n" - " add %0, %0, 1 # Num of NON NULL bytes copied \n" - "3: \n" - " .section .fixup, \"ax\" \n" - " .align 4 \n" - "4: mov %0, %4 # sets @res as -EFAULT \n" - " j 3b \n" - " .previous \n" - " .section __ex_table, \"a\" \n" - " .align 4 \n" - " .word 1b, 4b \n" - " .previous \n" - : "+r"(res), "+r"(dst), "+r"(src), "=r"(val) - : "g"(-EFAULT), "r"(count) - : "lp_count", "memory"); - - return res; -} - -static inline long __arc_strnlen_user(const char __user *s, long n) -{ - long res, tmp1, cnt; - char val; - - __asm__ __volatile__( - " mov %2, %1 \n" - "1: ldb.ab %3, [%0, 1] \n" - " breq.d %3, 0, 2f \n" - " sub.f %2, %2, 1 \n" - " bnz 1b \n" - " sub %2, %2, 1 \n" - "2: sub %0, %1, %2 \n" - "3: ;nop \n" - " .section .fixup, \"ax\" \n" - " .align 4 \n" - "4: mov %0, 0 \n" - " j 3b \n" - " .previous \n" - " .section __ex_table, \"a\" \n" - " .align 4 \n" - " .word 1b, 4b \n" - " .previous \n" - : "=r"(res), "=r"(tmp1), "=r"(cnt), "=r"(val) - : "0"(s), "1"(n) - : "memory"); - - return res; -} - #ifndef CONFIG_CC_OPTIMIZE_FOR_SIZE #define INLINE_COPY_TO_USER #define INLINE_COPY_FROM_USER #define __clear_user(d, n) __arc_clear_user(d, n) -#define __strncpy_from_user(d, s, n) __arc_strncpy_from_user(d, s, n) -#define __strnlen_user(s, n) __arc_strnlen_user(s, n) #else extern unsigned long arc_clear_user_noinline(void __user *to, unsigned long n); -extern long arc_strncpy_from_user_noinline (char *dst, const char __user *src, - long count); -extern long arc_strnlen_user_noinline(const char __user *src, long n); - #define __clear_user(d, n) arc_clear_user_noinline(d, n) -#define __strncpy_from_user(d, s, n) arc_strncpy_from_user_noinline(d, s, n) -#define __strnlen_user(s, n) arc_strnlen_user_noinline(s, n) - #endif #include <asm/segment.h> diff --git a/arch/arc/mm/extable.c b/arch/arc/mm/extable.c index b06b09ddf924..4e14c4244ea2 100644 --- a/arch/arc/mm/extable.c +++ b/arch/arc/mm/extable.c @@ -32,16 +32,4 @@ unsigned long arc_clear_user_noinline(void __user *to, } EXPORT_SYMBOL(arc_clear_user_noinline); -long arc_strncpy_from_user_noinline(char *dst, const char __user *src, - long count) -{ - return __arc_strncpy_from_user(dst, src, count); -} -EXPORT_SYMBOL(arc_strncpy_from_user_noinline); - -long arc_strnlen_user_noinline(const char __user *src, long n) -{ - return __arc_strnlen_user(src, n); -} -EXPORT_SYMBOL(arc_strnlen_user_noinline); #endif diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 2fb7012c3246..1a48c17a5909 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -63,8 +63,6 @@ config ARM select GENERIC_PCI_IOMAP select GENERIC_SCHED_CLOCK select GENERIC_SMP_IDLE_THREAD - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER select HANDLE_DOMAIN_IRQ select HARDIRQS_SW_RESEND select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 62c3c1d2190f..9dc1720a909f 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -130,8 +130,6 @@ config ARM64 select GENERIC_PTDUMP select GENERIC_SCHED_CLOCK select GENERIC_SMP_IDLE_THREAD - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL select GENERIC_GETTIMEOFDAY select GENERIC_VDSO_TIME_NS diff --git a/arch/csky/include/asm/uaccess.h b/arch/csky/include/asm/uaccess.h index ac83823fc437..c40f06ee8d3e 100644 --- a/arch/csky/include/asm/uaccess.h +++ b/arch/csky/include/asm/uaccess.h @@ -209,12 +209,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 -long __strncpy_from_user(char *dst, const char *src, long count); -#define __strncpy_from_user __strncpy_from_user - -long __strnlen_user(const char *s, long n); -#define __strnlen_user __strnlen_user - #include <asm/segment.h> #include <asm-generic/uaccess.h> diff --git a/arch/csky/lib/usercopy.c b/arch/csky/lib/usercopy.c index c5d394a0ae78..3c01c54421ca 100644 --- a/arch/csky/lib/usercopy.c +++ b/arch/csky/lib/usercopy.c @@ -143,108 +143,6 @@ unsigned long raw_copy_to_user(void *to, const void *from, EXPORT_SYMBOL(raw_copy_to_user); /* - * __strncpy_from_user: - Copy a NUL terminated string from userspace, - * with less checking. - * @dst: Destination address, in kernel space. This buffer must be at - * least @count bytes long. - * @src: Source address, in user space. - * @count: Maximum number of bytes to copy, including the trailing NUL. - * - * Copies a NUL-terminated string from userspace to kernel space. - * Caller must check the specified block with access_ok() before calling - * this function. - * - * On success, returns the length of the string (not including the trailing - * NUL). - * - * If access to userspace fails, returns -EFAULT (some data may have been - * copied). - * - * If @count is smaller than the length of the string, copies @count bytes - * and returns @count. - */ -long __strncpy_from_user(char *dst, const char *src, long count) -{ - long res, faultres; - int tmp; - - __asm__ __volatile__( - " cmpnei %3, 0 \n" - " bf 4f \n" - "1: cmpnei %1, 0 \n" - " bf 5f \n" - "2: ldb %4, (%3, 0) \n" - " stb %4, (%2, 0) \n" - " cmpnei %4, 0 \n" - " bf 3f \n" - " addi %3, 1 \n" - " addi %2, 1 \n" - " subi %1, 1 \n" - " br 1b \n" - "3: subu %0, %1 \n" - " br 5f \n" - "4: mov %0, %5 \n" - " br 5f \n" - ".section __ex_table, \"a\" \n" - ".align 2 \n" - ".long 2b, 4b \n" - ".previous \n" - "5: \n" - : "=r"(res), "=r"(count), "=r"(dst), - "=r"(src), "=r"(tmp), "=r"(faultres) - : "5"(-EFAULT), "0"(count), "1"(count), - "2"(dst), "3"(src) - : "memory"); - - return res; -} -EXPORT_SYMBOL(__strncpy_from_user); - -/* - * strnlen_user: - Get the size of a string in user space. - * @str: The string to measure. - * @n: The maximum valid length - * - * Get the size of a NUL-terminated string in user space. - * - * Returns the size of the string INCLUDING the terminating NUL. - * On exception, returns 0. - * If the string is too long, returns a value greater than @n. - */ -long __strnlen_user(const char *s, long n) -{ - unsigned long res, tmp; - - __asm__ __volatile__( - " cmpnei %1, 0 \n" - " bf 3f \n" - "1: cmpnei %0, 0 \n" - " bf 3f \n" - "2: ldb %3, (%1, 0) \n" - " cmpnei %3, 0 \n" - " bf 3f \n" - " subi %0, 1 \n" - " addi %1, 1 \n" - " br 1b \n" - "3: subu %2, %0 \n" - " addi %2, 1 \n" - " br 5f \n" - "4: movi %0, 0 \n" - " br 5f \n" - ".section __ex_table, \"a\" \n" - ".align 2 \n" - ".long 2b, 4b \n" - ".previous \n" - "5: \n" - : "=r"(n), "=r"(s), "=r"(res), "=r"(tmp) - : "0"(n), "1"(s), "2"(n) - : "memory"); - - return res; -} -EXPORT_SYMBOL(__strnlen_user); - -/* * __clear_user: - Zero a block of memory in user space, with less checking. * @to: Destination address, in user space. * @n: Number of bytes to zero. diff --git a/arch/h8300/kernel/h8300_ksyms.c b/arch/h8300/kernel/h8300_ksyms.c index 1c6f902e82a5..853d6e886477 100644 --- a/arch/h8300/kernel/h8300_ksyms.c +++ b/arch/h8300/kernel/h8300_ksyms.c @@ -19,7 +19,6 @@ asmlinkage long __mulsi3(long, long); asmlinkage long __udivsi3(long, long); asmlinkage void *memcpy(void *, const void *, size_t); asmlinkage void *memset(void *, int, size_t); -asmlinkage long strncpy_from_user(void *to, void *from, size_t n); /* gcc lib functions */ EXPORT_SYMBOL(__ucmpdi2); @@ -34,4 +33,3 @@ EXPORT_SYMBOL(__mulsi3); EXPORT_SYMBOL(__udivsi3); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(strncpy_from_user); diff --git a/arch/h8300/lib/Makefile b/arch/h8300/lib/Makefile index 685fa837c1f7..5911c1fa856d 100644 --- a/arch/h8300/lib/Makefile +++ b/arch/h8300/lib/Makefile @@ -3,7 +3,7 @@ # Makefile for H8/300-specific library files.. # -lib-y = memcpy.o memset.o abs.o strncpy.o \ +lib-y = memcpy.o memset.o abs.o \ mulsi3.o udivsi3.o muldi3.o moddivsi3.o \ ashldi3.o lshrdi3.o ashrdi3.o ucmpdi2.o \ delay.o diff --git a/arch/h8300/lib/strncpy.S b/arch/h8300/lib/strncpy.S deleted file mode 100644 index 8b65d7c4727b..000000000000 --- a/arch/h8300/lib/strncpy.S +++ /dev/null @@ -1,35 +0,0 @@ -;;; SPDX-License-Identifier: GPL-2.0 -;;; strncpy.S - -#include <asm/linkage.h> - - .text -.global strncpy_from_user - -;;; long strncpy_from_user(void *to, void *from, size_t n) -strncpy_from_user: - mov.l er2,er2 - bne 1f - sub.l er0,er0 - rts -1: - mov.l er4,@-sp - sub.l er3,er3 -2: - mov.b @er1+,r4l - mov.b r4l,@er0 - adds #1,er0 - beq 3f - inc.l #1,er3 - dec.l #1,er2 - bne 2b -3: - dec.l #1,er2 -4: - mov.b r4l,@er0 - adds #1,er0 - dec.l #1,er2 - bne 4b - mov.l er3,er0 - mov.l @sp+,er4 - rts diff --git a/arch/hexagon/include/asm/uaccess.h b/arch/hexagon/include/asm/uaccess.h index c1019a736ff1..ef5bfef8d490 100644 --- a/arch/hexagon/include/asm/uaccess.h +++ b/arch/hexagon/include/asm/uaccess.h @@ -57,38 +57,7 @@ unsigned long raw_copy_to_user(void __user *to, const void *from, __kernel_size_t __clear_user_hexagon(void __user *dest, unsigned long count); #define __clear_user(a, s) __clear_user_hexagon((a), (s)) -#define __strncpy_from_user(dst, src, n) hexagon_strncpy_from_user(dst, src, n) - -/* get around the ifndef in asm-generic/uaccess.h */ -#define __strnlen_user __strnlen_user - -extern long __strnlen_user(const char __user *src, long n); - -static inline long hexagon_strncpy_from_user(char *dst, const char __user *src, - long n); - #include <asm-generic/uaccess.h> -/* Todo: an actual accelerated version of this. */ -static inline long hexagon_strncpy_from_user(char *dst, const char __user *src, - long n) -{ - long res = __strnlen_user(src, n); - - if (unlikely(!res)) - return -EFAULT; - - if (res > n) { - long left = raw_copy_from_user(dst, src, n); - if (unlikely(left)) - memset(dst + (n - left), 0, left); - return n; - } else { - long left = raw_copy_from_user(dst, src, res); - if (unlikely(left)) - memset(dst + (res - left), 0, left); - return res-1; - } -} #endif diff --git a/arch/hexagon/kernel/hexagon_ksyms.c b/arch/hexagon/kernel/hexagon_ksyms.c index 35545a7386a0..ec56ce2d92a2 100644 --- a/arch/hexagon/kernel/hexagon_ksyms.c +++ b/arch/hexagon/kernel/hexagon_ksyms.c @@ -15,7 +15,6 @@ EXPORT_SYMBOL(__clear_user_hexagon); EXPORT_SYMBOL(raw_copy_from_user); EXPORT_SYMBOL(raw_copy_to_user); EXPORT_SYMBOL(iounmap); -EXPORT_SYMBOL(__strnlen_user); EXPORT_SYMBOL(__vmgetie); EXPORT_SYMBOL(__vmsetie); EXPORT_SYMBOL(__vmyield); diff --git a/arch/hexagon/mm/Makefile b/arch/hexagon/mm/Makefile index 893838499591..49911a906fd0 100644 --- a/arch/hexagon/mm/Makefile +++ b/arch/hexagon/mm/Makefile @@ -4,4 +4,4 @@ # obj-y := init.o ioremap.o uaccess.o vm_fault.o cache.o -obj-y += copy_to_user.o copy_from_user.o strnlen_user.o vm_tlb.o +obj-y += copy_to_user.o copy_from_user.o vm_tlb.o diff --git a/arch/hexagon/mm/strnlen_user.S b/arch/hexagon/mm/strnlen_user.S deleted file mode 100644 index 4b5574a7cc9c..000000000000 --- a/arch/hexagon/mm/strnlen_user.S +++ /dev/null @@ -1,126 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * User string length functions for kernel - * - * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. - */ - -#define isrc r0 -#define max r1 /* Do not change! */ - -#define end r2 -#define tmp1 r3 - -#define obo r6 /* off-by-one */ -#define start r7 -#define mod8 r8 -#define dbuf r15:14 -#define dcmp r13:12 - -/* - * The vector mask version of this turned out *really* badly. - * The hardware loop version also turned out *really* badly. - * Seems straight pointer arithmetic basically wins here. - */ - -#define fname __strnlen_user - - .text - .global fname - .type fname, @function - .p2align 5 /* why? */ -fname: - { - mod8 = and(isrc,#7); - end = add(isrc,max); - start = isrc; - } - { - P0 = cmp.eq(mod8,#0); - mod8 = and(end,#7); - dcmp = #0; - if (P0.new) jump:t dw_loop; /* fire up the oven */ - } - -alignment_loop: -fail_1: { - tmp1 = memb(start++#1); - } - { - P0 = cmp.eq(tmp1,#0); - if (P0.new) jump:nt exit_found; - P1 = cmp.gtu(end,start); - mod8 = and(start,#7); - } - { - if (!P1) jump exit_error; /* hit the end */ - P0 = cmp.eq(mod8,#0); - } - { - if (!P0) jump alignment_loop; - } - - - -dw_loop: -fail_2: { - dbuf = memd(start); - obo = add(start,#1); - } - { - P0 = vcmpb.eq(dbuf,dcmp); - } - { - tmp1 = P0; - P0 = cmp.gtu(end,start); - } - { - tmp1 = ct0(tmp1); - mod8 = and(end,#7); - if (!P0) jump end_check; - } - { - P0 = cmp.eq(tmp1,#32); - if (!P0.new) jump:nt exit_found; - if (!P0.new) start = add(obo,tmp1); - } - { - start = add(start,#8); - jump dw_loop; - } /* might be nice to combine these jumps... */ - - -end_check: - { - P0 = cmp.gt(tmp1,mod8); - if (P0.new) jump:nt exit_error; /* neverfound! */ - start = add(obo,tmp1); - } - -exit_found: - { - R0 = sub(start,isrc); - jumpr R31; - } - -exit_error: - { - R0 = add(max,#1); - jumpr R31; - } - - /* Uh, what does the "fixup" return here? */ - .falign -fix_1: - { - R0 = #0; - jumpr R31; - } - - .size fname,.-fname - - -.section __ex_table,"a" -.long fail_1,fix_1 -.long fail_2,fix_1 -.previous diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 4993c7ac7ff6..045792cde481 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -9,6 +9,8 @@ menu "Processor type and features" config IA64 bool select ARCH_HAS_DMA_MARK_CLEAN + select ARCH_HAS_STRNCPY_FROM_USER + select ARCH_HAS_STRNLEN_USER select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO select ACPI diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index d632a1d576f9..774c35f47eea 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -16,8 +16,6 @@ config M68K select GENERIC_CPU_DEVICES select GENERIC_IOMAP select GENERIC_IRQ_SHOW - select GENERIC_STRNCPY_FROM_USER if MMU - select GENERIC_STRNLEN_USER if MMU select HAVE_AOUT if MMU select HAVE_ASM_MODVERSIONS select HAVE_DEBUG_BUGVERBOSE diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index c44b59470e45..d2a8ef9f8978 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -35,6 +35,7 @@ # 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) @@ -296,28 +297,14 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n) /* * Copy a null terminated string from userspace. */ -extern int __strncpy_user(char *to, const char __user *from, int len); - -static inline long -strncpy_from_user(char *dst, const char __user *src, long count) -{ - if (!access_ok(src, 1)) - return -EFAULT; - return __strncpy_user(dst, src, count); -} +__must_check long strncpy_from_user(char *dst, const char __user *src, + long count); /* * Return the size of a string (including the ending 0) * * Return 0 on exception, a value greater than N if too long */ -extern int __strnlen_user(const char __user *sstr, int len); - -static inline long strnlen_user(const char __user *src, long n) -{ - if (!access_ok(src, 1)) - return 0; - return __strnlen_user(src, n); -} +__must_check long strnlen_user(const char __user *sstr, long len); #endif /* _ASM_MICROBLAZE_UACCESS_H */ diff --git a/arch/microblaze/kernel/microblaze_ksyms.c b/arch/microblaze/kernel/microblaze_ksyms.c index 303aaf13573b..c892e173ec99 100644 --- a/arch/microblaze/kernel/microblaze_ksyms.c +++ b/arch/microblaze/kernel/microblaze_ksyms.c @@ -26,7 +26,6 @@ EXPORT_SYMBOL(_mcount); * Assembly functions that may be used (directly or indirectly) by modules */ EXPORT_SYMBOL(__copy_tofrom_user); -EXPORT_SYMBOL(__strncpy_user); #ifdef CONFIG_OPT_LIB_ASM EXPORT_SYMBOL(memcpy); diff --git a/arch/microblaze/lib/uaccess_old.S b/arch/microblaze/lib/uaccess_old.S index eca290090038..dd5f3bfbc2c5 100644 --- a/arch/microblaze/lib/uaccess_old.S +++ b/arch/microblaze/lib/uaccess_old.S @@ -12,96 +12,6 @@ #include <linux/linkage.h> #include <asm/page.h> -/* - * int __strncpy_user(char *to, char *from, int len); - * - * Returns: - * -EFAULT for an exception - * len if we hit the buffer limit - * bytes copied - */ - - .text -.globl __strncpy_user; -.type __strncpy_user, @function -.align 4; -__strncpy_user: - - /* - * r5 - to - * r6 - from - * r7 - len - * r3 - temp count - * r4 - temp val - */ - beqid r7,3f - addik r3,r7,0 /* temp_count = len */ -1: - lbu r4,r6,r0 - beqid r4,2f - sb r4,r5,r0 - - addik r5,r5,1 - addik r6,r6,1 /* delay slot */ - - addik r3,r3,-1 - bnei r3,1b /* break on len */ -2: - rsubk r3,r3,r7 /* temp_count = len - temp_count */ -3: - rtsd r15,8 - nop - .size __strncpy_user, . - __strncpy_user - - .section .fixup, "ax" - .align 2 -4: - brid 3b - addik r3,r0, -EFAULT - - .section __ex_table, "a" - .word 1b,4b - -/* - * int __strnlen_user(char __user *str, int maxlen); - * - * Returns: - * 0 on error - * maxlen + 1 if no NUL byte found within maxlen bytes - * size of the string (including NUL byte) - */ - - .text -.globl __strnlen_user; -.type __strnlen_user, @function -.align 4; -__strnlen_user: - beqid r6,3f - addik r3,r6,0 -1: - lbu r4,r5,r0 - beqid r4,2f /* break on NUL */ - addik r3,r3,-1 /* delay slot */ - - bneid r3,1b - addik r5,r5,1 /* delay slot */ - - addik r3,r3,-1 /* for break on len */ -2: - rsubk r3,r3,r6 -3: - rtsd r15,8 - nop - .size __strnlen_user, . - __strnlen_user - - .section .fixup,"ax" -4: - brid 3b - addk r3,r0,r0 - - .section __ex_table,"a" - .word 1b,4b - /* Loop unrolling for __copy_tofrom_user */ #define COPY(offset) \ 1: lwi r4 , r6, 0x0000 + offset; \ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 6dfb27d531dd..24e374266fdc 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -9,6 +9,8 @@ config MIPS select ARCH_HAS_KCOV select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE if !EVA select ARCH_HAS_PTE_SPECIAL if !(32BIT && CPU_HAS_RIXI) + select ARCH_HAS_STRNCPY_FROM_USER + select ARCH_HAS_STRNLEN_USER select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_HAS_UBSAN_SANITIZE_ALL select ARCH_HAS_GCOV_PROFILE_ALL diff --git a/arch/nds32/Kconfig b/arch/nds32/Kconfig index 62313902d75d..9c9f3877abf9 100644 --- a/arch/nds32/Kconfig +++ b/arch/nds32/Kconfig @@ -26,8 +26,6 @@ config NDS32 select GENERIC_LIB_LSHRDI3 select GENERIC_LIB_MULDI3 select GENERIC_LIB_UCMPDI2 - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL select HANDLE_DOMAIN_IRQ select HAVE_ARCH_TRACEHOOK diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig index c24955c81c92..3efe5533ea1c 100644 --- a/arch/nios2/Kconfig +++ b/arch/nios2/Kconfig @@ -13,8 +13,6 @@ config NIOS2 select GENERIC_CPU_DEVICES select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_KGDB select IRQ_DOMAIN diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig index 591acc5990dc..50035a9816c8 100644 --- a/arch/openrisc/Kconfig +++ b/arch/openrisc/Kconfig @@ -25,8 +25,6 @@ config OPENRISC select HAVE_UID16 select GENERIC_ATOMIC64 select GENERIC_CLOCKEVENTS_BROADCAST - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER select GENERIC_SMP_IDLE_THREAD select MODULES_USE_ELF_RELA select HAVE_DEBUG_STACKOVERFLOW diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 4f8c1fbf8f2f..95d4bbf4e455 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -10,6 +10,7 @@ config PARISC select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_STRICT_KERNEL_RWX select ARCH_HAS_UBSAN_SANITIZE_ALL + select ARCH_HAS_STRNLEN_USER select ARCH_NO_SG_CHAIN select ARCH_SUPPORTS_HUGETLBFS if PA20 select ARCH_SUPPORTS_MEMORY_FAILURE @@ -33,7 +34,6 @@ config PARISC select ARCH_HAVE_NMI_SAFE_CMPXCHG select GENERIC_SMP_IDLE_THREAD select GENERIC_CPU_DEVICES - select GENERIC_STRNCPY_FROM_USER select GENERIC_LIB_DEVMEM_IS_ALLOWED select SYSCTL_ARCH_UNALIGN_ALLOW select SYSCTL_EXCEPTION_TRACE diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 663766fbf505..678a0acbad7b 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -183,8 +183,6 @@ config PPC select GENERIC_IRQ_SHOW_LEVEL select GENERIC_PCI_IOMAP if PCI select GENERIC_SMP_IDLE_THREAD - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL select GENERIC_VDSO_TIME_NS select HAVE_ARCH_AUDITSYSCALL diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 4f7b70ae7c31..1452584f83be 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -56,8 +56,6 @@ config RISCV select GENERIC_PTDUMP if MMU select GENERIC_SCHED_CLOCK select GENERIC_SMP_IDLE_THREAD - select GENERIC_STRNCPY_FROM_USER if MMU - select GENERIC_STRNLEN_USER if MMU select GENERIC_TIME_VSYSCALL if MMU && 64BIT select HANDLE_DOMAIN_IRQ select HAVE_ARCH_AUDITSYSCALL diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h index 2316f2440881..9ed9aa37e836 100644 --- a/arch/s390/include/asm/uaccess.h +++ b/arch/s390/include/asm/uaccess.h @@ -233,23 +233,9 @@ raw_copy_in_user(void __user *to, const void __user *from, unsigned long n); /* * Copy a null terminated string from userspace. */ +long __must_check strncpy_from_user(char *dst, const char __user *src, long count); -long __strncpy_from_user(char *dst, const char __user *src, long count); - -static inline long __must_check -strncpy_from_user(char *dst, const char __user *src, long count) -{ - might_fault(); - return __strncpy_from_user(dst, src, count); -} - -unsigned long __must_check __strnlen_user(const char __user *src, unsigned long count); - -static inline unsigned long strnlen_user(const char __user *src, unsigned long n) -{ - might_fault(); - return __strnlen_user(src, n); -} +long __must_check strnlen_user(const char __user *src, long count); /* * Zero Userspace diff --git a/arch/s390/lib/uaccess.c b/arch/s390/lib/uaccess.c index 7ec8b1fa0f08..94ca99bde59d 100644 --- a/arch/s390/lib/uaccess.c +++ b/arch/s390/lib/uaccess.c @@ -338,55 +338,3 @@ unsigned long __clear_user(void __user *to, unsigned long size) return clear_user_xc(to, size); } EXPORT_SYMBOL(__clear_user); - -static inline unsigned long strnlen_user_srst(const char __user *src, - unsigned long size) -{ - unsigned long tmp1, tmp2; - - asm volatile( - " lghi 0,0\n" - " la %2,0(%1)\n" - " la %3,0(%0,%1)\n" - " slgr %0,%0\n" - " sacf 256\n" - "0: srst %3,%2\n" - " jo 0b\n" - " la %0,1(%3)\n" /* strnlen_user results includes \0 */ - " slgr %0,%1\n" - "1: sacf 768\n" - EX_TABLE(0b,1b) - : "+a" (size), "+a" (src), "=a" (tmp1), "=a" (tmp2) - : - : "cc", "memory", "0"); - return size; -} - -unsigned long __strnlen_user(const char __user *src, unsigned long size) -{ - if (unlikely(!size)) - return 0; - return strnlen_user_srst(src, size); -} -EXPORT_SYMBOL(__strnlen_user); - -long __strncpy_from_user(char *dst, const char __user *src, long size) -{ - size_t done, len, offset, len_str; - - if (unlikely(size <= 0)) - return 0; - done = 0; - do { - offset = (size_t)src & (L1_CACHE_BYTES - 1); - len = min(size - done, L1_CACHE_BYTES - offset); - if (copy_from_user(dst, src, len)) - return -EFAULT; - len_str = strnlen(dst, len); - done += len_str; - src += len_str; - dst += len_str; - } while ((len_str == len) && (done < size)); - return done; -} -EXPORT_SYMBOL(__strncpy_from_user); diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index b683b69a4556..f37280e805ea 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -22,8 +22,6 @@ config SUPERH select GENERIC_IRQ_SHOW select GENERIC_PCI_IOMAP if PCI select GENERIC_SCHED_CLOCK - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER select GENERIC_SMP_IDLE_THREAD select GUP_GET_PTE_LOW_HIGH if X2TLB select HAVE_ARCH_AUDITSYSCALL diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index f0c0f955e169..fa650e4eadba 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -37,8 +37,6 @@ config SPARC select HAVE_EBPF_JIT if SPARC64 select HAVE_DEBUG_BUGVERBOSE select GENERIC_SMP_IDLE_THREAD - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER select MODULES_USE_ELF_RELA select PCI_SYSCALL if PCI select PCI_MSI_ARCH_FALLBACKS if PCI_MSI diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 0561b73cfd9a..77e66d3719f6 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -7,6 +7,8 @@ config UML default y select ARCH_EPHEMERAL_INODES select ARCH_HAS_KCOV + select ARCH_HAS_STRNCPY_FROM_USER + select ARCH_HAS_STRNLEN_USER select ARCH_NO_PREEMPT select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_SECCOMP_FILTER diff --git a/arch/um/include/asm/uaccess.h b/arch/um/include/asm/uaccess.h index fe66d659acad..191ef36dd543 100644 --- a/arch/um/include/asm/uaccess.h +++ b/arch/um/include/asm/uaccess.h @@ -23,16 +23,13 @@ extern unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n); extern unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long n); -extern long __strncpy_from_user(char *dst, const char __user *src, long count); -extern long __strnlen_user(const void __user *str, long len); extern unsigned long __clear_user(void __user *mem, unsigned long len); static inline int __access_ok(unsigned long addr, unsigned long size); /* Teach asm-generic/uaccess.h that we have C functions for these. */ #define __access_ok __access_ok #define __clear_user __clear_user -#define __strnlen_user __strnlen_user -#define __strncpy_from_user __strncpy_from_user + #define INLINE_COPY_FROM_USER #define INLINE_COPY_TO_USER diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index 6c76df96e858..a509be911026 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -189,11 +189,14 @@ static int strncpy_chunk_from_user(unsigned long from, int len, void *arg) return 0; } -long __strncpy_from_user(char *dst, const char __user *src, long count) +long strncpy_from_user(char *dst, const char __user *src, long count) { long n; char *ptr = dst; + if (!access_ok(src, 1)) + return -EFAULT; + if (uaccess_kernel()) { strncpy(dst, (__force void *) src, count); return strnlen(dst, count); @@ -205,7 +208,7 @@ long __strncpy_from_user(char *dst, const char __user *src, long count) return -EFAULT; return strnlen(dst, count); } -EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(strncpy_from_user); static int clear_chunk(unsigned long addr, int len, void *unused) { @@ -236,10 +239,13 @@ static int strnlen_chunk(unsigned long str, int len, void *arg) return 0; } -long __strnlen_user(const void __user *str, long len) +long strnlen_user(const char __user *str, long len) { int count = 0, n; + if (!access_ok(str, 1)) + return -EFAULT; + if (uaccess_kernel()) return strnlen((__force char*)str, len) + 1; @@ -248,7 +254,7 @@ long __strnlen_user(const void __user *str, long len) return count + 1; return 0; } -EXPORT_SYMBOL(__strnlen_user); +EXPORT_SYMBOL(strnlen_user); /** * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 45962aaf2b2c..1146b85d708b 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -145,8 +145,6 @@ config X86 select GENERIC_PENDING_IRQ if SMP select GENERIC_PTDUMP select GENERIC_SMP_IDLE_THREAD - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL select GENERIC_GETTIMEOFDAY select GENERIC_VDSO_TIME_NS diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 3878880469d1..f02b8850b01b 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -7,6 +7,8 @@ config XTENSA select ARCH_HAS_SYNC_DMA_FOR_CPU if MMU select ARCH_HAS_SYNC_DMA_FOR_DEVICE if MMU select ARCH_HAS_DMA_SET_UNCACHED if MMU + select ARCH_HAS_STRNCPY_FROM_USER if !KASAN + select ARCH_HAS_STRNLEN_USER select ARCH_USE_MEMTEST select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_SPINLOCKS @@ -20,7 +22,6 @@ config XTENSA select GENERIC_IRQ_SHOW select GENERIC_PCI_IOMAP select GENERIC_SCHED_CLOCK - select GENERIC_STRNCPY_FROM_USER if KASAN select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL select HAVE_ARCH_KASAN if MMU && !XIP_KERNEL diff --git a/arch/xtensa/include/asm/uaccess.h b/arch/xtensa/include/asm/uaccess.h index 5c9fb8005aa8..75bd8fbf52ba 100644 --- a/arch/xtensa/include/asm/uaccess.h +++ b/arch/xtensa/include/asm/uaccess.h @@ -290,8 +290,7 @@ clear_user(void __user *addr, unsigned long size) #define __clear_user __xtensa_clear_user -#ifndef CONFIG_GENERIC_STRNCPY_FROM_USER - +#ifdef CONFIG_ARCH_HAS_STRNCPY_FROM_USER extern long __strncpy_user(char *dst, const char __user *src, long count); static inline long diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index 415fe7faa37f..d79edbb98d2a 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c @@ -43,7 +43,7 @@ EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memmove); -#ifndef CONFIG_GENERIC_STRNCPY_FROM_USER +#ifdef CONFIG_ARCH_HAS_STRNCPY_FROM_USER EXPORT_SYMBOL(__strncpy_user); #endif EXPORT_SYMBOL(clear_page); diff --git a/include/asm-generic/bitops/builtin-ffs.h b/include/asm-generic/bitops/builtin-ffs.h index 1dacfdb4247e..7b129329046b 100644 --- a/include/asm-generic/bitops/builtin-ffs.h +++ b/include/asm-generic/bitops/builtin-ffs.h @@ -8,7 +8,7 @@ * * This is defined the same way as * the libc and compiler builtin ffs routines, therefore - * differs in spirit from the above ffz (man ffs). + * differs in spirit from ffz (man ffs). */ #define ffs(x) __builtin_ffs(x) diff --git a/include/asm-generic/bitops/ffs.h b/include/asm-generic/bitops/ffs.h index e81868b2c0f0..323fd5d6ae26 100644 --- a/include/asm-generic/bitops/ffs.h +++ b/include/asm-generic/bitops/ffs.h @@ -8,7 +8,7 @@ * * This is defined the same way as * the libc and compiler builtin ffs routines, therefore - * differs in spirit from the above ffz (man ffs). + * differs in spirit from ffz (man ffs). */ static inline int ffs(int x) { diff --git a/include/asm-generic/bitops/non-atomic.h b/include/asm-generic/bitops/non-atomic.h index 365377fb104b..078cc68be2f1 100644 --- a/include/asm-generic/bitops/non-atomic.h +++ b/include/asm-generic/bitops/non-atomic.h @@ -14,7 +14,7 @@ * may be that only one operation succeeds. */ static __always_inline void -arch___set_bit(int nr, volatile unsigned long *addr) +arch___set_bit(unsigned int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); @@ -24,7 +24,7 @@ arch___set_bit(int nr, volatile unsigned long *addr) #define __set_bit arch___set_bit static __always_inline void -arch___clear_bit(int nr, volatile unsigned long *addr) +arch___clear_bit(unsigned int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); @@ -43,7 +43,7 @@ arch___clear_bit(int nr, volatile unsigned long *addr) * may be that only one operation succeeds. */ static __always_inline -void arch___change_bit(int nr, volatile unsigned long *addr) +void arch___change_bit(unsigned int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); @@ -62,7 +62,7 @@ void arch___change_bit(int nr, volatile unsigned long *addr) * but actually fail. You must protect multiple accesses with a lock. */ static __always_inline int -arch___test_and_set_bit(int nr, volatile unsigned long *addr) +arch___test_and_set_bit(unsigned int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); @@ -83,7 +83,7 @@ arch___test_and_set_bit(int nr, volatile unsigned long *addr) * but actually fail. You must protect multiple accesses with a lock. */ static __always_inline int -arch___test_and_clear_bit(int nr, volatile unsigned long *addr) +arch___test_and_clear_bit(unsigned int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); @@ -96,7 +96,7 @@ arch___test_and_clear_bit(int nr, volatile unsigned long *addr) /* WARNING: non atomic and it can be reordered! */ static __always_inline int -arch___test_and_change_bit(int nr, volatile unsigned long *addr) +arch___test_and_change_bit(unsigned int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); @@ -113,7 +113,7 @@ arch___test_and_change_bit(int nr, volatile unsigned long *addr) * @addr: Address to start counting from */ static __always_inline int -arch_test_bit(int nr, const volatile unsigned long *addr) +arch_test_bit(unsigned int nr, const volatile unsigned long *addr) { return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); } diff --git a/include/asm-generic/uaccess.h b/include/asm-generic/uaccess.h index a0b2f270dddc..10ffa8b5c117 100644 --- a/include/asm-generic/uaccess.h +++ b/include/asm-generic/uaccess.h @@ -119,6 +119,11 @@ static inline void set_fs(mm_segment_t fs) #ifndef uaccess_kernel #define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg) #endif + +#ifndef user_addr_max +#define user_addr_max() (uaccess_kernel() ? ~0UL : TASK_SIZE) +#endif + #endif /* CONFIG_SET_FS */ #define access_ok(addr, size) __access_ok((unsigned long)(addr),(size)) @@ -244,50 +249,6 @@ static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) extern int __get_user_bad(void) __attribute__((noreturn)); /* - * Copy a null terminated string from userspace. - */ -#ifndef __strncpy_from_user -static inline long -__strncpy_from_user(char *dst, const char __user *src, long count) -{ - char *tmp; - strncpy(dst, (const char __force *)src, count); - for (tmp = dst; *tmp && count > 0; tmp++, count--) - ; - return (tmp - dst); -} -#endif - -static inline long -strncpy_from_user(char *dst, const char __user *src, long count) -{ - if (!access_ok(src, 1)) - return -EFAULT; - return __strncpy_from_user(dst, src, count); -} - -/* - * Return the size of a string (including the ending 0) - * - * Return 0 on exception, a value greater than N if too long - */ -#ifndef __strnlen_user -#define __strnlen_user(s, n) (strnlen((s), (n)) + 1) -#endif - -/* - * Unlike strnlen, strnlen_user includes the nul terminator in - * its returned count. Callers should check for a returned value - * greater than N as an indication the string is too long. - */ -static inline long strnlen_user(const char __user *src, long n) -{ - if (!access_ok(src, 1)) - return 0; - return __strnlen_user(src, n); -} - -/* * Zero Userspace */ #ifndef __clear_user @@ -311,4 +272,8 @@ clear_user(void __user *to, unsigned long n) #include <asm/extable.h> +__must_check long strncpy_from_user(char *dst, const char __user *src, + long count); +__must_check long strnlen_user(const char __user *src, long n); + #endif /* __ASM_GENERIC_UACCESS_H */ diff --git a/lib/Kconfig b/lib/Kconfig index 5c9c0687f76d..5e7165e6a346 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -50,12 +50,18 @@ config HAVE_ARCH_BITREVERSE This option enables the use of hardware bit-reversal instructions on architectures which support such operations. -config GENERIC_STRNCPY_FROM_USER +config ARCH_HAS_STRNCPY_FROM_USER bool -config GENERIC_STRNLEN_USER +config ARCH_HAS_STRNLEN_USER bool +config GENERIC_STRNCPY_FROM_USER + def_bool !ARCH_HAS_STRNCPY_FROM_USER + +config GENERIC_STRNLEN_USER + def_bool !ARCH_HAS_STRNLEN_USER + config GENERIC_NET_UTILS bool |