Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hexagon: use generic strncpy/strnlen from_user

Remove the hexagon implementation of strncpy/strnlen and instead use
the generic version. The hexagon version reads the data twice for
strncpy() by doing an extra strnlen(), and it apparently lacks a check
for user_addr_max().

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

+5 -159
+2
arch/hexagon/Kconfig
··· 19 19 # GENERIC_ALLOCATOR is used by dma_alloc_coherent() 20 20 select GENERIC_ALLOCATOR 21 21 select GENERIC_IRQ_SHOW 22 + select GENERIC_STRNCPY_FROM_USER 23 + select GENERIC_STRNLEN_USER 22 24 select HAVE_ARCH_KGDB 23 25 select HAVE_ARCH_TRACEHOOK 24 26 select NEED_SG_DMA_LENGTH
+2 -31
arch/hexagon/include/asm/uaccess.h
··· 57 57 __kernel_size_t __clear_user_hexagon(void __user *dest, unsigned long count); 58 58 #define __clear_user(a, s) __clear_user_hexagon((a), (s)) 59 59 60 - extern long __strnlen_user(const char __user *src, long n); 61 - 62 - static inline strnlen_user(const char __user *src, long n) 63 - { 64 - if (!access_ok(src, 1)) 65 - return 0; 66 - 67 - return __strnlen_user(src, n); 68 - } 69 - /* get around the ifndef in asm-generic/uaccess.h */ 60 + extern long strnlen_user(const char __user *src, long n); 70 61 #define strnlen_user strnlen_user 71 62 72 - static inline long strncpy_from_user(char *dst, const char __user *src, long n); 63 + extern long strncpy_from_user(char *dst, const char __user *src, long n) 73 64 #define strncpy_from_user strncpy_from_user 74 65 75 66 #include <asm-generic/uaccess.h> 76 67 77 - /* Todo: an actual accelerated version of this. */ 78 - static inline long strncpy_from_user(char *dst, const char __user *src, long n) 79 - { 80 - long res = strnlen_user(src, n); 81 - 82 - if (unlikely(!res)) 83 - return -EFAULT; 84 - 85 - if (res > n) { 86 - long left = raw_copy_from_user(dst, src, n); 87 - if (unlikely(left)) 88 - memset(dst + (n - left), 0, left); 89 - return n; 90 - } else { 91 - long left = raw_copy_from_user(dst, src, res); 92 - if (unlikely(left)) 93 - memset(dst + (res - left), 0, left); 94 - return res-1; 95 - } 96 - } 97 68 98 69 #endif
-1
arch/hexagon/kernel/hexagon_ksyms.c
··· 15 15 EXPORT_SYMBOL(raw_copy_from_user); 16 16 EXPORT_SYMBOL(raw_copy_to_user); 17 17 EXPORT_SYMBOL(iounmap); 18 - EXPORT_SYMBOL(__strnlen_user); 19 18 EXPORT_SYMBOL(__vmgetie); 20 19 EXPORT_SYMBOL(__vmsetie); 21 20 EXPORT_SYMBOL(__vmyield);
+1 -1
arch/hexagon/mm/Makefile
··· 4 4 # 5 5 6 6 obj-y := init.o ioremap.o uaccess.o vm_fault.o cache.o 7 - obj-y += copy_to_user.o copy_from_user.o strnlen_user.o vm_tlb.o 7 + obj-y += copy_to_user.o copy_from_user.o vm_tlb.o
-126
arch/hexagon/mm/strnlen_user.S
··· 1 - /* SPDX-License-Identifier: GPL-2.0-only */ 2 - /* 3 - * User string length functions for kernel 4 - * 5 - * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. 6 - */ 7 - 8 - #define isrc r0 9 - #define max r1 /* Do not change! */ 10 - 11 - #define end r2 12 - #define tmp1 r3 13 - 14 - #define obo r6 /* off-by-one */ 15 - #define start r7 16 - #define mod8 r8 17 - #define dbuf r15:14 18 - #define dcmp r13:12 19 - 20 - /* 21 - * The vector mask version of this turned out *really* badly. 22 - * The hardware loop version also turned out *really* badly. 23 - * Seems straight pointer arithmetic basically wins here. 24 - */ 25 - 26 - #define fname __strnlen_user 27 - 28 - .text 29 - .global fname 30 - .type fname, @function 31 - .p2align 5 /* why? */ 32 - fname: 33 - { 34 - mod8 = and(isrc,#7); 35 - end = add(isrc,max); 36 - start = isrc; 37 - } 38 - { 39 - P0 = cmp.eq(mod8,#0); 40 - mod8 = and(end,#7); 41 - dcmp = #0; 42 - if (P0.new) jump:t dw_loop; /* fire up the oven */ 43 - } 44 - 45 - alignment_loop: 46 - fail_1: { 47 - tmp1 = memb(start++#1); 48 - } 49 - { 50 - P0 = cmp.eq(tmp1,#0); 51 - if (P0.new) jump:nt exit_found; 52 - P1 = cmp.gtu(end,start); 53 - mod8 = and(start,#7); 54 - } 55 - { 56 - if (!P1) jump exit_error; /* hit the end */ 57 - P0 = cmp.eq(mod8,#0); 58 - } 59 - { 60 - if (!P0) jump alignment_loop; 61 - } 62 - 63 - 64 - 65 - dw_loop: 66 - fail_2: { 67 - dbuf = memd(start); 68 - obo = add(start,#1); 69 - } 70 - { 71 - P0 = vcmpb.eq(dbuf,dcmp); 72 - } 73 - { 74 - tmp1 = P0; 75 - P0 = cmp.gtu(end,start); 76 - } 77 - { 78 - tmp1 = ct0(tmp1); 79 - mod8 = and(end,#7); 80 - if (!P0) jump end_check; 81 - } 82 - { 83 - P0 = cmp.eq(tmp1,#32); 84 - if (!P0.new) jump:nt exit_found; 85 - if (!P0.new) start = add(obo,tmp1); 86 - } 87 - { 88 - start = add(start,#8); 89 - jump dw_loop; 90 - } /* might be nice to combine these jumps... */ 91 - 92 - 93 - end_check: 94 - { 95 - P0 = cmp.gt(tmp1,mod8); 96 - if (P0.new) jump:nt exit_error; /* neverfound! */ 97 - start = add(obo,tmp1); 98 - } 99 - 100 - exit_found: 101 - { 102 - R0 = sub(start,isrc); 103 - jumpr R31; 104 - } 105 - 106 - exit_error: 107 - { 108 - R0 = add(max,#1); 109 - jumpr R31; 110 - } 111 - 112 - /* Uh, what does the "fixup" return here? */ 113 - .falign 114 - fix_1: 115 - { 116 - R0 = #0; 117 - jumpr R31; 118 - } 119 - 120 - .size fname,.-fname 121 - 122 - 123 - .section __ex_table,"a" 124 - .long fail_1,fix_1 125 - .long fail_2,fix_1 126 - .previous