aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/sparc/include/asm/uaccess.h3
-rw-r--r--arch/sparc/include/asm/uaccess_32.h10
-rw-r--r--arch/sparc/include/asm/uaccess_64.h4
-rw-r--r--arch/sparc/lib/Makefile2
-rw-r--r--arch/sparc/lib/ksyms.c3
-rw-r--r--arch/sparc/lib/strncpy_from_user_32.S47
-rw-r--r--arch/sparc/lib/strncpy_from_user_64.S133
-rw-r--r--arch/sparc/lib/usercopy.c132
8 files changed, 136 insertions, 198 deletions
diff --git a/arch/sparc/include/asm/uaccess.h b/arch/sparc/include/asm/uaccess.h
index e88fbe5c0457..42a28cfd941f 100644
--- a/arch/sparc/include/asm/uaccess.h
+++ b/arch/sparc/include/asm/uaccess.h
@@ -5,4 +5,7 @@
5#else 5#else
6#include <asm/uaccess_32.h> 6#include <asm/uaccess_32.h>
7#endif 7#endif
8
9extern long strncpy_from_user(char *dest, const char __user *src, long count);
10
8#endif 11#endif
diff --git a/arch/sparc/include/asm/uaccess_32.h b/arch/sparc/include/asm/uaccess_32.h
index d50c310f5d38..59586b57ef1a 100644
--- a/arch/sparc/include/asm/uaccess_32.h
+++ b/arch/sparc/include/asm/uaccess_32.h
@@ -304,16 +304,6 @@ static inline unsigned long clear_user(void __user *addr, unsigned long n)
304 return n; 304 return n;
305} 305}
306 306
307extern long __strncpy_from_user(char *dest, const char __user *src, long count);
308
309static inline long strncpy_from_user(char *dest, const char __user *src, long count)
310{
311 if (__access_ok((unsigned long) src, count))
312 return __strncpy_from_user(dest, src, count);
313 else
314 return -EFAULT;
315}
316
317extern long __strlen_user(const char __user *); 307extern long __strlen_user(const char __user *);
318extern long __strnlen_user(const char __user *, long len); 308extern long __strnlen_user(const char __user *, long len);
319 309
diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h
index a1091afb8831..dcdfb89cbf3f 100644
--- a/arch/sparc/include/asm/uaccess_64.h
+++ b/arch/sparc/include/asm/uaccess_64.h
@@ -257,10 +257,6 @@ extern unsigned long __must_check __clear_user(void __user *, unsigned long);
257 257
258#define clear_user __clear_user 258#define clear_user __clear_user
259 259
260extern long __must_check __strncpy_from_user(char *dest, const char __user *src, long count);
261
262#define strncpy_from_user __strncpy_from_user
263
264extern long __strlen_user(const char __user *); 260extern long __strlen_user(const char __user *);
265extern long __strnlen_user(const char __user *, long len); 261extern long __strnlen_user(const char __user *, long len);
266 262
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 389628f50a15..943d98dc4cdb 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -10,7 +10,7 @@ lib-y += strlen.o
10lib-y += checksum_$(BITS).o 10lib-y += checksum_$(BITS).o
11lib-$(CONFIG_SPARC32) += blockops.o 11lib-$(CONFIG_SPARC32) += blockops.o
12lib-y += memscan_$(BITS).o memcmp.o strncmp_$(BITS).o 12lib-y += memscan_$(BITS).o memcmp.o strncmp_$(BITS).o
13lib-y += strncpy_from_user_$(BITS).o strlen_user_$(BITS).o 13lib-y += strlen_user_$(BITS).o
14lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o 14lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o
15lib-$(CONFIG_SPARC32) += copy_user.o locks.o 15lib-$(CONFIG_SPARC32) += copy_user.o locks.o
16lib-$(CONFIG_SPARC64) += atomic_64.o 16lib-$(CONFIG_SPARC64) += atomic_64.o
diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c
index 2dc30875c8bc..6b278abdb63d 100644
--- a/arch/sparc/lib/ksyms.c
+++ b/arch/sparc/lib/ksyms.c
@@ -33,9 +33,6 @@ EXPORT_SYMBOL(memset);
33EXPORT_SYMBOL(memmove); 33EXPORT_SYMBOL(memmove);
34EXPORT_SYMBOL(__bzero); 34EXPORT_SYMBOL(__bzero);
35 35
36/* Moving data to/from/in userspace. */
37EXPORT_SYMBOL(__strncpy_from_user);
38
39/* Networking helper routines. */ 36/* Networking helper routines. */
40EXPORT_SYMBOL(csum_partial); 37EXPORT_SYMBOL(csum_partial);
41 38
diff --git a/arch/sparc/lib/strncpy_from_user_32.S b/arch/sparc/lib/strncpy_from_user_32.S
deleted file mode 100644
index db0ed2964bdb..000000000000
--- a/arch/sparc/lib/strncpy_from_user_32.S
+++ /dev/null
@@ -1,47 +0,0 @@
1/* strncpy_from_user.S: Sparc strncpy from userspace.
2 *
3 * Copyright(C) 1996 David S. Miller
4 */
5
6#include <linux/linkage.h>
7#include <asm/ptrace.h>
8#include <asm/errno.h>
9
10 .text
11
12 /* Must return:
13 *
14 * -EFAULT for an exception
15 * count if we hit the buffer limit
16 * bytes copied if we hit a null byte
17 */
18
19ENTRY(__strncpy_from_user)
20 /* %o0=dest, %o1=src, %o2=count */
21 mov %o2, %o3
221:
23 subcc %o2, 1, %o2
24 bneg 2f
25 nop
2610:
27 ldub [%o1], %o4
28 add %o0, 1, %o0
29 cmp %o4, 0
30 add %o1, 1, %o1
31 bne 1b
32 stb %o4, [%o0 - 1]
332:
34 add %o2, 1, %o0
35 retl
36 sub %o3, %o0, %o0
37ENDPROC(__strncpy_from_user)
38
39 .section .fixup,#alloc,#execinstr
40 .align 4
414:
42 retl
43 mov -EFAULT, %o0
44
45 .section __ex_table,#alloc
46 .align 4
47 .word 10b, 4b
diff --git a/arch/sparc/lib/strncpy_from_user_64.S b/arch/sparc/lib/strncpy_from_user_64.S
deleted file mode 100644
index d1246b713077..000000000000
--- a/arch/sparc/lib/strncpy_from_user_64.S
+++ /dev/null
@@ -1,133 +0,0 @@
1/*
2 * strncpy_from_user.S: Sparc64 strncpy from userspace.
3 *
4 * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
5 */
6
7#include <linux/linkage.h>
8#include <asm/asi.h>
9#include <asm/errno.h>
10
11 .data
12 .align 8
130: .xword 0x0101010101010101
14
15 .text
16
17 /* Must return:
18 *
19 * -EFAULT for an exception
20 * count if we hit the buffer limit
21 * bytes copied if we hit a null byte
22 * (without the null byte)
23 *
24 * This implementation assumes:
25 * %o1 is 8 aligned => !(%o2 & 7)
26 * %o0 is 8 aligned (if not, it will be slooooow, but will work)
27 *
28 * This is optimized for the common case:
29 * in my stats, 90% of src are 8 aligned (even on sparc32)
30 * and average length is 18 or so.
31 */
32
33ENTRY(__strncpy_from_user)
34 /* %o0=dest, %o1=src, %o2=count */
35 andcc %o1, 7, %g0 ! IEU1 Group
36 bne,pn %icc, 30f ! CTI
37 add %o0, %o2, %g3 ! IEU0
3860: ldxa [%o1] %asi, %g1 ! Load Group
39 brlez,pn %o2, 10f ! CTI
40 mov %o0, %o3 ! IEU0
4150: sethi %hi(0b), %o4 ! IEU0 Group
42 ldx [%o4 + %lo(0b)], %o4 ! Load
43 sllx %o4, 7, %o5 ! IEU1 Group
441: sub %g1, %o4, %g2 ! IEU0 Group
45 stx %g1, [%o0] ! Store
46 add %o0, 8, %o0 ! IEU1
47 andcc %g2, %o5, %g0 ! IEU1 Group
48 bne,pn %xcc, 5f ! CTI
49 add %o1, 8, %o1 ! IEU0
50 cmp %o0, %g3 ! IEU1 Group
51 bl,a,pt %xcc, 1b ! CTI
5261: ldxa [%o1] %asi, %g1 ! Load
5310: retl ! CTI Group
54 mov %o2, %o0 ! IEU0
555: srlx %g2, 32, %g7 ! IEU0 Group
56 sethi %hi(0xff00), %o4 ! IEU1
57 andcc %g7, %o5, %g0 ! IEU1 Group
58 be,pn %icc, 2f ! CTI
59 or %o4, %lo(0xff00), %o4 ! IEU0
60 srlx %g1, 48, %g7 ! IEU0 Group
61 andcc %g7, %o4, %g0 ! IEU1 Group
62 be,pn %icc, 50f ! CTI
63 andcc %g7, 0xff, %g0 ! IEU1 Group
64 be,pn %icc, 51f ! CTI
65 srlx %g1, 32, %g7 ! IEU0
66 andcc %g7, %o4, %g0 ! IEU1 Group
67 be,pn %icc, 52f ! CTI
68 andcc %g7, 0xff, %g0 ! IEU1 Group
69 be,pn %icc, 53f ! CTI
702: andcc %g2, %o5, %g0 ! IEU1 Group
71 be,pn %icc, 2f ! CTI
72 srl %g1, 16, %g7 ! IEU0
73 andcc %g7, %o4, %g0 ! IEU1 Group
74 be,pn %icc, 54f ! CTI
75 andcc %g7, 0xff, %g0 ! IEU1 Group
76 be,pn %icc, 55f ! CTI
77 andcc %g1, %o4, %g0 ! IEU1 Group
78 be,pn %icc, 56f ! CTI
79 andcc %g1, 0xff, %g0 ! IEU1 Group
80 be,a,pn %icc, 57f ! CTI
81 sub %o0, %o3, %o0 ! IEU0
822: cmp %o0, %g3 ! IEU1 Group
83 bl,a,pt %xcc, 50b ! CTI
8462: ldxa [%o1] %asi, %g1 ! Load
85 retl ! CTI Group
86 mov %o2, %o0 ! IEU0
8750: sub %o0, %o3, %o0
88 retl
89 sub %o0, 8, %o0
9051: sub %o0, %o3, %o0
91 retl
92 sub %o0, 7, %o0
9352: sub %o0, %o3, %o0
94 retl
95 sub %o0, 6, %o0
9653: sub %o0, %o3, %o0
97 retl
98 sub %o0, 5, %o0
9954: sub %o0, %o3, %o0
100 retl
101 sub %o0, 4, %o0
10255: sub %o0, %o3, %o0
103 retl
104 sub %o0, 3, %o0
10556: sub %o0, %o3, %o0
106 retl
107 sub %o0, 2, %o0
10857: retl
109 sub %o0, 1, %o0
11030: brlez,pn %o2, 3f
111 sub %g0, %o2, %o3
112 add %o0, %o2, %o0
11363: lduba [%o1] %asi, %o4
1141: add %o1, 1, %o1
115 brz,pn %o4, 2f
116 stb %o4, [%o0 + %o3]
117 addcc %o3, 1, %o3
118 bne,pt %xcc, 1b
11964: lduba [%o1] %asi, %o4
1203: retl
121 mov %o2, %o0
1222: retl
123 add %o2, %o3, %o0
124ENDPROC(__strncpy_from_user)
125
126 .section __ex_table,"a"
127 .align 4
128 .word 60b, __retl_efault
129 .word 61b, __retl_efault
130 .word 62b, __retl_efault
131 .word 63b, __retl_efault
132 .word 64b, __retl_efault
133 .previous
diff --git a/arch/sparc/lib/usercopy.c b/arch/sparc/lib/usercopy.c
index 14b363fec8a2..851cb75ce189 100644
--- a/arch/sparc/lib/usercopy.c
+++ b/arch/sparc/lib/usercopy.c
@@ -1,4 +1,6 @@
1#include <linux/module.h> 1#include <linux/module.h>
2#include <linux/uaccess.h>
3#include <linux/errno.h>
2#include <linux/bug.h> 4#include <linux/bug.h>
3 5
4void copy_from_user_overflow(void) 6void copy_from_user_overflow(void)
@@ -6,3 +8,133 @@ void copy_from_user_overflow(void)
6 WARN(1, "Buffer overflow detected!\n"); 8 WARN(1, "Buffer overflow detected!\n");
7} 9}
8EXPORT_SYMBOL(copy_from_user_overflow); 10EXPORT_SYMBOL(copy_from_user_overflow);
11
12#define REPEAT_BYTE(x) ((~0ul / 0xff) * (x))
13
14/* Return the high bit set in the first byte that is a zero */
15static inline unsigned long has_zero(unsigned long a)
16{
17 return ((a - REPEAT_BYTE(0x01)) & ~a) & REPEAT_BYTE(0x80);
18}
19
20static inline long find_zero(unsigned long c)
21{
22#ifdef CONFIG_64BIT
23 if (!(c & 0xff00000000000000UL))
24 return 0;
25 if (!(c & 0x00ff000000000000UL))
26 return 1;
27 if (!(c & 0x0000ff0000000000UL))
28 return 2;
29 if (!(c & 0x000000ff00000000UL))
30 return 3;
31#define __OFF 4
32#else
33#define __OFF 0
34#endif
35 if (!(c & 0xff000000))
36 return __OFF + 0;
37 if (!(c & 0x00ff0000))
38 return __OFF + 1;
39 if (!(c & 0x0000ff00))
40 return __OFF + 2;
41 return __OFF + 3;
42#undef __OFF
43}
44
45/*
46 * Do a strncpy, return length of string without final '\0'.
47 * 'count' is the user-supplied count (return 'count' if we
48 * hit it), 'max' is the address space maximum (and we return
49 * -EFAULT if we hit it).
50 */
51static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max)
52{
53 long res = 0;
54
55 /*
56 * Truncate 'max' to the user-specified limit, so that
57 * we only have one limit we need to check in the loop
58 */
59 if (max > count)
60 max = count;
61
62 if (((long) dst | (long) src) & (sizeof(long) - 1))
63 goto byte_at_a_time;
64
65 while (max >= sizeof(unsigned long)) {
66 unsigned long c;
67
68 /* Fall back to byte-at-a-time if we get a page fault */
69 if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
70 break;
71 *(unsigned long *)(dst+res) = c;
72 if (has_zero(c))
73 return res + find_zero(c);
74 res += sizeof(unsigned long);
75 max -= sizeof(unsigned long);
76 }
77
78byte_at_a_time:
79 while (max) {
80 char c;
81
82 if (unlikely(__get_user(c,src+res)))
83 return -EFAULT;
84 dst[res] = c;
85 if (!c)
86 return res;
87 res++;
88 max--;
89 }
90
91 /*
92 * Uhhuh. We hit 'max'. But was that the user-specified maximum
93 * too? If so, that's ok - we got as much as the user asked for.
94 */
95 if (res >= count)
96 return res;
97
98 /*
99 * Nope: we hit the address space limit, and we still had more
100 * characters the caller would have wanted. That's an EFAULT.
101 */
102 return -EFAULT;
103}
104
105/**
106 * strncpy_from_user: - Copy a NUL terminated string from userspace.
107 * @dst: Destination address, in kernel space. This buffer must be at
108 * least @count bytes long.
109 * @src: Source address, in user space.
110 * @count: Maximum number of bytes to copy, including the trailing NUL.
111 *
112 * Copies a NUL-terminated string from userspace to kernel space.
113 *
114 * On success, returns the length of the string (not including the trailing
115 * NUL).
116 *
117 * If access to userspace fails, returns -EFAULT (some data may have been
118 * copied).
119 *
120 * If @count is smaller than the length of the string, copies @count bytes
121 * and returns @count.
122 */
123long strncpy_from_user(char *dst, const char __user *src, long count)
124{
125 unsigned long max_addr, src_addr;
126
127 if (unlikely(count <= 0))
128 return 0;
129
130 max_addr = ~0UL;
131 if (likely(segment_eq(get_fs(), USER_DS)))
132 max_addr = STACK_TOP;
133 src_addr = (unsigned long)src;
134 if (likely(src_addr < max_addr)) {
135 unsigned long max = max_addr - src_addr;
136 return do_strncpy_from_user(dst, src, count, max);
137 }
138 return -EFAULT;
139}
140EXPORT_SYMBOL(strncpy_from_user);